From 9ca26cb49398b1fef4a008eba1615e4165f28c3b Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Mon, 13 Feb 2023 17:53:56 +0200 Subject: [PATCH 001/199] fix: non-zero mode for Lido --- contracts/0.4.24/Lido.sol | 23 ++++++----- contracts/0.4.24/StETH.sol | 45 +++++++++++++-------- contracts/0.4.24/test_helpers/LidoMock.sol | 1 + contracts/0.4.24/test_helpers/StETHMock.sol | 1 + lib/abi/Lido.json | 2 +- 5 files changed, 43 insertions(+), 29 deletions(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index b04df0f4b..35ecee93c 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -252,8 +252,16 @@ contract Lido is Versioned, StETHPermit, AragonApp { * @param _eip712StETH eip712 helper contract for StETH */ function initialize(address _lidoLocator, address _eip712StETH) - public onlyInit + public + payable + onlyInit { + (address holder, uint256 amount) = _bootstrapInitialHolder(); + BUFFERED_ETHER_POSITION.setStorageUint256(amount); + + emit Submitted(holder, amount, 0); + _emitTransferAfterMintingShares(holder, amount); + _initialize_v2(_lidoLocator, _eip712StETH); initialized(); } @@ -285,8 +293,8 @@ contract Lido is Versioned, StETHPermit, AragonApp { * For more details see https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-10.md */ function finalizeUpgrade_v2(address _lidoLocator, address _eip712StETH) external { - require(hasInitialized(), "NOT_INITIALIZED"); _checkContractVersion(0); + require(hasInitialized(), "NOT_INITIALIZED"); require(_lidoLocator != address(0), "LIDO_LOCATOR_ZERO_ADDRESS"); require(_eip712StETH != address(0), "EIP712_STETH_ZERO_ADDRESS"); @@ -430,7 +438,7 @@ contract Lido is Versioned, StETHPermit, AragonApp { * accepts payments of any size. Submitted Ethers are stored in Buffer until someone calls * deposit() and pushes them to the Ethereum Deposit contract. */ - // solhint-disable-next-line + // solhint-disable-next-line no-complex-fallback function() external payable { // protection against accidental submissions by calling non-existent function require(msg.data.length == 0, "NON_EMPTY_DATA"); @@ -928,14 +936,7 @@ contract Lido is Versioned, StETHPermit, AragonApp { STAKING_STATE_POSITION.setStorageStakeLimitStruct(stakeLimitData.updatePrevStakeLimit(currentStakeLimit - msg.value)); } - uint256 sharesAmount; - if (_getTotalPooledEther() != 0 && _getTotalShares() != 0) { - sharesAmount = getSharesByPooledEth(msg.value); - } else { - // totalPooledEther is 0: for first-ever deposit - // assume that shares correspond to Ether 1-to-1 - sharesAmount = msg.value; - } + uint256 sharesAmount = getSharesByPooledEth(msg.value); _mintShares(msg.sender, sharesAmount); diff --git a/contracts/0.4.24/StETH.sol b/contracts/0.4.24/StETH.sol index 3e23f8e33..814f063dc 100644 --- a/contracts/0.4.24/StETH.sol +++ b/contracts/0.4.24/StETH.sol @@ -297,28 +297,18 @@ contract StETH is IERC20, Pausable { * @return the amount of shares that corresponds to `_ethAmount` protocol-controlled Ether. */ function getSharesByPooledEth(uint256 _ethAmount) public view returns (uint256) { - uint256 totalPooledEther = _getTotalPooledEther(); - if (totalPooledEther == 0) { - return 0; - } else { - return _ethAmount - .mul(_getTotalShares()) - .div(totalPooledEther); - } + return _ethAmount + .mul(_getTotalShares()) + .div(_getTotalPooledEther()); } /** * @return the amount of Ether that corresponds to `_sharesAmount` token shares. */ function getPooledEthByShares(uint256 _sharesAmount) public view returns (uint256) { - uint256 totalShares = _getTotalShares(); - if (totalShares == 0) { - return 0; - } else { - return _sharesAmount - .mul(_getTotalPooledEther()) - .div(totalShares); - } + return _sharesAmount + .mul(_getTotalPooledEther()) + .div(_getTotalShares()); } /** @@ -398,7 +388,7 @@ contract StETH is IERC20, Pausable { * * Emits an `Approval` event. * - * NB: the method can be invoken even if the protocol paused. + * NB: the method can be invoked even if the protocol paused. * * Requirements: * @@ -512,4 +502,25 @@ contract StETH is IERC20, Pausable { // We're emitting `SharesBurnt` event to provide an explicit rebase log record nonetheless. } + + /** + * @notice Mints amount of shares equal to contract balance to 0xdead address + * It allows to get rid of zero checks and corner cases + * @dev should be invoked before using the token + */ + function _bootstrapInitialHolder() internal returns (address, uint256) { + uint256 balance = address(this).balance; + require(balance != 0, "EMPTY_INIT_BALANCE"); + + if (_getTotalShares() == 0) { + // if protocol is empty bootstrap it with the contract's balance + // 0xdead is a holder for initial shares + address bootstrapSharesHolder = 0xdead; + _mintShares(bootstrapSharesHolder, balance); + + return (bootstrapSharesHolder, balance); + } + + return (address(0), 0); + } } diff --git a/contracts/0.4.24/test_helpers/LidoMock.sol b/contracts/0.4.24/test_helpers/LidoMock.sol index ab834cc4e..171667e53 100644 --- a/contracts/0.4.24/test_helpers/LidoMock.sol +++ b/contracts/0.4.24/test_helpers/LidoMock.sol @@ -18,6 +18,7 @@ contract LidoMock is Lido { address _eip712StETH ) public + payable { super.initialize( _lidoLocator, diff --git a/contracts/0.4.24/test_helpers/StETHMock.sol b/contracts/0.4.24/test_helpers/StETHMock.sol index 50eadebe2..612166c60 100644 --- a/contracts/0.4.24/test_helpers/StETHMock.sol +++ b/contracts/0.4.24/test_helpers/StETHMock.sol @@ -14,6 +14,7 @@ contract StETHMock is StETH { constructor() public payable{ _resume(); + _bootstrapInitialHolder(); } function _getTotalPooledEther() internal view returns (uint256) { diff --git a/lib/abi/Lido.json b/lib/abi/Lido.json index 137b0ca7c..e2a9e1f47 100644 --- a/lib/abi/Lido.json +++ b/lib/abi/Lido.json @@ -1 +1 @@ -[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_clValidators","type":"uint256"},{"name":"_clBalance","type":"uint256"},{"name":"_withdrawalVaultBalance","type":"uint256"},{"name":"_elRewardsVaultBalance","type":"uint256"},{"name":"_lastFinalizableRequestId","type":"uint256"},{"name":"_simulatedShareRate","type":"uint256"}],"name":"handleOracleReport","outputs":[{"name":"postTotalPooledEther","type":"uint256"},{"name":"postTotalShares","type":"uint256"},{"name":"withdrawals","type":"uint256"},{"name":"elRewards","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"receiveStakingRouterDepositRemainder","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"totalFee","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"StakingRouterDepositRemainderReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}] \ No newline at end of file +[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_clValidators","type":"uint256"},{"name":"_clBalance","type":"uint256"},{"name":"_withdrawalVaultBalance","type":"uint256"},{"name":"_elRewardsVaultBalance","type":"uint256"},{"name":"_lastFinalizableRequestId","type":"uint256"},{"name":"_simulatedShareRate","type":"uint256"}],"name":"handleOracleReport","outputs":[{"name":"postTotalPooledEther","type":"uint256"},{"name":"postTotalShares","type":"uint256"},{"name":"withdrawals","type":"uint256"},{"name":"elRewards","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"receiveStakingRouterDepositRemainder","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"totalFee","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"StakingRouterDepositRemainderReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}] \ No newline at end of file From 51d6655b7f45e60ffd8a0d143d0f581b781ab52c Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Mon, 13 Feb 2023 18:34:19 +0200 Subject: [PATCH 002/199] fix: assert initial holder balance on upgrade --- contracts/0.4.24/Lido.sol | 7 ++++--- contracts/0.4.24/StETH.sol | 14 +++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index 35ecee93c..74f31ddd9 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -256,11 +256,10 @@ contract Lido is Versioned, StETHPermit, AragonApp { payable onlyInit { - (address holder, uint256 amount) = _bootstrapInitialHolder(); + uint256 amount = _bootstrapInitialHolder(); BUFFERED_ETHER_POSITION.setStorageUint256(amount); - emit Submitted(holder, amount, 0); - _emitTransferAfterMintingShares(holder, amount); + emit Submitted(INITIAL_TOKEN_HOLDER, amount, 0); _initialize_v2(_lidoLocator, _eip712StETH); initialized(); @@ -299,6 +298,8 @@ contract Lido is Versioned, StETHPermit, AragonApp { require(_lidoLocator != address(0), "LIDO_LOCATOR_ZERO_ADDRESS"); require(_eip712StETH != address(0), "EIP712_STETH_ZERO_ADDRESS"); + require(_sharesOf(INITIAL_TOKEN_HOLDER) != 0, "INITIAL_HOLDER_EXISTS"); + _initialize_v2(_lidoLocator, _eip712StETH); } diff --git a/contracts/0.4.24/StETH.sol b/contracts/0.4.24/StETH.sol index 814f063dc..e30591f57 100644 --- a/contracts/0.4.24/StETH.sol +++ b/contracts/0.4.24/StETH.sol @@ -50,6 +50,8 @@ contract StETH is IERC20, Pausable { using SafeMath for uint256; using UnstructuredStorage for bytes32; + address internal INITIAL_TOKEN_HOLDER = 0xdead; + /** * @dev StETH balances are dynamic and are calculated based on the accounts' shares * and the total amount of Ether controlled by the protocol. Account shares aren't @@ -508,19 +510,21 @@ contract StETH is IERC20, Pausable { * It allows to get rid of zero checks and corner cases * @dev should be invoked before using the token */ - function _bootstrapInitialHolder() internal returns (address, uint256) { + function _bootstrapInitialHolder() internal returns (uint256) { uint256 balance = address(this).balance; require(balance != 0, "EMPTY_INIT_BALANCE"); if (_getTotalShares() == 0) { // if protocol is empty bootstrap it with the contract's balance // 0xdead is a holder for initial shares - address bootstrapSharesHolder = 0xdead; - _mintShares(bootstrapSharesHolder, balance); + _mintShares(INITIAL_TOKEN_HOLDER, balance); + + emit Transfer(0x0, INITIAL_TOKEN_HOLDER, balance); + emit TransferShares(0x0, INITIAL_TOKEN_HOLDER, balance); - return (bootstrapSharesHolder, balance); + return balance; } - return (address(0), 0); + return 0; } } From 69da980d1d84dd2fc37048d5030775ebd469d88c Mon Sep 17 00:00:00 2001 From: Alexandr Tarelkin Date: Tue, 14 Feb 2023 01:21:53 +0300 Subject: [PATCH 003/199] fix tests --- test/0.4.24/helpers/dao.js | 6 ++-- test/0.4.24/lido.test.js | 7 ++-- test/0.4.24/lidoHandleOracleReport.test.js | 34 +++++++++---------- test/0.4.24/node-operators-registry.test.js | 6 ++-- test/0.4.24/steth.test.js | 6 ++-- test/0.8.9/deposit-security-module.test.js | 12 +++---- test/0.8.9/oracle-daemon-config.test.js | 2 +- .../accounting-oracle-access-control.test.js | 2 +- test/0.8.9/withdrawal-queue.test.js | 8 ++--- test/deposit.test.js | 4 +-- test/helpers/dao.js | 8 ++--- 11 files changed, 47 insertions(+), 48 deletions(-) diff --git a/test/0.4.24/helpers/dao.js b/test/0.4.24/helpers/dao.js index 74da43a97..27e3f0c58 100644 --- a/test/0.4.24/helpers/dao.js +++ b/test/0.4.24/helpers/dao.js @@ -81,19 +81,19 @@ class AragonDAO { async createPermission(entityAddress, app, permissionName) { const permission = await app[permissionName]() - return this.acl.createPermission(entityAddress, app.address, permission, this.appManager, { + return await this.acl.createPermission(entityAddress, app.address, permission, this.appManager, { from: this.appManager }) } async grantPermission(entityAddress, app, permissionName) { const permission = await app[permissionName]() - return this.acl.grantPermission(entityAddress, app.address, permission, { from: this.appManager }) + return await this.acl.grantPermission(entityAddress, app.address, permission, { from: this.appManager }) } async hasPermission(entity, app, permissionName) { const permission = await app[permissionName]() - return this.acl.hasPermission(entity, app.address, permission) + return await this.acl.hasPermission(entity, app.address, permission) } } diff --git a/test/0.4.24/lido.test.js b/test/0.4.24/lido.test.js index f5a951102..36affbc3d 100644 --- a/test/0.4.24/lido.test.js +++ b/test/0.4.24/lido.test.js @@ -734,7 +734,6 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody expectedIsStakingPaused, expectedIsStakingLimited ) => { - assert((await app.isStakingPaused()) === false) currentStakeLimit = await app.getCurrentStakeLimit() assertBn(currentStakeLimit, expectedCurrentStakeLimit) @@ -771,7 +770,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await assertRevert(app.pauseStaking(), 'APP_AUTH_FAILED') receipt = await app.pauseStaking({ from: voting }) assertEvent(receipt, 'StakingPaused') - verifyStakeLimitState(bn(0), bn(0), bn(0), true, false) + await verifyStakeLimitState(bn(0), bn(0), bn(0), true, false) await assertRevert(web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(2) }), `STAKING_PAUSED`) await assertRevert(app.submit(ZERO_ADDRESS, { from: user2, value: ETH(2) }), `STAKING_PAUSED`) @@ -1368,7 +1367,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody // Adding a key & setting staking limit will help await operators.addSigningKeys(0, 1, pad('0x0003', 48), pad('0x01', 96), { from: voting }) - operators.setNodeOperatorStakingLimit(0, 3, { from: voting }) + await operators.setNodeOperatorStakingLimit(0, 3, { from: voting }) await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(1) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) @@ -1494,7 +1493,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody // Adding a key & setting staking limit will help await operators.addSigningKeys(0, 1, pad('0x0003', 48), pad('0x01', 96), { from: voting }) - operators.setNodeOperatorStakingLimit(0, 3, { from: voting }) + await operators.setNodeOperatorStakingLimit(0, 3, { from: voting }) await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(1) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) diff --git a/test/0.4.24/lidoHandleOracleReport.test.js b/test/0.4.24/lidoHandleOracleReport.test.js index af4d83571..6505cbfbd 100644 --- a/test/0.4.24/lidoHandleOracleReport.test.js +++ b/test/0.4.24/lidoHandleOracleReport.test.js @@ -49,7 +49,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => it('report BcnValidators:0 BcnBalance:0 = no rewards', async () => { console.log(consensus.address, oracle.address) await pushOracleReport(consensus, oracle, 0, 0) - checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) + await checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await app.getBufferedEther(), ETH(0)) assertBn(await app.getTotalPooledEther(), ETH(0)) // assert.equal(await app.distributeFeeCalled(), false) @@ -58,7 +58,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => it('report BcnValidators:1 = revert', async () => { await assertRevert(pushOracleReport(consensus, oracle, 1, 0), 'REPORTED_MORE_DEPOSITED') - checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) + await checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await app.getBufferedEther(), ETH(0)) assertBn(await app.getTotalPooledEther(), ETH(0)) // assert.equal(await app.distributeFeeCalled(), false) @@ -69,14 +69,14 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => context('with depositedVals=0, beaconVals=0, bcnBal=0, bufferedEth=12', async () => { it('report BcnValidators:0 BcnBalance:0 = no rewards', async () => { await pushOracleReport(consensus, oracle, 0, 0) - checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) + await checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await app.getBufferedEther(), ETH(12)) assertBn(await app.getTotalPooledEther(), ETH(12)) // assert.equal(await app.distributeFeeCalled(), false) // assertBn(await app.totalRewards(), 0) await assertRevert(pushOracleReport(consensus, oracle, 1, 0), 'REPORTED_MORE_DEPOSITED') - checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) + await checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await app.getBufferedEther(), ETH(12)) assertBn(await app.getTotalPooledEther(), ETH(12)) // assert.equal(await app.distributeFeeCalled(), false) @@ -86,14 +86,14 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => context('with depositedVals=1, beaconVals=0, bcnBal=0, bufferedEth=3', async () => { it('initial state before report', async () => { - checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) + await checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await app.getBufferedEther(), ETH(3)) assertBn(await app.getTotalPooledEther(), ETH(35)) }) it('report BcnValidators:0 BcnBalance:0 = no rewards', async () => { await pushOracleReport(consensus, oracle, 0, 0) - checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) + await checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await app.getBufferedEther(), ETH(3)) assertBn(await app.getTotalPooledEther(), ETH(35)) // assert.equal(await app.distributeFeeCalled(), false) @@ -105,7 +105,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => pushOracleReport(consensus, oracle, 2, ETH(65)), 'REPORTED_MORE_DEPOSITED' ) - checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) + await checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await app.getBufferedEther(), ETH(3)) assertBn(await app.getTotalPooledEther(), ETH(35)) // assert.equal(await app.distributeFeeCalled(), false) @@ -114,7 +114,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => it('report BcnValidators:1 BcnBalance:31 = no rewards', async () => { await pushOracleReport(consensus, oracle, 1, ETH(31)) - checkStat({ depositedValidators: 1, beaconValidators: 1, beaconBalance: ETH(31) }) + await checkStat({ depositedValidators: 1, beaconValidators: 1, beaconBalance: ETH(31) }) assertBn(await app.getBufferedEther(), ETH(3)) assertBn(await app.getTotalPooledEther(), ETH(34)) // assert.equal(await app.distributeFeeCalled(), false) @@ -123,7 +123,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => it('report BcnValidators:1 BcnBalance:32 = no rewards', async () => { await pushOracleReport(consensus, oracle, 1, ETH(32)) - checkStat({ depositedValidators: 1, beaconValidators: 1, beaconBalance: ETH(32) }) + await checkStat({ depositedValidators: 1, beaconValidators: 1, beaconBalance: ETH(32) }) assertBn(await app.getBufferedEther(), ETH(3)) assertBn(await app.getTotalPooledEther(), ETH(35)) // assert.equal(await app.distributeFeeCalled(), false) @@ -141,14 +141,14 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => }) it('initial state before report', async () => { - checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(30) }) + await checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(30) }) assertBn(await app.getBufferedEther(), ETH(5)) assertBn(await app.getTotalPooledEther(), ETH(67)) }) it('report BcnValidators:1 BcnBalance:0 = no rewards', async () => { await pushOracleReport(consensus, oracle, 1, 0) - checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(0) }) + await checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(0) }) assertBn(await app.getBufferedEther(), ETH(5)) assertBn(await app.getTotalPooledEther(), ETH(37)) // assert.equal(await app.distributeFeeCalled(), false) @@ -157,7 +157,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => it('report BcnValidators:1 BcnBalance:1 = no rewards', async () => { await pushOracleReport({epochId: 100, clValidators: 1, clBalance: ETH(1)}) - checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(1) }) + await checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(1) }) assertBn(await app.getBufferedEther(), ETH(5)) assertBn(await app.getTotalPooledEther(), ETH(38)) // assert.equal(await app.distributeFeeCalled(), false) @@ -166,7 +166,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => it('report BcnValidators:2 BcnBalance:62 = no reward', async () => { await pushOracleReport({epochId: 100, clValidators: 2, clBalance: ETH(62)}) - checkStat({ depositedValidators: 2, beaconValidators: 2, beaconBalance: ETH(62) }) + await checkStat({ depositedValidators: 2, beaconValidators: 2, beaconBalance: ETH(62) }) assertBn(await app.getBufferedEther(), ETH(5)) assertBn(await app.getTotalPooledEther(), ETH(67)) // assert.equal(await app.distributeFeeCalled(), false) @@ -175,7 +175,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => it('report BcnValidators:1 BcnBalance:31 = reward:1', async () => { await pushOracleReport({epochId: 100, clValidators: 2, clBalance: ETH(63)}) - checkStat({ depositedValidators: 2, beaconValidators: 2, beaconBalance: ETH(63) }) + await checkStat({ depositedValidators: 2, beaconValidators: 2, beaconBalance: ETH(63) }) assertBn(await app.getBufferedEther(), ETH(5)) assertBn(await app.getTotalPooledEther(), ETH(68)) // assert.equal(await app.distributeFeeCalled(), true) @@ -184,7 +184,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => it('report BcnValidators:2 BcnBalance:63 = reward:1', async () => { await pushOracleReport({epochId: 100, clValidators: 2, clBalance: ETH(63)}) - checkStat({ depositedValidators: 2, beaconValidators: 2, beaconBalance: ETH(63) }) + await checkStat({ depositedValidators: 2, beaconValidators: 2, beaconBalance: ETH(63) }) assertBn(await app.getBufferedEther(), ETH(5)) assertBn(await app.getTotalPooledEther(), ETH(68)) // assert.equal(await app.distributeFeeCalled(), true) @@ -196,7 +196,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => pushOracleReport({epochId: 110, clValidators: 3, clBalance: ETH(65)}), 'REPORTED_MORE_DEPOSITED' ) - checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(30) }) + await checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(30) }) assertBn(await app.getBufferedEther(), ETH(5)) assertBn(await app.getTotalPooledEther(), ETH(67)) // assert.equal(await app.distributeFeeCalled(), false) @@ -228,7 +228,7 @@ contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => 'REPORTED_LESS_VALIDATORS' ) // values stay intact - checkStat({ depositedValidators: 5, beaconValidators: 4, beaconBalance: ETH(1) }) + await checkStat({ depositedValidators: 5, beaconValidators: 4, beaconBalance: ETH(1) }) assertBn(await app.getBufferedEther(), ETH(0)) assertBn(await app.getTotalPooledEther(), ETH(33)) // assert.equal(await app.distributeFeeCalled(), false) diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index ba8ae291a..ad7dba889 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -1325,7 +1325,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob { stoppedValidators: exitedValidatorsKeysCountBefore }, { exitedSigningKeysCount: exitedSigningKeysCountBefore } ] = await Promise.all([ - await app.getNodeOperator(firstNodeOperatorId, false), + app.getNodeOperator(firstNodeOperatorId, false), app.testing_getTotalSigningKeysStats() ]) assert(newExitedValidatorsCount < exitedValidatorsKeysCountBefore.toNumber()) @@ -1344,7 +1344,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob { stoppedValidators: exitedValidatorsKeysCountBefore }, { exitedSigningKeysCount: exitedSigningKeysCountBefore } ] = await Promise.all([ - await app.getNodeOperator(firstNodeOperatorId, false), + app.getNodeOperator(firstNodeOperatorId, false), app.testing_getTotalSigningKeysStats() ]) assert(newExitedValidatorsCount > exitedValidatorsKeysCountBefore.toNumber()) @@ -1494,7 +1494,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob // invalidated all keys before the test to remove all unused keys of node operators await app.onWithdrawalCredentialsChanged({ from: voting }) // the second invalidation must not invalidate keys - const receipt = app.onWithdrawalCredentialsChanged({ from: voting }) + const receipt = await app.onWithdrawalCredentialsChanged({ from: voting }) const nonceBefore = await app.getNonce() assert.notEmits(receipt, 'NodeOperatorTotalKeysTrimmed') const nonceAfter = await app.getNonce() diff --git a/test/0.4.24/steth.test.js b/test/0.4.24/steth.test.js index 9dd12219a..af72dfb34 100644 --- a/test/0.4.24/steth.test.js +++ b/test/0.4.24/steth.test.js @@ -52,9 +52,9 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { }) it(`transfers works with no pooled ehter, balances aren't changed`, async () => { - stEth.transfer(user1, tokens(1), { from: user2 }) - stEth.transfer(user2, tokens(100), { from: user3 }) - stEth.transfer(user3, tokens(1000), { from: user1 }) + await stEth.transfer(user1, tokens(1), { from: user2 }) + await stEth.transfer(user2, tokens(100), { from: user3 }) + await stEth.transfer(user3, tokens(1000), { from: user1 }) assertBn(await stEth.balanceOf(user1), tokens(0)) assertBn(await stEth.balanceOf(user2), tokens(0)) diff --git a/test/0.8.9/deposit-security-module.test.js b/test/0.8.9/deposit-security-module.test.js index c02f999ee..663227ca2 100644 --- a/test/0.8.9/deposit-security-module.test.js +++ b/test/0.8.9/deposit-security-module.test.js @@ -86,7 +86,7 @@ contract('DepositSecurityModule', ([owner, stranger, guardian]) => { for (let i = 0; i < numBlocksToMine; ++i) { await network.provider.send('evm_mine') } - return web3.eth.getBlock('latest') + return await web3.eth.getBlock('latest') } describe('depositBufferedEther', () => { @@ -970,7 +970,7 @@ contract('DepositSecurityModule', ([owner, stranger, guardian]) => { assert.isTrue((await depositSecurityModule.getGuardianQuorum()) > 0, 'invariant failed: quorum > 0') const lastDepositBlockNumber = await web3.eth.getBlockNumber() - stakingRouterMock.setStakingModuleLastDepositBlock(lastDepositBlockNumber) + await stakingRouterMock.setStakingModuleLastDepositBlock(lastDepositBlockNumber) await waitBlocks(2 * MIN_DEPOSIT_BLOCK_DISTANCE) const currentBlockNumber = await web3.eth.getBlockNumber() @@ -984,7 +984,7 @@ contract('DepositSecurityModule', ([owner, stranger, guardian]) => { assert.isTrue((await depositSecurityModule.getGuardianQuorum()) > 0, 'invariant failed: quorum > 0') const lastDepositBlockNumber = await web3.eth.getBlockNumber() - stakingRouterMock.setStakingModuleLastDepositBlock(lastDepositBlockNumber) + await stakingRouterMock.setStakingModuleLastDepositBlock(lastDepositBlockNumber) const latestBlock = await waitBlocks(2 * MIN_DEPOSIT_BLOCK_DISTANCE) const minDepositBlockDistance = await depositSecurityModule.getMinDepositBlockDistance() @@ -1003,7 +1003,7 @@ contract('DepositSecurityModule', ([owner, stranger, guardian]) => { assert.equal(await stakingRouterMock.getStakingModuleIsDepositsPaused(STAKING_MODULE), false, 'invariant failed: isPaused') const lastDepositBlockNumber = await web3.eth.getBlockNumber() - stakingRouterMock.setStakingModuleLastDepositBlock(lastDepositBlockNumber) + await stakingRouterMock.setStakingModuleLastDepositBlock(lastDepositBlockNumber) await waitBlocks(2 * MIN_DEPOSIT_BLOCK_DISTANCE) const currentBlockNumber = await web3.eth.getBlockNumber() @@ -1021,7 +1021,7 @@ contract('DepositSecurityModule', ([owner, stranger, guardian]) => { assert.equal(await stakingRouterMock.getStakingModuleIsDepositsPaused(STAKING_MODULE), false, 'invariant failed: isPaused') const lastDepositBlockNumber = await web3.eth.getBlockNumber() - stakingRouterMock.setStakingModuleLastDepositBlock(lastDepositBlockNumber) + await stakingRouterMock.setStakingModuleLastDepositBlock(lastDepositBlockNumber) await waitBlocks(Math.floor(MIN_DEPOSIT_BLOCK_DISTANCE / 2)) const currentBlockNumber = await web3.eth.getBlockNumber() @@ -1036,7 +1036,7 @@ contract('DepositSecurityModule', ([owner, stranger, guardian]) => { assert.isTrue((await depositSecurityModule.getGuardianQuorum()) > 0, 'invariant failed: quorum > 0') const lastDepositBlockNumber = await web3.eth.getBlockNumber() - stakingRouterMock.setStakingModuleLastDepositBlock(lastDepositBlockNumber) + await stakingRouterMock.setStakingModuleLastDepositBlock(lastDepositBlockNumber) await waitBlocks(2 * MIN_DEPOSIT_BLOCK_DISTANCE) const currentBlockNumber = await web3.eth.getBlockNumber() diff --git a/test/0.8.9/oracle-daemon-config.test.js b/test/0.8.9/oracle-daemon-config.test.js index cbe587c46..bf6e4cc23 100644 --- a/test/0.8.9/oracle-daemon-config.test.js +++ b/test/0.8.9/oracle-daemon-config.test.js @@ -168,7 +168,7 @@ contract('OracleDaemonConfig', async ([deployer, manager, stranger]) => { it('deployer cannot unset a defaultValue', async () => { await config.set(defaultKey, defaultValue, { from: manager }) - assert.revertsOZAccessControl( + await assert.revertsOZAccessControl( config.unset(defaultKey, { from: deployer }), deployer, `CONFIG_MANAGER_ROLE` diff --git a/test/0.8.9/oracle/accounting-oracle-access-control.test.js b/test/0.8.9/oracle/accounting-oracle-access-control.test.js index 379549713..25205b2d0 100644 --- a/test/0.8.9/oracle/accounting-oracle-access-control.test.js +++ b/test/0.8.9/oracle/accounting-oracle-access-control.test.js @@ -65,7 +65,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra oracle = deployed.oracle consensus = deployed.consensus - mockLido = deploy.mockLido + mockLido = deployed.mockLido } context('deploying', () => { diff --git a/test/0.8.9/withdrawal-queue.test.js b/test/0.8.9/withdrawal-queue.test.js index 377f65df4..492e30d9f 100644 --- a/test/0.8.9/withdrawal-queue.test.js +++ b/test/0.8.9/withdrawal-queue.test.js @@ -30,8 +30,8 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { await steth.mintShares(user, shares(1)) await steth.approve(withdrawalQueue.address, StETH(300), { from: user }) - impersonate(ethers.provider, steth.address) - snapshot.make(); + await impersonate(ethers.provider, steth.address) + await snapshot.make(); }) afterEach(async () => { @@ -771,12 +771,12 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) it("One can't change someone else's request", async () => { - await assert.reverts(withdrawalQueue.transferFrom(user, owner, requestId, { from: stranger }), + await assert.reverts(withdrawalQueue.transferFrom(user, owner, requestId, { from: stranger }), `NotOwnerOrApproved("${stranger}")`) }) it("One can't pass zero owner", async () => { - await assert.reverts(withdrawalQueue.transferFrom(user, ZERO_ADDRESS, requestId, { from: user }), + await assert.reverts(withdrawalQueue.transferFrom(user, ZERO_ADDRESS, requestId, { from: user }), 'TransferToZeroAddress()') }) diff --git a/test/deposit.test.js b/test/deposit.test.js index c5bbbc078..d5ad41bf1 100644 --- a/test/deposit.test.js +++ b/test/deposit.test.js @@ -281,7 +281,7 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d // Adding a key & setting staking limit will help await operators.addSigningKeys(0, 1, pad('0x0003', 48), pad('0x01', 96), { from: voting }) - operators.setNodeOperatorStakingLimit(0, 3, { from: voting }) + await operators.setNodeOperatorStakingLimit(0, 3, { from: voting }) await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(1) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) @@ -412,7 +412,7 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d // Adding a key & setting staking limit will help await operators.addSigningKeys(0, 1, pad('0x0003', 48), pad('0x01', 96), { from: voting }) - operators.setNodeOperatorStakingLimit(0, 3, { from: voting }) + await operators.setNodeOperatorStakingLimit(0, 3, { from: voting }) await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(1) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) diff --git a/test/helpers/dao.js b/test/helpers/dao.js index e383e9d18..27e3f0c58 100644 --- a/test/helpers/dao.js +++ b/test/helpers/dao.js @@ -81,19 +81,19 @@ class AragonDAO { async createPermission(entityAddress, app, permissionName) { const permission = await app[permissionName]() - return this.acl.createPermission(entityAddress, app.address, permission, this.appManager, { + return await this.acl.createPermission(entityAddress, app.address, permission, this.appManager, { from: this.appManager }) } async grantPermission(entityAddress, app, permissionName) { const permission = await app[permissionName]() - return this.acl.grantPermission(entityAddress, app.address, permission, { from: this.appManager }) + return await this.acl.grantPermission(entityAddress, app.address, permission, { from: this.appManager }) } async hasPermission(entity, app, permissionName) { const permission = await app[permissionName]() - return this.acl.hasPermission(entity, app.address, permission) + return await this.acl.hasPermission(entity, app.address, permission) } } @@ -137,4 +137,4 @@ module.exports = { AragonDAO, newDao, newApp -} \ No newline at end of file +} From aa465af82da04fa21326520ac40d0bd17e1c1081 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 13:06:07 +0200 Subject: [PATCH 004/199] chore: fix outdated command --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c2553d6e..c9633a851 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "test-sequential": "yarn run test:unit-sequential", "test:unit": "hardhat test --parallel --network hardhat", "test:unit-sequential": "hardhat test --network hardhat", - "test:gas": "REPORT_GAS=true hardhat test --network localhost", + "test:gas": "REPORT_GAS=true hardhat test --network hardhat", "test:coverage": "hardhat coverage --testfiles test", "test:e2e": "npm run compile && ava -T 1000000 -v", "estimate-deposit-loop-gas": "yarn run test:unit ./estimate_deposit_loop_gas.js", From 4e3b482ecff3da1ff606b5ff193dfb71f5b97fbf Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 13:43:00 +0200 Subject: [PATCH 005/199] fix: lost `constant` for initial holder --- contracts/0.4.24/StETH.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/0.4.24/StETH.sol b/contracts/0.4.24/StETH.sol index e30591f57..bc91bcd9e 100644 --- a/contracts/0.4.24/StETH.sol +++ b/contracts/0.4.24/StETH.sol @@ -50,7 +50,7 @@ contract StETH is IERC20, Pausable { using SafeMath for uint256; using UnstructuredStorage for bytes32; - address internal INITIAL_TOKEN_HOLDER = 0xdead; + address constant internal INITIAL_TOKEN_HOLDER = 0xdead; /** * @dev StETH balances are dynamic and are calculated based on the accounts' shares From c2eddb958dba18e6911aa9ca1eee9e39ff3a566d Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 13:43:48 +0200 Subject: [PATCH 006/199] test: fix lido initialization --- test/helpers/factories.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/helpers/factories.js b/test/helpers/factories.js index 86f15a638..6b7760a2f 100644 --- a/test/helpers/factories.js +++ b/test/helpers/factories.js @@ -2,6 +2,7 @@ const withdrawals = require('./withdrawals') const { newApp } = require('./dao') const { artifacts } = require('hardhat') const { deployLocatorWithDummyAddressesImplementation } = require('./locator-deploy') +const { ETH } = require("./utils") const { SLOTS_PER_EPOCH, @@ -352,7 +353,7 @@ async function postSetup({ legacyOracle, consensusContract }) { - await pool.initialize(lidoLocator.address, eip712StETH.address) + await pool.initialize(lidoLocator.address, eip712StETH.address, { value: ETH(1) }) await legacyOracle.initialize(lidoLocator.address, consensusContract.address) From fa0c0653355c21e3abbe497b196f488425fade04 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 13:46:32 +0200 Subject: [PATCH 007/199] test: fix lost awaits --- test/0.4.24/lido.test.js | 6 +++--- test/0.4.24/node-operators-registry.test.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/0.4.24/lido.test.js b/test/0.4.24/lido.test.js index c8df0b85c..e5a834047 100644 --- a/test/0.4.24/lido.test.js +++ b/test/0.4.24/lido.test.js @@ -426,14 +426,14 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await app.setELRewardsWithdrawalLimit(initialValue, { from: voting }) // unable to receive execution layer rewards from arbitrary account - assertRevert(app.receiveELRewards({ from: user1, value: ETH(1) }), 'EXECUTION_LAYER_REAWARDS_VAULT_ONLY') + await assertRevert(app.receiveELRewards({ from: user1, value: ETH(1) }), 'EXECUTION_LAYER_REWARDS_VAULT_ONLY') }) }) }) describe('receiveELRewards()', async () => { it('unable to receive eth from arbitrary account', async () => { - assertRevert(app.receiveELRewards({ from: nobody, value: ETH(1) }), 'EXECUTION_LAYER_REAWARDS_VAULT_ONLY') + await assertRevert(app.receiveELRewards({ from: nobody, value: ETH(1) }), 'EXECUTION_LAYER_REWARDS_VAULT_ONLY') }) it('event work', async () => { @@ -452,7 +452,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody describe('receiveStakingRouterRemainder()', async () => { it('unable to receive eth from arbitrary account', async () => { - assertRevert(app.receiveStakingRouterDepositRemainder({ from: nobody, value: ETH(1) })) + await assertRevert(app.receiveStakingRouterDepositRemainder({ from: nobody, value: ETH(1) })) }) it('event work', async () => { diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index a6d3c7cf8..c4d8cc89d 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -189,7 +189,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('reverts with error WRONG_BASE_VERSION when called on already initialized contract', async () => { await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) assert.equals(await app.getContractVersion(), 2) - assert.reverts(app.finalizeUpgrade_v2(locator.address, CURATED_TYPE), 'WRONG_BASE_VERSION') + await assert.reverts(app.finalizeUpgrade_v2(locator.address, CURATED_TYPE), 'UNEXPECTED_CONTRACT_VERSION') }) it('sets total signing keys stats correctly', async () => { From 3cf8fc830f48111509ae26a4d38715d36fc2a82d Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 13:50:21 +0200 Subject: [PATCH 008/199] chore: fix a warning --- scripts/extract-abi.js | 2 +- test/0.4.24/lido.test.js | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/scripts/extract-abi.js b/scripts/extract-abi.js index 8259f49a9..276f6f5f1 100644 --- a/scripts/extract-abi.js +++ b/scripts/extract-abi.js @@ -29,7 +29,7 @@ async function extractABIs(artifactPaths, abisPath) { for (const file of files) { await fs.unlink(path.join(abisPath, file)) } - await fs.rmdir(abisPath, { recursive: true }) + await fs.rm(abisPath, { recursive: true }) } await fs.mkdir(abisPath, { recursive: true }) diff --git a/test/0.4.24/lido.test.js b/test/0.4.24/lido.test.js index e5a834047..874ed0594 100644 --- a/test/0.4.24/lido.test.js +++ b/test/0.4.24/lido.test.js @@ -188,29 +188,30 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody it('reverts if not initialized', async () => { const proxyAddress = await newApp(dao, 'lido-pool', appBase.address, appManager.address) const appProxy = await LidoMock.at(proxyAddress) - assert.reverts(appProxy.finalizeUpgrade_v2(lidoLocator.address, eip712StETH.address), 'NOT_INITIALIZED') + await assert.reverts(appProxy.finalizeUpgrade_v2(lidoLocator.address, eip712StETH.address), 'NOT_INITIALIZED') }) - it('reverts with PETRIFIED on implementation finalized ', async () => { - assert.reverts(appBase.finalizeUpgrade_v2(lidoLocator.address, eip712StETH.address), 'PETRIFIED') + it('reverts with NOT_INITIALIZED on implementation', async () => { + await assert.reverts(appBase.finalizeUpgrade_v2(lidoLocator.address, eip712StETH.address), + 'UNEXPECTED_CONTRACT_VERSION') }) it('reverts if already initialized', async () => { assert.equal(await app.getContractVersion(), 0) await app.finalizeUpgrade_v2(lidoLocator.address, eip712StETH.address) assert.equal(await app.getContractVersion(), 2) - assertRevert( - app.finalizeUpgrade_v2(stakingRouter.address, depositor, eip712StETH.address, withdrawalQueue.address), - 'WRONG_BASE_VERSION' + await assert.reverts( + app.finalizeUpgrade_v2(lidoLocator.address, eip712StETH.address), + 'UNEXPECTED_CONTRACT_VERSION' ) }) it('reverts if lido locator address is ZERO', async () => { - assertRevert(app.finalizeUpgrade_v2(ZERO_ADDRESS, eip712StETH.address), 'LIDO_LOCATOR_ZERO_ADDRESS') + await assert.reverts(app.finalizeUpgrade_v2(ZERO_ADDRESS, eip712StETH.address), 'LIDO_LOCATOR_ZERO_ADDRESS') }) it('reverts if eip712StETH address is ZERO', async () => { - assertRevert(app.finalizeUpgrade_v2(lidoLocator.address, ZERO_ADDRESS), 'EIP712_STETH_ZERO_ADDRESS') + await assert.reverts(app.finalizeUpgrade_v2(lidoLocator.address, ZERO_ADDRESS), 'EIP712_STETH_ZERO_ADDRESS') }) }) From 7394e11c180b7372ae87cfb6803c0213a61ad687 Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Tue, 14 Feb 2023 17:42:43 +0400 Subject: [PATCH 009/199] Bump hardhat version. Integrate foundry --- .gitignore | 4 + .gitmodules | 4 + foundry.toml | 21 + foundry/lib/forge-std | 1 + hardhat.config.js | 7 +- package.json | 4 +- remappings.txt | 2 + test/common/lib/mem-utils.test.sol | 43 ++ yarn.lock | 868 +++++++++++++++++------------ 9 files changed, 603 insertions(+), 351 deletions(-) create mode 100644 .gitmodules create mode 100644 foundry.toml create mode 160000 foundry/lib/forge-std create mode 100644 remappings.txt create mode 100644 test/common/lib/mem-utils.test.sol diff --git a/.gitignore b/.gitignore index ae4edcfc0..239264963 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,7 @@ cli/vendor # OS relative .DS_Store + +# foundry artifacts +foundry/cache +foundry/out \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..0c2994f67 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "foundry/lib/forge-std"] + path = foundry/lib/forge-std + url = https://github.com/foundry-rs/forge-std + branch = v1.3.0 diff --git a/foundry.toml b/foundry.toml new file mode 100644 index 000000000..f1aa5cf0d --- /dev/null +++ b/foundry.toml @@ -0,0 +1,21 @@ +[profile.default] +# The source directory +src = 'contracts' + +# The artifact directory +out = 'foundry/out' + +# A list of paths to look for libraries in +libs = ['node_modules', 'foundry/lib'] + +# The test directory +test = 'test' + +# Whether to cache builds or not +cache = true + +# The cache directory if enabled +cache_path = 'foundry/cache' + +# only run tests in contracts matching the specified regex pattern +match_path = 'test/*.test.sol' \ No newline at end of file diff --git a/foundry/lib/forge-std b/foundry/lib/forge-std new file mode 160000 index 000000000..662ae0d69 --- /dev/null +++ b/foundry/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 662ae0d6936654c5d1fb79fc15f521de28edb60e diff --git a/hardhat.config.js b/hardhat.config.js index e1fddf077..74687eb28 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -11,6 +11,7 @@ require('hardhat-gas-reporter') require('solidity-coverage') require('hardhat-contract-sizer') require('hardhat-ignore-warnings') +require('@nomicfoundation/hardhat-foundry') const NETWORK_NAME = getNetworkName() const ETH_ACCOUNT_NAME = process.env.ETH_ACCOUNT_NAME @@ -75,7 +76,8 @@ const getNetConfig = (networkName, ethAccountName) => { initialBaseFeePerGas: 0, allowUnlimitedContractSize: true, accounts: { - mnemonic: 'hardhat', + // default hardhat's node mnemonic + mnemonic: 'test test test test test test test test test test test junk', count: 20, accountsBalance: '100000000000000000000000', gasPrice: 0 @@ -214,6 +216,9 @@ module.exports = { runOnCompile: true, strict: true, except: ['test_helpers', 'template', 'mocks', '@aragon', 'openzeppelin'], + }, + paths: { + sources: 'contracts' } } diff --git a/package.json b/package.json index 8c2553d6e..f78d7ef89 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "lint:js": "yarn lint:js:cmd .", "lint:js:fix": "yarn lint:js:cmd --fix .", "lint:js:cmd": "eslint --ext .js --cache --ignore-path .gitignore --ignore-pattern 'apps/*/app/' --ignore-pattern /gasprofile/ --ignore-pattern /scripts/", + "test:forge": "forge test", "test": "yarn run test:unit", "test-sequential": "yarn run test:unit-sequential", "test:unit": "hardhat test --parallel --network hardhat", @@ -78,6 +79,7 @@ "@babel/node": "^7.12.1", "@babel/preset-env": "^7.11.5", "@babel/register": "^7.12.1", + "@nomicfoundation/hardhat-foundry": "^1.0.0", "@nomiclabs/hardhat-ethers": "^2.0.4", "@nomiclabs/hardhat-etherscan": "^2.1.8", "@nomiclabs/hardhat-ganache": "^2.0.1", @@ -100,7 +102,7 @@ "eslint-plugin-standard": "^4.0.1", "eth-ens-namehash": "^2.0.8", "ethereumjs-testrpc-sc": "^6.5.1-sc.1", - "hardhat": "2.9.9", + "hardhat": "2.12.7", "hardhat-contract-sizer": "^2.5.0", "hardhat-gas-reporter": "1.0.8", "hardhat-ignore-warnings": "skozin/hardhat-ignore-warnings#0ecf2ae85bddb83594193ee5c463cb4ae54cde7d", diff --git a/remappings.txt b/remappings.txt new file mode 100644 index 000000000..216904bb6 --- /dev/null +++ b/remappings.txt @@ -0,0 +1,2 @@ +ds-test/=foundry/lib/forge-std/lib/ds-test/src/ +forge-std/=foundry/lib/forge-std/src/ \ No newline at end of file diff --git a/test/common/lib/mem-utils.test.sol b/test/common/lib/mem-utils.test.sol new file mode 100644 index 000000000..d13db1607 --- /dev/null +++ b/test/common/lib/mem-utils.test.sol @@ -0,0 +1,43 @@ +pragma solidity 0.8.9; + +import { MemUtils } from "contracts/common/lib/MemUtils.sol"; +import "forge-std/Test.sol"; + +contract MemUtilsTestFoundry is Test { + uint256 testNumber; + + function setUp() public { + testNumber = 42; + } + + function testUnsafeAlloc_allocates_empty_byte_array() external { + // disable all compiler optimizations by including an assembly block not marked as mem-safe + assembly { + mstore(0x00, 0x1) + } + + uint256 preAllocFreeMemPtr = getFreeMemPtr(); + + // assert free mem pointer is 32-byte aligned initially + assertTrue(preAllocFreeMemPtr % 32 == 0); + + bytes memory arr = MemUtils.unsafeAllocateBytes(0); + assert(arr.length == 0); + assertEq(getMemPtr(arr), preAllocFreeMemPtr); + + uint256 freeMemPtr = getFreeMemPtr(); + assertEq(freeMemPtr, preAllocFreeMemPtr + 32); + } + + function getFreeMemPtr() internal pure returns (uint256 result) { + assembly { + result := mload(0x40) + } + } + + function getMemPtr(bytes memory arr) internal pure returns (uint256 result) { + assembly { + result := arr + } + } +} diff --git a/yarn.lock b/yarn.lock index ce3c533ab..f3284cbe9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1787,87 +1787,6 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/block@npm:^3.5.0, @ethereumjs/block@npm:^3.6.2, @ethereumjs/block@npm:^3.6.3": - version: 3.6.3 - resolution: "@ethereumjs/block@npm:3.6.3" - dependencies: - "@ethereumjs/common": ^2.6.5 - "@ethereumjs/tx": ^3.5.2 - ethereumjs-util: ^7.1.5 - merkle-patricia-tree: ^4.2.4 - checksum: c0f44f3fabbec6a0040dcf5f2cc13619e2130187232e19f3e4d92426d1b6f47d245e730bf60ee717c3d09af12443b94383c0b58d114f042bfce2b43c59981ab8 - languageName: node - linkType: hard - -"@ethereumjs/blockchain@npm:^5.5.2, @ethereumjs/blockchain@npm:^5.5.3": - version: 5.5.3 - resolution: "@ethereumjs/blockchain@npm:5.5.3" - dependencies: - "@ethereumjs/block": ^3.6.2 - "@ethereumjs/common": ^2.6.4 - "@ethereumjs/ethash": ^1.1.0 - debug: ^4.3.3 - ethereumjs-util: ^7.1.5 - level-mem: ^5.0.1 - lru-cache: ^5.1.1 - semaphore-async-await: ^1.5.1 - checksum: 2524125d5cb7ac26c4ada4edbe4ba36165ad2dd2835719f469272e1948b9219495b3d3ebf765a2f8a9cb9cc05fcc4de6cc837850b6aa77737193c2e1acd2d763 - languageName: node - linkType: hard - -"@ethereumjs/common@npm:^2.6.4, @ethereumjs/common@npm:^2.6.5": - version: 2.6.5 - resolution: "@ethereumjs/common@npm:2.6.5" - dependencies: - crc-32: ^1.2.0 - ethereumjs-util: ^7.1.5 - checksum: 86792c74eeead4e699b97d61ea23a9eddf48ed798922ddb77f570ac47e81e02d19be350e5308d24ee13ba57a78034161c0c9412d32f226ef794072f803aa32f8 - languageName: node - linkType: hard - -"@ethereumjs/ethash@npm:^1.1.0": - version: 1.1.0 - resolution: "@ethereumjs/ethash@npm:1.1.0" - dependencies: - "@ethereumjs/block": ^3.5.0 - "@types/levelup": ^4.3.0 - buffer-xor: ^2.0.1 - ethereumjs-util: ^7.1.1 - miller-rabin: ^4.0.0 - checksum: dc9ca39e2b5f19927d982ad73015446d589b01daed78aee8c6c82e36eabd8ef916eb0c55b1f95d0c7377631a59b8fb414fcee83ecac9c3f067660d7053cfc480 - languageName: node - linkType: hard - -"@ethereumjs/tx@npm:^3.5.1, @ethereumjs/tx@npm:^3.5.2": - version: 3.5.2 - resolution: "@ethereumjs/tx@npm:3.5.2" - dependencies: - "@ethereumjs/common": ^2.6.4 - ethereumjs-util: ^7.1.5 - checksum: 6162af9474ed673a8f57121dec88958ad0c6c26dd9158c262253397a6ce542904883971b42b065c608568761a18039c784c5f705c70e8fda28b0c836d48fbc5b - languageName: node - linkType: hard - -"@ethereumjs/vm@npm:^5.9.0": - version: 5.9.3 - resolution: "@ethereumjs/vm@npm:5.9.3" - dependencies: - "@ethereumjs/block": ^3.6.3 - "@ethereumjs/blockchain": ^5.5.3 - "@ethereumjs/common": ^2.6.5 - "@ethereumjs/tx": ^3.5.2 - async-eventemitter: ^0.2.4 - core-js-pure: ^3.0.1 - debug: ^4.3.3 - ethereumjs-util: ^7.1.5 - functional-red-black-tree: ^1.0.1 - mcl-wasm: ^0.7.1 - merkle-patricia-tree: ^4.2.4 - rustbn.js: ~0.2.0 - checksum: 4d259a2e660cf9b36c610f8f2c022945258cf4a1bc55a68a9340e27e9f2ba6f3460d911aa4ec5b094751af33b90ad2b98cfc4111b02bdaed319c98705f3dbb26 - languageName: node - linkType: hard - "@ethersproject/abi@npm:5.0.0-beta.153": version: 5.0.0-beta.153 resolution: "@ethersproject/abi@npm:5.0.0-beta.153" @@ -3620,6 +3539,7 @@ __metadata: "@babel/node": ^7.12.1 "@babel/preset-env": ^7.11.5 "@babel/register": ^7.12.1 + "@nomicfoundation/hardhat-foundry": ^1.0.0 "@nomiclabs/hardhat-ethers": ^2.0.4 "@nomiclabs/hardhat-etherscan": ^2.1.8 "@nomiclabs/hardhat-ganache": ^2.0.1 @@ -3648,7 +3568,7 @@ __metadata: ethereumjs-testrpc-sc: ^6.5.1-sc.1 ethereumjs-util: ^7.0.8 ethers: ^5.1.4 - hardhat: 2.9.9 + hardhat: 2.12.7 hardhat-contract-sizer: ^2.5.0 hardhat-gas-reporter: 1.0.8 hardhat-ignore-warnings: "skozin/hardhat-ignore-warnings#0ecf2ae85bddb83594193ee5c463cb4ae54cde7d" @@ -3767,6 +3687,282 @@ __metadata: languageName: node linkType: hard +"@nomicfoundation/ethereumjs-block@npm:^4.0.0": + version: 4.0.0 + resolution: "@nomicfoundation/ethereumjs-block@npm:4.0.0" + dependencies: + "@nomicfoundation/ethereumjs-common": ^3.0.0 + "@nomicfoundation/ethereumjs-rlp": ^4.0.0 + "@nomicfoundation/ethereumjs-trie": ^5.0.0 + "@nomicfoundation/ethereumjs-tx": ^4.0.0 + "@nomicfoundation/ethereumjs-util": ^8.0.0 + ethereum-cryptography: 0.1.3 + checksum: c034da8adb519fb592de4cb927381759bb79a5597e208e8efff446b5e1058b83e11af6e0f6810e2f473523d7d381572b9ec534630dd6e939d56dfafc10ed2939 + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-blockchain@npm:^6.0.0": + version: 6.0.0 + resolution: "@nomicfoundation/ethereumjs-blockchain@npm:6.0.0" + dependencies: + "@nomicfoundation/ethereumjs-block": ^4.0.0 + "@nomicfoundation/ethereumjs-common": ^3.0.0 + "@nomicfoundation/ethereumjs-ethash": ^2.0.0 + "@nomicfoundation/ethereumjs-rlp": ^4.0.0 + "@nomicfoundation/ethereumjs-trie": ^5.0.0 + "@nomicfoundation/ethereumjs-util": ^8.0.0 + abstract-level: ^1.0.3 + debug: ^4.3.3 + ethereum-cryptography: 0.1.3 + level: ^8.0.0 + lru-cache: ^5.1.1 + memory-level: ^1.0.0 + checksum: 482149f2cfd8110c1e74c2e1cc5c578778e921dc6a8a6d98ecfebeacf713f9beee2d27c37b642ca553158985a69bc8e04806eac059d8d6a2ba66f6c85a066ba2 + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-common@npm:^3.0.0": + version: 3.0.0 + resolution: "@nomicfoundation/ethereumjs-common@npm:3.0.0" + dependencies: + "@nomicfoundation/ethereumjs-util": ^8.0.0 + crc-32: ^1.2.0 + checksum: 2381dd1223524e386f145cca4508b2c613afda39cbb9a0a146120909588cc59700edecc9fa6767fcc867f5b3d674b6356411e8614b8940473ef3e9d8dcba5b5f + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-ethash@npm:^2.0.0": + version: 2.0.0 + resolution: "@nomicfoundation/ethereumjs-ethash@npm:2.0.0" + dependencies: + "@nomicfoundation/ethereumjs-block": ^4.0.0 + "@nomicfoundation/ethereumjs-rlp": ^4.0.0 + "@nomicfoundation/ethereumjs-util": ^8.0.0 + abstract-level: ^1.0.3 + bigint-crypto-utils: ^3.0.23 + ethereum-cryptography: 0.1.3 + checksum: ab2c3abdab6ec1dd1c858b8b11f97feee4ced6c9f021adcb3ba8c560839523d9cab2e2368f1188d9db12fd48202fd46abea9d7e09448b7ce19dc7573d822ecc5 + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-evm@npm:^1.0.0": + version: 1.0.0 + resolution: "@nomicfoundation/ethereumjs-evm@npm:1.0.0" + dependencies: + "@nomicfoundation/ethereumjs-common": ^3.0.0 + "@nomicfoundation/ethereumjs-util": ^8.0.0 + "@types/async-eventemitter": ^0.2.1 + async-eventemitter: ^0.2.4 + debug: ^4.3.3 + ethereum-cryptography: 0.1.3 + mcl-wasm: ^0.7.1 + rustbn.js: ~0.2.0 + checksum: d58581a7ac6c01bbfebb5d60b49fa0c3463bcf5a02d6e3a0da58f631bffb6ac3a4b48c302b3707541047f26f1c6658aa5719b91367c16f41d3fb2a3b28f31cf4 + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-rlp@npm:^4.0.0, @nomicfoundation/ethereumjs-rlp@npm:^4.0.0-beta.2": + version: 4.0.0 + resolution: "@nomicfoundation/ethereumjs-rlp@npm:4.0.0" + bin: + rlp: bin/rlp + checksum: feb52ec7c8f2a13463042441e7b217e9818a85c58473f04c8f1ba67f9039e312895e18bc4dbb908a104aca473b152bd2288c7342a8c8baa483f67af65d4aa1de + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-statemanager@npm:^1.0.0": + version: 1.0.0 + resolution: "@nomicfoundation/ethereumjs-statemanager@npm:1.0.0" + dependencies: + "@nomicfoundation/ethereumjs-common": ^3.0.0 + "@nomicfoundation/ethereumjs-rlp": ^4.0.0 + "@nomicfoundation/ethereumjs-trie": ^5.0.0 + "@nomicfoundation/ethereumjs-util": ^8.0.0 + debug: ^4.3.3 + ethereum-cryptography: 0.1.3 + functional-red-black-tree: ^1.0.1 + checksum: 4657e551d96a5f7ef93c630a514bb912531e8253c0a9ccb9d2b4253aaebf120dbc0a95c00de5583b8f712ca6066d45020f8667fa526c8dd4745609ac829b2a17 + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-trie@npm:^5.0.0": + version: 5.0.0 + resolution: "@nomicfoundation/ethereumjs-trie@npm:5.0.0" + dependencies: + "@nomicfoundation/ethereumjs-rlp": ^4.0.0 + "@nomicfoundation/ethereumjs-util": ^8.0.0 + ethereum-cryptography: 0.1.3 + readable-stream: ^3.6.0 + checksum: d6963e4a20e5c67bb926fbb63f8b1a6a273590d7781fb63e774534b93c62e08d871a60fbc0f1aabce2934f02796210757d5223986b572261056c13e3ea5b5961 + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-tx@npm:^4.0.0": + version: 4.0.0 + resolution: "@nomicfoundation/ethereumjs-tx@npm:4.0.0" + dependencies: + "@nomicfoundation/ethereumjs-common": ^3.0.0 + "@nomicfoundation/ethereumjs-rlp": ^4.0.0 + "@nomicfoundation/ethereumjs-util": ^8.0.0 + ethereum-cryptography: 0.1.3 + checksum: fd6a09467a5e4fd2ec0fbf14d26487abb1ae3e1f6e3b1343860e5c2f8968359067f26ceb571271059bc5c33ae4c16ae346816b55c460177732677a4f6181e2f2 + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-util@npm:^8.0.0": + version: 8.0.0 + resolution: "@nomicfoundation/ethereumjs-util@npm:8.0.0" + dependencies: + "@nomicfoundation/ethereumjs-rlp": ^4.0.0-beta.2 + ethereum-cryptography: 0.1.3 + checksum: d75c50e29dd52d7ea7a9d9c8522e1c4c00de023cd64a9bde0141a971ae3bf1a8762594f8e93ac43825fc5fbb954b175a52fe9d5b44236db98d60385cb2942773 + languageName: node + linkType: hard + +"@nomicfoundation/ethereumjs-vm@npm:^6.0.0": + version: 6.0.0 + resolution: "@nomicfoundation/ethereumjs-vm@npm:6.0.0" + dependencies: + "@nomicfoundation/ethereumjs-block": ^4.0.0 + "@nomicfoundation/ethereumjs-blockchain": ^6.0.0 + "@nomicfoundation/ethereumjs-common": ^3.0.0 + "@nomicfoundation/ethereumjs-evm": ^1.0.0 + "@nomicfoundation/ethereumjs-rlp": ^4.0.0 + "@nomicfoundation/ethereumjs-statemanager": ^1.0.0 + "@nomicfoundation/ethereumjs-trie": ^5.0.0 + "@nomicfoundation/ethereumjs-tx": ^4.0.0 + "@nomicfoundation/ethereumjs-util": ^8.0.0 + "@types/async-eventemitter": ^0.2.1 + async-eventemitter: ^0.2.4 + debug: ^4.3.3 + ethereum-cryptography: 0.1.3 + functional-red-black-tree: ^1.0.1 + mcl-wasm: ^0.7.1 + rustbn.js: ~0.2.0 + checksum: 4cb2de3821f5b3b649e3652473aa1e2661fc8f958770720a027cfdeb8887b8946e9ad85f98703e44e2d23b53def89fec73e5192de6b9ef0243ccc33dfd6975f8 + languageName: node + linkType: hard + +"@nomicfoundation/hardhat-foundry@npm:^1.0.0": + version: 1.0.0 + resolution: "@nomicfoundation/hardhat-foundry@npm:1.0.0" + dependencies: + chalk: ^2.4.2 + peerDependencies: + hardhat: ^2.12.6 + checksum: ca4768663b9d6345c1a83ecbbbc4272c5f5920d7c366963aab3ed92048c08a59838e9b9a97422ad687fe0d730b5fd1be971572139641c673448983b8798a4c3f + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer-darwin-arm64@npm:0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer-darwin-arm64@npm:0.1.0" + checksum: e6db014b5c63c5d32bbde1370dea6201f62d1def69cf5387b0280b95c0046e491cbe85fc6a835bea30590ed62ef972319f1a70097cc208a8bd88dd983a93d23b + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer-darwin-x64@npm:0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer-darwin-x64@npm:0.1.0" + checksum: 1f5c8a592e70b93fc25de560460e23dd5fea90c51196d5d480c0c2f5b758de7fb409fe34f2c9c5edf9f80ad2bb9dfd96a3dbbffbda5819a1da80a6d31590f45a + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer-freebsd-x64@npm:0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer-freebsd-x64@npm:0.1.0" + checksum: 6e697edc5a68f62eeac141dfe26ed3ba21fd363b3c061ce8b7a00b154d372d3d627c3deb71609788af66a542a8570f9418dbb8de969489110279daa6bf8d8040 + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer-linux-arm64-gnu@npm:0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer-linux-arm64-gnu@npm:0.1.0" + checksum: 2c7d290e4d89164a7b695343a04462ebd6ce0d3dfa39151bd2c53f515fbc968d41a0850a3e1a8ae70dc1ff12ecd1c2b49d34b07b0ecb3866210cc81123ac3a48 + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer-linux-arm64-musl@npm:0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer-linux-arm64-musl@npm:0.1.0" + checksum: 07cf45eba4cd5ff29ee627dbea848b9cada734f19895f88934b772608893a31af0535c5e6971624ab95b53ab4fa6668271ece06c6d514a2c751d47973a3bfdd1 + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer-linux-x64-gnu@npm:0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer-linux-x64-gnu@npm:0.1.0" + checksum: 13af17479644b1cc95f8c6c572e113aef1abbab153e3ce92c1090e89989235ed77e8ff64ceb2dd9531542529f89ac052aa733db65fc063238190cb14c04c4181 + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer-linux-x64-musl@npm:0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer-linux-x64-musl@npm:0.1.0" + checksum: 1fd982bc50141113280af5c396f54d142b16dd78978b1e63292858ad79f303d686a19c1266f269ff7d65c213484bf656b762496b4843b46acadcdfbe6c49700c + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer-win32-arm64-msvc@npm:0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer-win32-arm64-msvc@npm:0.1.0" + checksum: 628d798d809c92e1148ce3c57f12dfecb71fbfc6c8373a5da14a70992c68c88a9ae4338dbf124c24bd1efd7b065af2e6ba89a4c57daf2267546ca6d7792a8741 + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer-win32-ia32-msvc@npm:0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer-win32-ia32-msvc@npm:0.1.0" + checksum: 4c6d8fcff9a20bb82d4689b2c985214cfce44a8c9a66a7351a410a594a6a7b90368309855f878948a315bad1c6c93f73097dafb5b70790ea8db8838aa2563d86 + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer-win32-x64-msvc@npm:0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer-win32-x64-msvc@npm:0.1.0" + checksum: f0b0d3ddea8472ca34db682cc913905743ef95bef01418c94b039f9245bc7fa863bb029ab6e681fcaa44d4db54d03e6987135040c5ff0fb796c7e5d5387c2d86 + languageName: node + linkType: hard + +"@nomicfoundation/solidity-analyzer@npm:^0.1.0": + version: 0.1.0 + resolution: "@nomicfoundation/solidity-analyzer@npm:0.1.0" + dependencies: + "@nomicfoundation/solidity-analyzer-darwin-arm64": 0.1.0 + "@nomicfoundation/solidity-analyzer-darwin-x64": 0.1.0 + "@nomicfoundation/solidity-analyzer-freebsd-x64": 0.1.0 + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": 0.1.0 + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": 0.1.0 + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": 0.1.0 + "@nomicfoundation/solidity-analyzer-linux-x64-musl": 0.1.0 + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": 0.1.0 + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": 0.1.0 + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": 0.1.0 + dependenciesMeta: + "@nomicfoundation/solidity-analyzer-darwin-arm64": + optional: true + "@nomicfoundation/solidity-analyzer-darwin-x64": + optional: true + "@nomicfoundation/solidity-analyzer-freebsd-x64": + optional: true + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": + optional: true + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": + optional: true + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": + optional: true + "@nomicfoundation/solidity-analyzer-linux-x64-musl": + optional: true + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": + optional: true + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": + optional: true + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": + optional: true + checksum: 6bc08ce289b9818817b54d480f8c4520035cb1a45dbbb4ee65834296ccb69e3566586318b99e18b4b87ac461c77222a5e915511492a12e0bd90c96410d841458 + languageName: node + linkType: hard + "@nomiclabs/buidler@npm:1.4.7": version: 1.4.7 resolution: "@nomiclabs/buidler@npm:1.4.7" @@ -4906,10 +5102,10 @@ __metadata: languageName: node linkType: hard -"@types/abstract-leveldown@npm:*": - version: 7.2.1 - resolution: "@types/abstract-leveldown@npm:7.2.1" - checksum: 7a1ce7f30f7e179db0d2dcc9b056a2aa54d541f1810b66e9e66f89826a1635a1038e159c441cec80e656f952264388a2ce596ef22ecc999ace03667123cf2c57 +"@types/async-eventemitter@npm:^0.2.1": + version: 0.2.1 + resolution: "@types/async-eventemitter@npm:0.2.1" + checksum: ca5182a046c91d0e4cd333d296997a05a5b7a15f12b4434648bed3d4188d057611a17fd943898be901b82a1fb029ab2b8a22cc1bed761d7c2f01b4dacf026469 languageName: node linkType: hard @@ -5019,24 +5215,6 @@ __metadata: languageName: node linkType: hard -"@types/level-errors@npm:*": - version: 3.0.0 - resolution: "@types/level-errors@npm:3.0.0" - checksum: cc9fd32145d46ad574e9d6c255ccf3c745717214a573e09dc94f63e4c5320ba8d15cc5741cb9565d4680b200b8abf729da38e38a63559ecd4cb574a81185e334 - languageName: node - linkType: hard - -"@types/levelup@npm:^4.3.0": - version: 4.3.3 - resolution: "@types/levelup@npm:4.3.3" - dependencies: - "@types/abstract-leveldown": "*" - "@types/level-errors": "*" - "@types/node": "*" - checksum: f09553ab633dacc7c550a09895d5f5d743cc0301a5358fa6c26cb0f6cca60643c881cc9823ae5727b7d641b8ab8cba60423f75242dc12ee20ec9fa246a0cd8b3 - languageName: node - linkType: hard - "@types/long@npm:^4.0.1": version: 4.0.1 resolution: "@types/long@npm:4.0.1" @@ -5195,13 +5373,6 @@ __metadata: languageName: node linkType: hard -"@ungap/promise-all-settled@npm:1.1.2": - version: 1.1.2 - resolution: "@ungap/promise-all-settled@npm:1.1.2" - checksum: be6c80a2fcea2fc4ed9ccf707da9837c2f501ba21312bf9b39f8b0c4ac7e581ed37909f4f64f8dab0c51c0ae5bdf2a45b59d9a215050876b3f27e6844dba30b6 - languageName: node - linkType: hard - "@yarnpkg/lockfile@npm:^1.1.0": version: 1.1.0 resolution: "@yarnpkg/lockfile@npm:1.1.0" @@ -5255,6 +5426,21 @@ __metadata: languageName: node linkType: hard +"abstract-level@npm:^1.0.0, abstract-level@npm:^1.0.2, abstract-level@npm:^1.0.3": + version: 1.0.3 + resolution: "abstract-level@npm:1.0.3" + dependencies: + buffer: ^6.0.3 + catering: ^2.1.0 + is-buffer: ^2.0.5 + level-supports: ^4.0.0 + level-transcoder: ^1.0.1 + module-error: ^1.0.1 + queue-microtask: ^1.2.3 + checksum: f60adf9a39ce131b9b257cea56ddfc6464debc986e222bf704a97c431946ae1ab432b3f37991e94db33277fa49b8526483595879cd6bacbe933a1d75fdafd061 + languageName: node + linkType: hard + "abstract-leveldown@npm:3.0.0": version: 3.0.0 resolution: "abstract-leveldown@npm:3.0.0" @@ -5282,19 +5468,6 @@ __metadata: languageName: node linkType: hard -"abstract-leveldown@npm:^6.2.1": - version: 6.3.0 - resolution: "abstract-leveldown@npm:6.3.0" - dependencies: - buffer: ^5.5.0 - immediate: ^3.2.3 - level-concat-iterator: ~2.0.0 - level-supports: ~1.0.0 - xtend: ~4.0.0 - checksum: fddd5380019790bcf889fbd1b5c56c81f66df85a2949befc33fab8f154bfe8d8c9cebc86295d7ad9151677d798b5c61f6dfb43477f7c7f97e3143288caf76ca4 - languageName: node - linkType: hard - "abstract-leveldown@npm:~2.6.0": version: 2.6.3 resolution: "abstract-leveldown@npm:2.6.3" @@ -5304,19 +5477,6 @@ __metadata: languageName: node linkType: hard -"abstract-leveldown@npm:~6.2.1": - version: 6.2.3 - resolution: "abstract-leveldown@npm:6.2.3" - dependencies: - buffer: ^5.5.0 - immediate: ^3.2.3 - level-concat-iterator: ~2.0.0 - level-supports: ~1.0.0 - xtend: ~4.0.0 - checksum: 193fd90d2110b63bf46aa761f18b3cb8c6e774d5b969c4b5ff8230d215b8982eac9edb8e10dcda7d9ccef361a845bcaa99e6a510d4ba7215a709b3d3ffffee8a - languageName: node - linkType: hard - "accepts@npm:~1.3.4, accepts@npm:~1.3.7": version: 1.3.7 resolution: "accepts@npm:1.3.7" @@ -7062,6 +7222,22 @@ __metadata: languageName: node linkType: hard +"bigint-crypto-utils@npm:^3.0.23": + version: 3.1.8 + resolution: "bigint-crypto-utils@npm:3.1.8" + dependencies: + bigint-mod-arith: ^3.1.0 + checksum: 8787187e10ab7fb8307c6a1e3b6aac6ae059c494caa0d3646fa147995af8f166d5c4b25cdbdee2008550db78d389107783e693871431b1702b6c983ffa8b754d + languageName: node + linkType: hard + +"bigint-mod-arith@npm:^3.1.0": + version: 3.1.2 + resolution: "bigint-mod-arith@npm:3.1.2" + checksum: d3edc1c9918becc5303ddaef6802d020dfb2bf2100ad81bd03abfab06f2fe181bf043ecbd2575c0f26a79961a6872f5141a517796fd61c05f613c6b55b81f734 + languageName: node + linkType: hard + "bignumber.js@git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2": version: 2.0.7 resolution: "bignumber.js@https://github.com/debris/bignumber.js.git#commit=94d7146671b9719e00a09c29b01a691bc85048c2" @@ -7409,6 +7585,18 @@ __metadata: languageName: node linkType: hard +"browser-level@npm:^1.0.1": + version: 1.0.1 + resolution: "browser-level@npm:1.0.1" + dependencies: + abstract-level: ^1.0.2 + catering: ^2.1.1 + module-error: ^1.0.2 + run-parallel-limit: ^1.1.0 + checksum: fafa1351ab97eceb64a60fe0372c088595d74ac7a66eb9fc5ac7a807b8cc4a2cdb10d679ecee703814fadeaf985d763f471a4820aab9d18cef2a6a30c6dbbbc7 + languageName: node + linkType: hard + "browser-process-hrtime@npm:^1.0.0": version: 1.0.0 resolution: "browser-process-hrtime@npm:1.0.0" @@ -8004,6 +8192,13 @@ __metadata: languageName: node linkType: hard +"catering@npm:^2.1.0, catering@npm:^2.1.1": + version: 2.1.1 + resolution: "catering@npm:2.1.1" + checksum: 47202d87b1dc13fdb5167557466458f491e13a03be8f13c1ab5975eb9545b34de00f4ee26f67551c23bb3596324b571277db1b13d8c1ea1e68110ab11c3d5a43 + languageName: node + linkType: hard + "caw@npm:^2.0.1": version: 2.0.1 resolution: "caw@npm:2.0.1" @@ -8365,6 +8560,20 @@ __metadata: languageName: node linkType: hard +"classic-level@npm:^1.2.0": + version: 1.2.0 + resolution: "classic-level@npm:1.2.0" + dependencies: + abstract-level: ^1.0.2 + catering: ^2.1.0 + module-error: ^1.0.1 + napi-macros: ~2.0.0 + node-gyp: latest + node-gyp-build: ^4.3.0 + checksum: 0c5265a227684d4f5db4ee192b376f138f774604213be10155fb904ee843dc90aa081e7d36d6fcbe1c83b7990ea58eaa5ab6a0cc538ecf456b5f43fba4f0df87 + languageName: node + linkType: hard + "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -9730,7 +9939,19 @@ __metadata: languageName: node linkType: hard -"debug@npm:4.3.3, debug@npm:^4.3.1, debug@npm:^4.3.3": +"debug@npm:4.3.4": + version: 4.3.4 + resolution: "debug@npm:4.3.4" + dependencies: + ms: 2.1.2 + peerDependenciesMeta: + supports-color: + optional: true + checksum: 7d71c93be25ed05e85840ec12df1a6d1848adbf8bc66948017ad4120fed17d7889e305adec560c18d70710e6de0c55548fbed170f4355045bbbbbd2afd1532a2 + languageName: node + linkType: hard + +"debug@npm:^4.3.1, debug@npm:^4.3.3": version: 4.3.3 resolution: "debug@npm:4.3.3" dependencies: @@ -9954,16 +10175,6 @@ __metadata: languageName: node linkType: hard -"deferred-leveldown@npm:~5.3.0": - version: 5.3.0 - resolution: "deferred-leveldown@npm:5.3.0" - dependencies: - abstract-leveldown: ~6.2.1 - inherits: ^2.0.3 - checksum: 2d2dbff3db68635a872218145b6c88f37358d26e31cf9e1efda229a68a56b420f82278794915c4ceb7129a651facfad4e44c8b6740d43733da6f808d981ac014 - languageName: node - linkType: hard - "define-properties@npm:^1.1.2, define-properties@npm:^1.1.3": version: 1.1.3 resolution: "define-properties@npm:1.1.3" @@ -10585,18 +10796,6 @@ __metadata: languageName: node linkType: hard -"encoding-down@npm:^6.3.0": - version: 6.3.0 - resolution: "encoding-down@npm:6.3.0" - dependencies: - abstract-leveldown: ^6.2.1 - inherits: ^2.0.3 - level-codec: ^9.0.0 - level-errors: ^2.0.0 - checksum: 002e025e623647585f410e9184840bbdec3451e7473b27dba75d89e7c031b8aef51b16aa21bd3955ef2f5f57ead57a477715d7234b677885c14f5f3af69a8873 - languageName: node - linkType: hard - "encoding@npm:^0.1.11, encoding@npm:^0.1.12, encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -11685,7 +11884,7 @@ __metadata: languageName: node linkType: hard -"ethereum-cryptography@npm:^0.1.2, ethereum-cryptography@npm:^0.1.3": +"ethereum-cryptography@npm:0.1.3, ethereum-cryptography@npm:^0.1.2, ethereum-cryptography@npm:^0.1.3": version: 0.1.3 resolution: "ethereum-cryptography@npm:0.1.3" dependencies: @@ -12008,19 +12207,6 @@ __metadata: languageName: node linkType: hard -"ethereumjs-util@npm:^7.1.1, ethereumjs-util@npm:^7.1.4, ethereumjs-util@npm:^7.1.5": - version: 7.1.5 - resolution: "ethereumjs-util@npm:7.1.5" - dependencies: - "@types/bn.js": ^5.1.0 - bn.js: ^5.1.2 - create-hash: ^1.1.2 - ethereum-cryptography: ^0.1.3 - rlp: ^2.2.4 - checksum: b438d76ce8699e56929110e32a5dc9a265cc3b53cdb5fa497f0f164ed596e5c689702b09b0be17093401618063337e4695c647dc516327cc85c9fafb37fa7b31 - languageName: node - linkType: hard - "ethereumjs-vm@npm:4.2.0": version: 4.2.0 resolution: "ethereumjs-vm@npm:4.2.0" @@ -14168,19 +14354,24 @@ fsevents@~2.3.2: languageName: node linkType: hard -"hardhat@npm:2.9.9": - version: 2.9.9 - resolution: "hardhat@npm:2.9.9" +"hardhat@npm:2.12.7": + version: 2.12.7 + resolution: "hardhat@npm:2.12.7" dependencies: - "@ethereumjs/block": ^3.6.2 - "@ethereumjs/blockchain": ^5.5.2 - "@ethereumjs/common": ^2.6.4 - "@ethereumjs/tx": ^3.5.1 - "@ethereumjs/vm": ^5.9.0 "@ethersproject/abi": ^5.1.2 "@metamask/eth-sig-util": ^4.0.0 + "@nomicfoundation/ethereumjs-block": ^4.0.0 + "@nomicfoundation/ethereumjs-blockchain": ^6.0.0 + "@nomicfoundation/ethereumjs-common": ^3.0.0 + "@nomicfoundation/ethereumjs-evm": ^1.0.0 + "@nomicfoundation/ethereumjs-rlp": ^4.0.0 + "@nomicfoundation/ethereumjs-statemanager": ^1.0.0 + "@nomicfoundation/ethereumjs-trie": ^5.0.0 + "@nomicfoundation/ethereumjs-tx": ^4.0.0 + "@nomicfoundation/ethereumjs-util": ^8.0.0 + "@nomicfoundation/ethereumjs-vm": ^6.0.0 + "@nomicfoundation/solidity-analyzer": ^0.1.0 "@sentry/node": ^5.18.1 - "@solidity-parser/parser": ^0.14.1 "@types/bn.js": ^5.1.0 "@types/lru-cache": ^5.1.0 abort-controller: ^3.0.0 @@ -14193,31 +14384,28 @@ fsevents@~2.3.2: debug: ^4.1.1 enquirer: ^2.3.0 env-paths: ^2.2.0 - ethereum-cryptography: ^0.1.2 + ethereum-cryptography: ^1.0.3 ethereumjs-abi: ^0.6.8 - ethereumjs-util: ^7.1.4 find-up: ^2.1.0 fp-ts: 1.19.3 fs-extra: ^7.0.1 glob: 7.2.0 immutable: ^4.0.0-rc.12 io-ts: 1.10.4 + keccak: ^3.0.2 lodash: ^4.17.11 - merkle-patricia-tree: ^4.2.4 mnemonist: ^0.38.0 - mocha: ^9.2.0 + mocha: ^10.0.0 p-map: ^4.0.0 qs: ^6.7.0 raw-body: ^2.4.1 resolve: 1.17.0 semver: ^6.3.0 - slash: ^3.0.0 solc: 0.7.3 source-map-support: ^0.5.13 stacktrace-parser: ^0.1.10 - true-case-path: ^2.2.1 tsort: 0.0.1 - undici: ^5.4.0 + undici: ^5.14.0 uuid: ^8.3.2 ws: ^7.4.6 peerDependencies: @@ -14230,7 +14418,7 @@ fsevents@~2.3.2: optional: true bin: hardhat: internal/cli/cli.js - checksum: 79080cc2dfdedb3bb7790e0cbec3e4d51ded9444f4da7f8a71dcc9969bbf626c03146fe68dbaf2ef6917ce116f5d6b3f52ad57c0739fa4b6747324a52ec7850f + checksum: cdd74f22e6783a1395781a66992ea869c012645d1598da7c20a71bb55ef1707921b056ea8df88371be918e705ca5691d3244b6099a95da595012b4475686e374 languageName: node linkType: hard @@ -15641,6 +15829,13 @@ fsevents@~2.3.2: languageName: node linkType: hard +"is-buffer@npm:^2.0.5": + version: 2.0.5 + resolution: "is-buffer@npm:2.0.5" + checksum: 1a6dc68206e834887d3b0d8e8ec6c95e0d780314479526a5a2cf458838d1bc441a105c4cebf95d8cc16e383238f66c41761ec622f6154043186e3d9439d56970 + languageName: node + linkType: hard + "is-buffer@npm:~2.0.3": version: 2.0.4 resolution: "is-buffer@npm:2.0.4" @@ -16983,6 +17178,18 @@ fsevents@~2.3.2: languageName: node linkType: hard +"keccak@npm:^3.0.2": + version: 3.0.3 + resolution: "keccak@npm:3.0.3" + dependencies: + node-addon-api: ^2.0.0 + node-gyp: latest + node-gyp-build: ^4.2.0 + readable-stream: ^3.6.0 + checksum: d95dbe1871ee87f1df270b57366061c72e16cf43623ca83116479082ffbee9ef67feeebbb40ccfb4db305a571efba1a20e5e66ae4d1ff95e4501aa6896036cb3 + languageName: node + linkType: hard + "keyv@npm:3.0.0, keyv@npm:^3.0.0": version: 3.0.0 resolution: "keyv@npm:3.0.0" @@ -17132,13 +17339,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"level-concat-iterator@npm:~2.0.0": - version: 2.0.1 - resolution: "level-concat-iterator@npm:2.0.1" - checksum: d5ac362a950bcf63bc19c4e8d397055c9bbd335eea2c56f7de372d38c66147d6db2430596025861d99820f890a9881aef9a192ee62b109ccf0885c0b5c5c2586 - languageName: node - linkType: hard - "level-errors@npm:^1.0.3, level-errors@npm:~1.0.3": version: 1.0.5 resolution: "level-errors@npm:1.0.5" @@ -17191,17 +17391,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"level-iterator-stream@npm:~4.0.0": - version: 4.0.2 - resolution: "level-iterator-stream@npm:4.0.2" - dependencies: - inherits: ^2.0.4 - readable-stream: ^3.4.0 - xtend: ^4.0.2 - checksum: 795cdbbf856b58fffaf19e0d0b294f65fd4d8feb22bdee8563408f739107ce88b03b8b36ecc60be95c736ea676d611f95dabfbbb15346a9005ed627ae644dfb5 - languageName: node - linkType: hard - "level-mem@npm:^3.0.1": version: 3.0.1 resolution: "level-mem@npm:3.0.1" @@ -17212,26 +17401,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"level-mem@npm:^5.0.1": - version: 5.0.1 - resolution: "level-mem@npm:5.0.1" - dependencies: - level-packager: ^5.0.3 - memdown: ^5.0.0 - checksum: 715c2e59e3b6814324d961155cd280be7053c3e82446906b1ab7e6a024719d5eb545238c946ab8059da301fefa092c64678661de1ece9a035ed396dd21af306a - languageName: node - linkType: hard - -"level-packager@npm:^5.0.3": - version: 5.1.1 - resolution: "level-packager@npm:5.1.1" - dependencies: - encoding-down: ^6.3.0 - levelup: ^4.3.2 - checksum: bf36e98c6dcb1f35c6e05b6fee9e505feb0ca5b88d88206e96bfd328da5ed6c2e52d8b0c5ba53d283f74d8a9e9ab634697c4f7de69339ad26a4e302d8299b98e - languageName: node - linkType: hard - "level-packager@npm:~4.0.0": version: 4.0.1 resolution: "level-packager@npm:4.0.1" @@ -17269,12 +17438,20 @@ fsevents@~2.3.2: languageName: node linkType: hard -"level-supports@npm:~1.0.0": +"level-supports@npm:^4.0.0": + version: 4.0.1 + resolution: "level-supports@npm:4.0.1" + checksum: 6addbea71960db2ea5518010c76bcafb4283f58a7f56b636b495380be39b7445d1d08a1dd20b24c9b96b05bd8eddcaf7212290f52ade7ba79b8358ef7e679099 + languageName: node + linkType: hard + +"level-transcoder@npm:^1.0.1": version: 1.0.1 - resolution: "level-supports@npm:1.0.1" + resolution: "level-transcoder@npm:1.0.1" dependencies: - xtend: ^4.0.2 - checksum: 73c845921516d38ea57d6574908e86fedbdf3a069938f14f72e221e3f9dc04adc93b0b484fc9d7591c3baab7405f33292d90250b4239a75c6afc7f37bc5b3540 + buffer: ^6.0.3 + module-error: ^1.0.1 + checksum: 4edafcd791f8c548e44f68e6967b12abf48d4d3d973143f2deca4ab98cfdb54a8018dcac043fc68b7baf3a1db931735beb5abe894032b3ffe4aed9b2f5fa29b3 languageName: node linkType: hard @@ -17299,14 +17476,13 @@ fsevents@~2.3.2: languageName: node linkType: hard -"level-ws@npm:^2.0.0": - version: 2.0.0 - resolution: "level-ws@npm:2.0.0" +"level@npm:^8.0.0": + version: 8.0.0 + resolution: "level@npm:8.0.0" dependencies: - inherits: ^2.0.3 - readable-stream: ^3.1.0 - xtend: ^4.0.1 - checksum: c826ebd63a167389fc172235ec66cedd016055768c53353b7577462dfdfd16462cb13ee87529c2f95ee61124d94e3da61acf6bd8b62eec1a9605e8a96e5bb8eb + browser-level: ^1.0.1 + classic-level: ^1.2.0 + checksum: e04aa34bb3392865a968a02c229513b80ad46c486bc6a49184268e62c7047375738e5193453bb045545e6e8c443f6ccff5c2fd643ed283febb76ddc10ddb46aa languageName: node linkType: hard @@ -17337,19 +17513,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"levelup@npm:^4.3.2": - version: 4.4.0 - resolution: "levelup@npm:4.4.0" - dependencies: - deferred-leveldown: ~5.3.0 - level-errors: ~2.0.0 - level-iterator-stream: ~4.0.0 - level-supports: ~1.0.0 - xtend: ~4.0.0 - checksum: 7cc5b84c29baeae52ee81c5d6f56a03557ec0eed4b95b1a7f22c82d8a0ebe4cea537166d2823e0cf45125dff86f119c058ccd824b5c5f2c2c8041df745b6dd39 - languageName: node - linkType: hard - "leven@npm:^3.1.0": version: 3.1.0 resolution: "leven@npm:3.1.0" @@ -18182,20 +18345,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"memdown@npm:^5.0.0": - version: 5.1.0 - resolution: "memdown@npm:5.1.0" - dependencies: - abstract-leveldown: ~6.2.1 - functional-red-black-tree: ~1.0.1 - immediate: ~3.2.3 - inherits: ~2.0.1 - ltgt: ~2.2.0 - safe-buffer: ~5.2.0 - checksum: ce9ad9e7ddb761eadb89e72a0e9bcc50474eab9bc1dafdf662140e0264d746d58b07b0bb19de0326f097e04c9d7a8c91b59ff811b4661d30bac8655b06b540df - languageName: node - linkType: hard - "memdown@npm:~3.0.0": version: 3.0.0 resolution: "memdown@npm:3.0.0" @@ -18210,6 +18359,17 @@ fsevents@~2.3.2: languageName: node linkType: hard +"memory-level@npm:^1.0.0": + version: 1.0.0 + resolution: "memory-level@npm:1.0.0" + dependencies: + abstract-level: ^1.0.0 + functional-red-black-tree: ^1.0.1 + module-error: ^1.0.1 + checksum: 391eb84bbd5afbd8273a7b20534c3449ad01e294ec7a79998bbfe84f17f1620e015da56e06a8fbf4dcbae711ef2cb81351b8274ab21c27e120e4144494cd245e + languageName: node + linkType: hard + "memorystream@npm:^0.3.1": version: 0.3.1 resolution: "memorystream@npm:0.3.1" @@ -18350,20 +18510,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"merkle-patricia-tree@npm:^4.2.4": - version: 4.2.4 - resolution: "merkle-patricia-tree@npm:4.2.4" - dependencies: - "@types/levelup": ^4.3.0 - ethereumjs-util: ^7.1.4 - level-mem: ^5.0.1 - level-ws: ^2.0.0 - readable-stream: ^3.6.0 - semaphore-async-await: ^1.5.1 - checksum: e69956f11ac30d53486fe6590968f363b8449b1e12006a4ec7e95a3d887687b916a3ba3d6d024a9176cd67983c44a3fde9417d2d156e414bd753b7ead4de5b56 - languageName: node - linkType: hard - "methods@npm:~1.1.2": version: 1.1.2 resolution: "methods@npm:1.1.2" @@ -18513,12 +18659,12 @@ fsevents@~2.3.2: languageName: node linkType: hard -"minimatch@npm:4.2.1": - version: 4.2.1 - resolution: "minimatch@npm:4.2.1" +"minimatch@npm:5.0.1": + version: 5.0.1 + resolution: "minimatch@npm:5.0.1" dependencies: - brace-expansion: ^1.1.7 - checksum: 953d3cd9bd77627db5bf81ab24fd903321eb0c336ac357cba862172ffa1f9db07a315f2de38f0dcf72462549a32863585fce55cfde91eb57ba731ec4edc7bb97 + brace-expansion: ^2.0.1 + checksum: 6554aca25884b6c31bf42ca7c91970bb0f0c82447b99468f87809ba9ad7803fcd6dd888e58fcd592df5b1a0fd4f5e2b752656a1dbd6a9bbeb629d2c40f1f8b94 languageName: node linkType: hard @@ -18766,6 +18912,38 @@ fsevents@~2.3.2: languageName: node linkType: hard +"mocha@npm:^10.0.0": + version: 10.2.0 + resolution: "mocha@npm:10.2.0" + dependencies: + ansi-colors: 4.1.1 + browser-stdout: 1.3.1 + chokidar: 3.5.3 + debug: 4.3.4 + diff: 5.0.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 7.2.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.0.1 + ms: 2.1.3 + nanoid: 3.3.3 + serialize-javascript: 6.0.0 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.2.1 + yargs: 16.2.0 + yargs-parser: 20.2.4 + yargs-unparser: 2.0.0 + bin: + _mocha: bin/_mocha + mocha: bin/mocha.js + checksum: 4298ccaf890d6c888bc5539ef7e35c237fa3a9ca33d168f6c5122e0250823b5460dfb09e1ab870a93255d67963727dff9241557f8f41b96258f203fb12878189 + languageName: node + linkType: hard + "mocha@npm:^7.1.1, mocha@npm:^7.1.2": version: 7.2.0 resolution: "mocha@npm:7.2.0" @@ -18801,41 +18979,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"mocha@npm:^9.2.0": - version: 9.2.2 - resolution: "mocha@npm:9.2.2" - dependencies: - "@ungap/promise-all-settled": 1.1.2 - ansi-colors: 4.1.1 - browser-stdout: 1.3.1 - chokidar: 3.5.3 - debug: 4.3.3 - diff: 5.0.0 - escape-string-regexp: 4.0.0 - find-up: 5.0.0 - glob: 7.2.0 - growl: 1.10.5 - he: 1.2.0 - js-yaml: 4.1.0 - log-symbols: 4.1.0 - minimatch: 4.2.1 - ms: 2.1.3 - nanoid: 3.3.1 - serialize-javascript: 6.0.0 - strip-json-comments: 3.1.1 - supports-color: 8.1.1 - which: 2.0.2 - workerpool: 6.2.0 - yargs: 16.2.0 - yargs-parser: 20.2.4 - yargs-unparser: 2.0.0 - bin: - _mocha: bin/_mocha - mocha: bin/mocha - checksum: 1c9bb011e2f755a763d67bd0e2f2c9b6070435c6bfba832146b0eef4f1763b149908615f291bfcf75083b3854af0017d334600ef5500105f878017ebc7ce52fc - languageName: node - linkType: hard - "mock-fs@npm:^4.1.0": version: 4.13.0 resolution: "mock-fs@npm:4.13.0" @@ -18850,6 +18993,13 @@ fsevents@~2.3.2: languageName: node linkType: hard +"module-error@npm:^1.0.1, module-error@npm:^1.0.2": + version: 1.0.2 + resolution: "module-error@npm:1.0.2" + checksum: 833bf8cb735e1834813e76bfe42c4f03b44fccb983df85ce7e9dc9b5b2ceaa1c0e5ff644da3461376425f66971caac4d1b6d3cea09749c049fbe970e20b6fa91 + languageName: node + linkType: hard + "mold-source-map@npm:~0.4.0": version: 0.4.0 resolution: "mold-source-map@npm:0.4.0" @@ -19188,12 +19338,12 @@ fsevents@~2.3.2: languageName: node linkType: hard -"nanoid@npm:3.3.1": - version: 3.3.1 - resolution: "nanoid@npm:3.3.1" +"nanoid@npm:3.3.3": + version: 3.3.3 + resolution: "nanoid@npm:3.3.3" bin: nanoid: bin/nanoid.cjs - checksum: a357d61e7c404c45526a6de65d186711bfcca134d8ce67db2d160752e1bb0bc35dd41d3d78a7f5d74fb50ad040ecf59512e92b84d114607326399c94d435fdad + checksum: 012f9e5ab59cf28359e6c6f670571a1febcf03a6d6c48800971ecf81c5df846290280e3e90236a2ee36c87bf0b91807c19aed3c82fbd58faed00aedd7186fbc8 languageName: node linkType: hard @@ -19241,6 +19391,13 @@ fsevents@~2.3.2: languageName: node linkType: hard +"napi-macros@npm:~2.0.0": + version: 2.0.0 + resolution: "napi-macros@npm:2.0.0" + checksum: 1b67e5271e6688d7801a5bfa49c50c097ead038ed552af5f4b1e849255f711581b389cbeb8d746ee14803612dbdf205c086e75606f8ff7d354bc9d4b5863912c + languageName: node + linkType: hard + "native-abort-controller@npm:^1.0.3, native-abort-controller@npm:^1.0.4": version: 1.0.4 resolution: "native-abort-controller@npm:1.0.4" @@ -19391,6 +19548,17 @@ fsevents@~2.3.2: languageName: node linkType: hard +"node-gyp-build@npm:^4.3.0": + version: 4.6.0 + resolution: "node-gyp-build@npm:4.6.0" + bin: + node-gyp-build: bin.js + node-gyp-build-optional: optional.js + node-gyp-build-test: build-test.js + checksum: f132cb9553c71c03d2e47febe28eeefe4d13e9b61b9444a2404753bc6e31e10b409d0984839bc199b01897ede8db0663110462d13e383c58c8cd9de15eff2f57 + languageName: node + linkType: hard + "node-gyp-build@npm:~3.7.0": version: 3.7.0 resolution: "node-gyp-build@npm:3.7.0" @@ -22086,6 +22254,13 @@ fsevents@~2.3.2: languageName: node linkType: hard +"queue-microtask@npm:^1.2.2, queue-microtask@npm:^1.2.3": + version: 1.2.3 + resolution: "queue-microtask@npm:1.2.3" + checksum: 0f88d794d4d825d39cdc2cda2fa701722858fc8de9567ad612776fce0d113376a3fc67f6a0091f31c9142b28f0c14fef08e9f92422b49f2372d5537e250fbfad + languageName: node + linkType: hard + "quick-lru@npm:^1.0.0": version: 1.1.0 resolution: "quick-lru@npm:1.1.0" @@ -22434,7 +22609,7 @@ fsevents@~2.3.2: languageName: node linkType: hard -"readable-stream@npm:2 || 3, readable-stream@npm:^3.0.2, readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.0, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": +"readable-stream@npm:2 || 3, readable-stream@npm:^3.0.2, readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": version: 3.6.0 resolution: "readable-stream@npm:3.6.0" dependencies: @@ -23166,6 +23341,15 @@ resolve@1.1.x: languageName: node linkType: hard +"run-parallel-limit@npm:^1.1.0": + version: 1.1.0 + resolution: "run-parallel-limit@npm:1.1.0" + dependencies: + queue-microtask: ^1.2.2 + checksum: 0176e95921f24d611259c39618bffd3970343c838243b9bfedc463a5e91042fa13d3f8868f3fd9b4437545595d3d21d68ae3b769f05e251d10812aa5a901ea93 + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.1.9 resolution: "run-parallel@npm:1.1.9" @@ -23391,13 +23575,6 @@ resolve@1.1.x: languageName: node linkType: hard -"semaphore-async-await@npm:^1.5.1": - version: 1.5.1 - resolution: "semaphore-async-await@npm:1.5.1" - checksum: 439e67dfad14a77b094cdd1488a7edd9d01e5b91f0b35ca9893ebe7fe70eb44083ef83cee04a9bcbcf94a9a3457e278139742c3ef7fb97c94085506962ac4541 - languageName: node - linkType: hard - "semaphore@npm:>=1.0.1, semaphore@npm:^1.0.3, semaphore@npm:^1.1.0": version: 1.1.0 resolution: "semaphore@npm:1.1.0" @@ -25665,13 +25842,6 @@ resolve@1.1.x: languageName: node linkType: hard -"true-case-path@npm:^2.2.1": - version: 2.2.1 - resolution: "true-case-path@npm:2.2.1" - checksum: 963316436960f9fa2c396b50b065218b6d9a6690ef5c0e70c3e560168272da46d14cb8c19e361c5e9c29fa0425f18b5d44ded8fdb55a38e06a58fe218522be5f - languageName: node - linkType: hard - "truffle-extract@npm:^1.2.1": version: 1.2.1 resolution: "truffle-extract@npm:1.2.1" @@ -26042,12 +26212,12 @@ resolve@1.1.x: languageName: node linkType: hard -"undici@npm:^5.4.0": - version: 5.16.0 - resolution: "undici@npm:5.16.0" +"undici@npm:^5.14.0": + version: 5.19.1 + resolution: "undici@npm:5.19.1" dependencies: busboy: ^1.6.0 - checksum: 48049fea77d4d43ad921ba221c7a2671f6ca5bf7509f09f1308ca4b070a4a39a475811b3a4e499b0106609f65a5880c6b57ac89ab11cdd9b5c5366651a7b1227 + checksum: fda67aea0d188864ff9bd8273ab50471b754b0a6f9942a4a57d1bffaf4e481f3eba453e8740776196ed4c8fcf5f55c04bb00629f4fbe6f46794e1b57415008cd languageName: node linkType: hard @@ -28049,10 +28219,10 @@ resolve@1.1.x: languageName: node linkType: hard -"workerpool@npm:6.2.0": - version: 6.2.0 - resolution: "workerpool@npm:6.2.0" - checksum: b0590cd8359001226ac9578ec6188c8fb7776359232e9a3ca9e413332b07afbf3a4f5ad023668c1bd477ed590c21b70ae75d366baa3b595a62be76ae06b84af3 +"workerpool@npm:6.2.1": + version: 6.2.1 + resolution: "workerpool@npm:6.2.1" + checksum: 1ddf04aea8149bd822c90b7f9dcb9bcd39d5fa474e1193098f0623b3bd82fb07ebbddfac7d0b441dbb97747f6ace0d5e1432e451167c0166445d06de13d05b2d languageName: node linkType: hard @@ -28339,7 +28509,7 @@ resolve@1.1.x: languageName: node linkType: hard -"xtend@npm:^4.0.0, xtend@npm:^4.0.1, xtend@npm:^4.0.2, xtend@npm:~4.0.0, xtend@npm:~4.0.1": +"xtend@npm:^4.0.0, xtend@npm:^4.0.1, xtend@npm:~4.0.0, xtend@npm:~4.0.1": version: 4.0.2 resolution: "xtend@npm:4.0.2" checksum: 37ee522a3e9fb9b143a400c30b21dc122aa8c9c9411c6afae1005a4617dc20a21765c114d544e37a6bb60c2733dd8ee0a44ed9e80d884ac78cccd30b5e0ab0da From b353d08b46d9c08016676ee6149681a7ccde6d07 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Tue, 14 Feb 2023 21:31:28 +0700 Subject: [PATCH 010/199] test: AccountingOracle submit extra data handlers refactor --- ...ng-oracle-submit-report-extra-data.test.js | 199 ++++++++---------- 1 file changed, 88 insertions(+), 111 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index b098b799f..788367471 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -1,5 +1,4 @@ const { assert } = require('../../helpers/assert') -const { assertEvent } = require('@aragon/contract-helpers-test/src/asserts') const { e9, e18, e27 } = require('../../helpers/utils') const { @@ -14,74 +13,94 @@ const { SLOTS_PER_FRAME } = require('./accounting-oracle-deploy.test') +const getDefaultExtraData = () => ({ + stuckKeys: [ + { moduleId: 1, nodeOpIds: [0], keysCounts: [1] }, + { moduleId: 2, nodeOpIds: [0], keysCounts: [2] }, + { moduleId: 3, nodeOpIds: [2], keysCounts: [3] } + ], + exitedKeys: [ + { moduleId: 2, nodeOpIds: [1, 2], keysCounts: [1, 3] }, + { moduleId: 3, nodeOpIds: [1], keysCounts: [2] } + ] +}) + +const getDefaultReportFields = (overrides) => ({ + consensusVersion: CONSENSUS_VERSION, + numValidators: 10, + clBalanceGwei: e9(320), + stakingModuleIdsWithNewlyExitedValidators: [1], + numExitedValidatorsByStakingModule: [3], + withdrawalVaultBalance: e18(1), + elRewardsVaultBalance: e18(2), + lastWithdrawalRequestIdToFinalize: 1, + finalizationShareRate: e27(1), + isBunkerMode: true, + extraDataFormat: EXTRA_DATA_FORMAT_LIST, + // required override: refSlot, + // required override: extraDataHash, + // required override: extraDataItemsCount + ...overrides +}) + contract('AccountingOracle', ([admin, account1, account2, member1, member2, stranger]) => { let consensus = null let oracle = null - let reportItems = null - let reportFields = null - let extraDataList = null - let extraDataHash = null - let extraDataItems = null let oracleVersion = null - let deadline = null - let extraData = null const deploy = async (options = undefined) => { const deployed = await deployAndConfigureAccountingOracle(admin) - const { refSlot } = await deployed.consensus.getCurrentFrame() - - extraData = { - stuckKeys: [ - { moduleId: 1, nodeOpIds: [0], keysCounts: [1] }, - { moduleId: 2, nodeOpIds: [0], keysCounts: [2] }, - { moduleId: 3, nodeOpIds: [2], keysCounts: [3] } - ], - exitedKeys: [ - { moduleId: 2, nodeOpIds: [1, 2], keysCounts: [1, 3] }, - { moduleId: 3, nodeOpIds: [1], keysCounts: [2] } - ] - } - - extraDataItems = encodeExtraDataItems(extraData) - extraDataList = packExtraDataList(extraDataItems) - extraDataHash = calcExtraDataListHash(extraDataList) - reportFields = { - consensusVersion: CONSENSUS_VERSION, - refSlot: +refSlot, - numValidators: 10, - clBalanceGwei: e9(320), - stakingModuleIdsWithNewlyExitedValidators: [1], - numExitedValidatorsByStakingModule: [3], - withdrawalVaultBalance: e18(1), - elRewardsVaultBalance: e18(2), - lastWithdrawalRequestIdToFinalize: 1, - finalizationShareRate: e27(1), - isBunkerMode: true, - extraDataFormat: EXTRA_DATA_FORMAT_LIST, - extraDataHash: extraDataHash, - extraDataItemsCount: extraDataItems.length - } - reportItems = getReportDataItems(reportFields) - const reportHash = calcReportDataHash(reportItems) - await deployed.consensus.addMember(member1, 1, { from: admin }) - await deployed.consensus.submitReport(refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) - - oracleVersion = +(await deployed.oracle.getContractVersion()) - deadline = (await deployed.oracle.getConsensusReport()).processingDeadlineTime - oracle = deployed.oracle consensus = deployed.consensus + oracleVersion = +(await oracle.getContractVersion()) + await consensus.addMember(member1, 1, { from: admin }) } - async function prepareNextReport(newReportFields) { - await consensus.setTime(deadline) + async function prepareNextReport({ extraData: extraDataArg = {}, reportFields: reportFieldsArg = {} }) { + const extraData = extraDataArg || getDefaultExtraData() + + const extraDataItems = encodeExtraDataItems(extraData) + const extraDataList = packExtraDataList(extraDataItems) + const extraDataHash = calcExtraDataListHash(extraDataList) + + const reportFields = getDefaultReportFields({ + extraDataHash, + extraDataItemsCount: extraDataItems.length, + ...reportFieldsArg + }) - const newReportItems = getReportDataItems(newReportFields) - const reportHash = calcReportDataHash(newReportItems) + const reportItems = getReportDataItems(reportFields) + const reportHash = calcReportDataHash(reportItems) await consensus.advanceTimeToNextFrameStart() - await consensus.submitReport(newReportFields.refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) - await oracle.submitReportData(newReportItems, oracleVersion, { from: member1 }) + await consensus.submitReport(reportFields.refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) + const deadline = (await oracle.getConsensusReport()).processingDeadlineTime + await oracle.submitReportData(reportItems, oracleVersion, { from: member1 }) + + console.log(deadline) + + return { + extraData, + extraDataItems, + extraDataList, + extraDataHash, + reportFields, + reportItems, + reportHash, + deadline + } + } + + async function prepareNextReportInNextFrame({ extraData = {}, reportFields = {} }) { + const { refSlot } = await consensus.getCurrentFrame() + const next = await prepareNextReport({ + extraData, + reportFields: { + ...reportFields, + refSlot: +refSlot + SLOTS_PER_FRAME + } + }) + return next } context('deploying', () => { @@ -90,13 +109,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra it('deploying accounting oracle', async () => { assert.isNotNull(oracle) assert.isNotNull(consensus) - assert.isNotNull(reportItems) - assert.isNotNull(extraData) - assert.isNotNull(extraDataList) - assert.isNotNull(extraDataHash) - assert.isNotNull(extraDataItems) assert.isNotNull(oracleVersion) - assert.isNotNull(deadline) }) }) @@ -107,29 +120,17 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra beforeEach(deploy) it('should revert if incorrect extra data list stuckKeys moduleId', async () => { - const { refSlot } = await consensus.getCurrentFrame() - - const nextRefSlot = +refSlot + SLOTS_PER_FRAME + const extraDataDefault = getDefaultExtraData() const invalidExtraData = { - ...extraData, + ...extraDataDefault, stuckKeys: [ - ...extraData.stuckKeys, + ...extraDataDefault.stuckKeys, { moduleId: 4, nodeOpIds: [1], keysCounts: [2] }, { moduleId: 4, nodeOpIds: [1], keysCounts: [2] } ] } - const extraDataItems = encodeExtraDataItems(invalidExtraData) - const extraDataList = packExtraDataList(extraDataItems) - const extraDataHash = calcExtraDataListHash(extraDataList) - - const newReportFields = { - ...reportFields, - refSlot: nextRefSlot, - extraDataHash: extraDataHash, - extraDataItemsCount: extraDataItems.length - } - await prepareNextReport(newReportFields) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData: invalidExtraData }) await assert.reverts( oracle.submitReportExtraDataList(extraDataList, { @@ -140,29 +141,17 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) it('should revert if incorrect extra data list exitedKeys moduleId', async () => { - const { refSlot } = await consensus.getCurrentFrame() - - const nextRefSlot = +refSlot + SLOTS_PER_FRAME + const extraDataDefault = getDefaultExtraData() const invalidExtraData = { - ...extraData, + ...extraDataDefault, exitedKeys: [ - ...extraData.exitedKeys, + ...extraDataDefault.exitedKeys, { moduleId: 4, nodeOpIds: [1], keysCounts: [2] }, { moduleId: 4, nodeOpIds: [1], keysCounts: [2] } ] } - const extraDataItems = encodeExtraDataItems(invalidExtraData) - const extraDataList = packExtraDataList(extraDataItems) - const extraDataHash = calcExtraDataListHash(extraDataList) - - const newReportFields = { - ...reportFields, - refSlot: nextRefSlot, - extraDataHash: extraDataHash, - extraDataItemsCount: extraDataItems.length - } - await prepareNextReport(newReportFields) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData: invalidExtraData }) await assert.reverts( oracle.submitReportExtraDataList(extraDataList, { @@ -172,37 +161,25 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra ) }) - it('should should allow calling if correct extra data list moduleId', async () => { - const { refSlot } = await consensus.getCurrentFrame() - - const nextRefSlot = +refSlot + SLOTS_PER_FRAME + it('should allow calling if correct extra data list moduleId', async () => { + const extraDataDefault = getDefaultExtraData() const invalidExtraData = { stuckKeys: [ - ...extraData.stuckKeys, + ...extraDataDefault.stuckKeys, { moduleId: 4, nodeOpIds: [1], keysCounts: [2] }, { moduleId: 5, nodeOpIds: [1], keysCounts: [2] } ], exitedKeys: [ - ...extraData.exitedKeys, + ...extraDataDefault.exitedKeys, { moduleId: 4, nodeOpIds: [1], keysCounts: [2] }, { moduleId: 5, nodeOpIds: [1], keysCounts: [2] } ] } - const extraDataItems = encodeExtraDataItems(invalidExtraData) - const extraDataList = packExtraDataList(extraDataItems) - const extraDataHash = calcExtraDataListHash(extraDataList) - - const newReportFields = { - ...reportFields, - refSlot: nextRefSlot, - extraDataHash: extraDataHash, - extraDataItemsCount: extraDataItems.length - } - await prepareNextReport(newReportFields) + const { extraDataList, reportFields } = await prepareNextReportInNextFrame({ extraData: invalidExtraData }) const tx = await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) - assertEvent(tx, 'ExtraDataSubmitted', { expectedArgs: { refSlot: newReportFields.refSlot } }) + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) }) }) }) From 5eeadd291289a7f6522a0d3e20fccb3e6fc18603 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Tue, 14 Feb 2023 21:46:22 +0700 Subject: [PATCH 011/199] test: rm log --- .../oracle/accounting-oracle-submit-report-extra-data.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 788367471..a20a347af 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -77,8 +77,6 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra const deadline = (await oracle.getConsensusReport()).processingDeadlineTime await oracle.submitReportData(reportItems, oracleVersion, { from: member1 }) - console.log(deadline) - return { extraData, extraDataItems, From ddbc5df3d6d78c68e29f607982487115b0063448 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 15:20:30 +0200 Subject: [PATCH 012/199] test: fix lido test for initial holder --- test/0.4.24/lido.test.js | 208 +++++++++++++++++++++------------------ 1 file changed, 110 insertions(+), 98 deletions(-) diff --git a/test/0.4.24/lido.test.js b/test/0.4.24/lido.test.js index 874ed0594..6f3c5710a 100644 --- a/test/0.4.24/lido.test.js +++ b/test/0.4.24/lido.test.js @@ -10,13 +10,13 @@ const { assertRevert } = require('../helpers/assertThrow') const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') const { formatEther } = require('ethers/lib/utils') const { waitBlocks, EvmSnapshot } = require('../helpers/blockchain') -const { getEthBalance, formatStEth, formatBN, hexConcat, pad, ETH, tokens, div15, assertNoEvent, StETH } = require('../helpers/utils') +const { getEthBalance, formatStEth, formatBN, hexConcat, pad, ETH, tokens, div15, assertNoEvent, StETH, shares } = require('../helpers/utils') const { assert } = require('../helpers/assert') const nodeOperators = require('../helpers/node-operators') const { deployProtocol } = require('../helpers/protocol') const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') const { pushOracleReport } = require('../helpers/oracle') -const { SECONDS_PER_FRAME } = require('../helpers/constants') +const { SECONDS_PER_FRAME, MAX_UINT256 } = require('../helpers/constants') const { oracleReportSanityCheckerStubFactory } = require('../helpers/factories') const { newApp } = require('../helpers/dao') @@ -33,10 +33,10 @@ const ADDRESS_2 = '0x0000000000000000000000000000000000000002' const ADDRESS_3 = '0x0000000000000000000000000000000000000003' const ADDRESS_4 = '0x0000000000000000000000000000000000000004' +const INITIAL_HOLDER = '0x000000000000000000000000000000000000dead' + const UNLIMITED = 1000000000 const TOTAL_BASIS_POINTS = 10000 -const FEE_PRECISION_POINTS = bn(10).pow(bn(20)) // 100 * 10e18 -const toPrecBP = (bp) => bn(bp).mul(FEE_PRECISION_POINTS).div(bn(10000)) // Divides a BN by 1e15 const MAX_DEPOSITS = 150 @@ -269,60 +269,66 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody console.log() } - it('Execution layer rewards distribution works when zero rewards reported', async () => { - const depositAmount = 32 - const elRewards = depositAmount / TOTAL_BASIS_POINTS - const beaconRewards = 0 + it('Execution layer rewards distribution works when zero cl rewards reported', async () => { + const clRewards = 0 + const initialDeposit = 1 + const user2Deposit = 31 + const totalDeposit = initialDeposit + user2Deposit + const totalElRewards = totalDeposit / TOTAL_BASIS_POINTS + const user2Rewards = user2Deposit / TOTAL_BASIS_POINTS - await setupNodeOperatorsForELRewardsVaultTests(user2, ETH(depositAmount)) - await pushReport(1, ETH(depositAmount)) + await setupNodeOperatorsForELRewardsVaultTests(user2, ETH(user2Deposit)) + await pushReport(1, ETH(totalDeposit)) - await rewarder.reward({ from: user1, value: ETH(elRewards) }) - await pushReport(1, ETH(depositAmount + beaconRewards)) + await rewarder.reward({ from: user1, value: ETH(totalElRewards) }) + await pushReport(1, ETH(totalDeposit + clRewards)) - assertBn(await app.getTotalPooledEther(), ETH(depositAmount + elRewards + beaconRewards)) - assertBn(await app.totalSupply(), ETH(depositAmount + elRewards + beaconRewards)) - assertBn(await app.balanceOf(user2), StETH(depositAmount + elRewards)) - assertBn(await app.getTotalELRewardsCollected(), ETH(elRewards)) + assertBn(await app.getTotalPooledEther(), ETH(initialDeposit + user2Deposit + totalElRewards + clRewards)) + assertBn(await app.totalSupply(), StETH(initialDeposit + user2Deposit + totalElRewards + clRewards)) + assertBn(await app.balanceOf(user2), StETH(user2Deposit + user2Rewards)) + assertBn(await app.getTotalELRewardsCollected(), ETH(totalElRewards)) }) - it('Execution layer rewards distribution works when negative rewards reported', async () => { - const depositAmount = 32 - const elRewards = depositAmount / TOTAL_BASIS_POINTS - const beaconRewards = -2 + it('Execution layer rewards distribution works when negative cl rewards reported', async () => { + const clRewards = -2 + const initialDeposit = 1 + const user2Deposit = 31 + const totalDeposit = initialDeposit + user2Deposit + const totalElRewards = totalDeposit / TOTAL_BASIS_POINTS + const user2Rewards = user2Deposit / TOTAL_BASIS_POINTS - await setupNodeOperatorsForELRewardsVaultTests(user2, ETH(depositAmount)) - await pushReport(1, ETH(depositAmount)) + await setupNodeOperatorsForELRewardsVaultTests(user2, ETH(user2Deposit)) + await pushReport(1, ETH(totalDeposit)) - await rewarder.reward({ from: user1, value: ETH(elRewards) }) - await pushReport(1, ETH(depositAmount + beaconRewards)) + await rewarder.reward({ from: user1, value: ETH(totalElRewards) }) + await pushReport(1, ETH(totalDeposit + clRewards)) - assertBn(await app.getTotalPooledEther(), ETH(depositAmount + elRewards + beaconRewards)) - assertBn(await app.balanceOf(user2), StETH(depositAmount + elRewards + beaconRewards)) - assertBn(await app.getTotalELRewardsCollected(), ETH(elRewards)) + assertBn(await app.getTotalPooledEther(), ETH(initialDeposit + user2Deposit + totalElRewards + clRewards)) + assertBn(await app.balanceOf(user2), StETH(user2Deposit + user2Rewards + clRewards * 31 / 32)) + assertBn(await app.getTotalELRewardsCollected(), ETH(totalElRewards)) }) - it('Execution layer rewards distribution works when positive rewards reported', async () => { - const depositAmount = 32 - const elRewards = depositAmount / TOTAL_BASIS_POINTS - const beaconRewards = 3 + it('Execution layer rewards distribution works when positive cl rewards reported', async () => { + const clRewards = 3 + const initialDeposit = 1 + const user2Deposit = 31 + const totalDeposit = initialDeposit + user2Deposit + const totalElRewards = totalDeposit / TOTAL_BASIS_POINTS - await setupNodeOperatorsForELRewardsVaultTests(user2, ETH(depositAmount)) - await pushReport(1, ETH(depositAmount)) + await setupNodeOperatorsForELRewardsVaultTests(user2, ETH(user2Deposit)) + await pushReport(1, ETH(totalDeposit)) - await rewarder.reward({ from: user1, value: ETH(elRewards) }) - await pushReport(1, ETH(depositAmount + beaconRewards)) + await rewarder.reward({ from: user1, value: ETH(totalElRewards) }) + await pushReport(1, ETH(totalDeposit + clRewards)) - assertBn(await app.getTotalPooledEther(), ETH(depositAmount + elRewards + beaconRewards)) - assertBn(await app.getTotalELRewardsCollected(), ETH(elRewards)) + assertBn(await app.getTotalPooledEther(), ETH(totalDeposit + totalElRewards + clRewards)) + assertBn(await app.getTotalELRewardsCollected(), ETH(totalElRewards)) - const { modulesFee, treasuryFee } = await stakingRouter.getStakingFeeAggregateDistribution() + const fee = await app.getFee() - const stakersReward = bn(ETH(elRewards + beaconRewards)) - .mul(FEE_PRECISION_POINTS.sub(modulesFee).sub(treasuryFee)) - .div(FEE_PRECISION_POINTS) + const stakersReward = (totalElRewards + clRewards) * (TOTAL_BASIS_POINTS - fee) / TOTAL_BASIS_POINTS - assertBn(await app.balanceOf(user2), bn(StETH(depositAmount)).add(stakersReward)) + assertBn(await app.balanceOf(user2), StETH(user2Deposit + stakersReward * 31 / 32)) }) it('Attempt to set invalid execution layer rewards withdrawal limit', async () => { @@ -404,7 +410,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await rewarder.reward({ from: user1, value: ETH(elRewards) }) await pushReport(1, ETH(depositAmount + beaconRewards)) - const {totalFee} = await app.getFee() + const { totalFee } = await app.getFee() const shareOfRewardsForStakers = (TOTAL_BASIS_POINTS - totalFee) / TOTAL_BASIS_POINTS assertBn(await app.getTotalPooledEther(), ETH(depositAmount + elRewards + beaconRewards)) assertBn(await app.getBufferedEther(), ETH(elRewards)) @@ -540,16 +546,22 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await assertRevert(app.submit(ZERO_ADDRESS, { from: user1, value: ETH(0) }), 'ZERO_DEPOSIT') await assertRevert(web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(0) }), 'ZERO_DEPOSIT') + // Initial balance (1 ETH) + assertBn(await app.getTotalPooledEther(), ETH(1)) + assertBn(await app.getBufferedEther(), ETH(1)) + assertBn(await app.balanceOf(INITIAL_HOLDER), tokens(1)) + assertBn(await app.totalSupply(), tokens(1)) + // +1 ETH await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(1) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await depositContract.totalCalls(), 0) - assertBn(await app.getTotalPooledEther(), ETH(1)) - assertBn(await app.getBufferedEther(), ETH(1)) + assertBn(await app.getTotalPooledEther(), ETH(2)) + assertBn(await app.getBufferedEther(), ETH(2)) assertBn(await app.getTotalELRewardsCollected(), 0) assertBn(await app.balanceOf(user1), tokens(1)) - assertBn(await app.totalSupply(), tokens(1)) + assertBn(await app.totalSupply(), tokens(2)) // +2 ETH const receipt = await app.submit(ZERO_ADDRESS, { from: user2, value: ETH(2) }) // another form of a deposit call @@ -558,11 +570,11 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await depositContract.totalCalls(), 0) - assertBn(await app.getTotalPooledEther(), ETH(3)) - assertBn(await app.getBufferedEther(), ETH(3)) + assertBn(await app.getTotalPooledEther(), ETH(4)) + assertBn(await app.getBufferedEther(), ETH(4)) assertBn(await app.getTotalELRewardsCollected(), 0) assertBn(await app.balanceOf(user2), tokens(2)) - assertBn(await app.totalSupply(), tokens(3)) + assertBn(await app.totalSupply(), tokens(4)) // +30 ETH await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(30) }) @@ -590,19 +602,19 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await operators.setNodeOperatorStakingLimit(0, UNLIMITED, { from: voting }) assertBn(await stakingRouter.getStakingModuleMaxDepositsCount(CURATED_MODULE_ID), 1) - assertBn(await app.getTotalPooledEther(), ETH(33)) - assertBn(await app.getBufferedEther(), ETH(33)) + assertBn(await app.getTotalPooledEther(), ETH(34)) + assertBn(await app.getBufferedEther(), ETH(34)) // now deposit works await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getTotalPooledEther(), ETH(33)) - assertBn(await app.getBufferedEther(), ETH(1)) + assertBn(await app.getTotalPooledEther(), ETH(34)) + assertBn(await app.getBufferedEther(), ETH(2)) assertBn(await app.balanceOf(user1), tokens(1)) assertBn(await app.balanceOf(user2), tokens(2)) assertBn(await app.balanceOf(user3), tokens(30)) - assertBn(await app.totalSupply(), tokens(33)) + assertBn(await app.totalSupply(), tokens(34)) assertBn(await depositContract.totalCalls(), 1) const c0 = await depositContract.calls.call(0) @@ -615,21 +627,21 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(100) }) await app.deposit(1, 1, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 2, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getTotalPooledEther(), ETH(133)) - assertBn(await app.getBufferedEther(), ETH(69)) + assertBn(await app.getTotalPooledEther(), ETH(134)) + assertBn(await app.getBufferedEther(), ETH(70)) assertBn(await app.balanceOf(user1), tokens(101)) assertBn(await app.balanceOf(user2), tokens(2)) assertBn(await app.balanceOf(user3), tokens(30)) - assertBn(await app.totalSupply(), tokens(133)) + assertBn(await app.totalSupply(), tokens(134)) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 4, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getTotalPooledEther(), ETH(133)) - assertBn(await app.getBufferedEther(), ETH(5)) + assertBn(await app.getTotalPooledEther(), ETH(134)) + assertBn(await app.getBufferedEther(), ETH(6)) assertBn(await app.balanceOf(user1), tokens(101)) assertBn(await app.balanceOf(user2), tokens(2)) assertBn(await app.balanceOf(user3), tokens(30)) - assertBn(await app.totalSupply(), tokens(133)) + assertBn(await app.totalSupply(), tokens(134)) assertBn(await depositContract.totalCalls(), 4) const calls = {} @@ -725,7 +737,6 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody expectedIsStakingPaused, expectedIsStakingLimited ) => { - assert((await app.isStakingPaused()) === false) currentStakeLimit = await app.getCurrentStakeLimit() assertBn(currentStakeLimit, expectedCurrentStakeLimit) @@ -752,17 +763,18 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody } it('staking pause & unlimited resume works', async () => { + assert.equals(await app.isStakingPaused(), false) + let receipt - const MAX_UINT256 = bn(2).pow(bn(256)).sub(bn(1)) - await verifyStakeLimitState(bn(0), bn(0), MAX_UINT256, false, false) + await verifyStakeLimitState(0, 0, MAX_UINT256, false, false) receipt = await app.submit(ZERO_ADDRESS, { from: user2, value: ETH(2) }) assertEvent(receipt, 'Submitted', { expectedArgs: { sender: user2, amount: ETH(2), referral: ZERO_ADDRESS } }) await assertRevert(app.pauseStaking(), 'APP_AUTH_FAILED') receipt = await app.pauseStaking({ from: voting }) assertEvent(receipt, 'StakingPaused') - verifyStakeLimitState(bn(0), bn(0), bn(0), true, false) + await verifyStakeLimitState(0, 0, 0, true, false) await assertRevert(web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(2) }), `STAKING_PAUSED`) await assertRevert(app.submit(ZERO_ADDRESS, { from: user2, value: ETH(2) }), `STAKING_PAUSED`) @@ -770,7 +782,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await assertRevert(app.resumeStaking(), 'APP_AUTH_FAILED') receipt = await app.resumeStaking({ from: voting }) assertEvent(receipt, 'StakingResumed') - await verifyStakeLimitState(bn(0), bn(0), MAX_UINT256, false, false) + await verifyStakeLimitState(0, 0, MAX_UINT256, false, false) await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(1.1) }) receipt = await app.submit(ZERO_ADDRESS, { from: user2, value: ETH(1.4) }) @@ -942,7 +954,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody assertBn(await depositContract.totalCalls(), 1) await assertRevert(operators.removeSigningKey(0, 0, { from: voting }), 'OUT_OF_RANGE') - assertBn(await app.getBufferedEther(), ETH(1)) + assertBn(await app.getBufferedEther(), ETH(2)) await operators.removeSigningKey(0, 1, { from: voting }) @@ -950,8 +962,8 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) assertBn(await depositContract.totalCalls(), 1) - assertBn(await app.getTotalPooledEther(), ETH(133)) - assertBn(await app.getBufferedEther(), ETH(101)) + assertBn(await app.getTotalPooledEther(), ETH(134)) + assertBn(await app.getBufferedEther(), ETH(102)) }) it("out of signing keys doesn't revert but buffers", async () => { @@ -965,7 +977,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await operators.setNodeOperatorStakingLimit(0, UNLIMITED, { from: voting }) await operators.setNodeOperatorStakingLimit(1, UNLIMITED, { from: voting }) - await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(100) }) + await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(99) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await depositContract.totalCalls(), 1) @@ -1034,7 +1046,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await operators.addNodeOperator('1', ADDRESS_1, { from: voting }) await operators.addNodeOperator('2', ADDRESS_2, { from: voting }) - await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(34) }) + await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(33) }) const withdrawal = await WithdrawalVault.new(app.address, treasury) const withdrawalCredentials = hexConcat('0x01', pad(withdrawal.address, 31)) await stakingRouter.setWithdrawalCredentials(withdrawalCredentials, { from: voting }) @@ -1107,7 +1119,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(40) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getBufferedEther(), ETH(8)) + assertBn(await app.getBufferedEther(), ETH(9)) await assertRevert(app.stop({ from: user2 }), 'APP_AUTH_FAILED') await app.stop({ from: voting }) @@ -1124,7 +1136,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(4) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getBufferedEther(), ETH(12)) + assertBn(await app.getBufferedEther(), ETH(13)) }) it('rewards distribution on module with zero treasury and module fee', async () => { @@ -1163,7 +1175,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody // check stat before deposit await checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: 0 }) - await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(34) }) + await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(33) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await pushReport(1, ETH(36)) @@ -1189,7 +1201,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await operators.setNodeOperatorStakingLimit(0, UNLIMITED, { from: voting }) await operators.setNodeOperatorStakingLimit(1, UNLIMITED, { from: voting }) - await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(34) }) + await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(33) }) const withdrawal = await WithdrawalVault.new(app.address, treasury) await stakingRouter.setWithdrawalCredentials(hexConcat('0x01', pad(withdrawal.address, 31)), { from: voting }) await operators.addSigningKeys(0, 1, pad('0x010203', 48), pad('0x01', 96), { from: voting }) @@ -1216,7 +1228,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await operators.addNodeOperator('1', ADDRESS_1, { from: voting }) await operators.addNodeOperator('2', ADDRESS_2, { from: voting }) - await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(34) }) + await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(33) }) const withdrawal = await WithdrawalVault.new(app.address, treasury) await stakingRouter.setWithdrawalCredentials(hexConcat('0x01', pad(withdrawal.address, 31)), { from: voting }) await operators.addSigningKeys(0, 1, pad('0x010203', 48), pad('0x01', 96), { from: voting }) @@ -1262,16 +1274,16 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await operators.setNodeOperatorStakingLimit(0, UNLIMITED, { from: voting }) await operators.setNodeOperatorStakingLimit(1, UNLIMITED, { from: voting }) - // Only 32 ETH deposited - await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(32) }) + // Only 32 ETH deposited (we have initial 1 ETH) + await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(31) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(32) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) - assertBn(await app.totalSupply(), tokens(64)) + assertBn(await app.totalSupply(), StETH(64)) await pushReport(1, ETH(36)) await checkStat({ depositedValidators: 1, beaconValidators: 1, beaconBalance: ETH(36) }) - assertBn(await app.totalSupply(), tokens(68)) + assertBn(await app.totalSupply(), StETH(68)) await checkRewards({ treasury: 200, operator: 199 }) }) @@ -1303,7 +1315,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await nodeOperators.addNodeOperator(operators, { name: 'short on keys', rewardAddress: ADDRESS_4 }, { from: voting }) // Deposit huge chunk - await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(32 * 3 + 50) }) + await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(32 * 3 + 49) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 3, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await app.getTotalPooledEther(), ETH(146)) @@ -1428,7 +1440,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody // Small deposits for (let i = 0; i < 14; i++) await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(10) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) - await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(6) }) + await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(5) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 3, beaconValidators: 0, beaconBalance: ETH(0) }) @@ -1550,7 +1562,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await operators.setNodeOperatorStakingLimit(3, UNLIMITED, { from: voting }) // #1 and #0 get the funds - await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(64) }) + await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(63) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 2, beaconValidators: 0, beaconBalance: ETH(0) }) assertBn(await app.getTotalPooledEther(), ETH(64)) @@ -1583,38 +1595,38 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody }) it('burnShares works', async () => { - await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(1) }) + await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(2) }) // 4 ETH total // can burn shares of an arbitrary user - const expectedPreTokenAmount = await app.getPooledEthByShares(ETH(0.5)) - let receipt = await app.burnShares(user1, ETH(0.5), { from: voting }) - const expectedPostTokenAmount = await app.getPooledEthByShares(ETH(0.5)) + const pre1SharePrice = await app.getPooledEthByShares(shares(1)) + let receipt = await app.burnShares(user1, shares(1), { from: voting }) + const post1SharePrice = await app.getPooledEthByShares(shares(1)) assertEvent(receipt, 'SharesBurnt', { expectedArgs: { account: user1, - preRebaseTokenAmount: expectedPreTokenAmount, - postRebaseTokenAmount: expectedPostTokenAmount, - sharesAmount: ETH(0.5) + preRebaseTokenAmount: pre1SharePrice, + postRebaseTokenAmount: post1SharePrice, + sharesAmount: shares(1) } }) - const expectedPreDoubledAmount = await app.getPooledEthByShares(ETH(0.5)) - receipt = await app.burnShares(user1, ETH(0.5), { from: voting }) - const expectedPostDoubledAmount = await app.getPooledEthByShares(ETH(0.5)) + const pre2SharePrice = await app.getPooledEthByShares(shares(1)) + receipt = await app.burnShares(user1, shares(1), { from: voting }) + const post2SharePrice = await app.getPooledEthByShares(shares(1)) assertEvent(receipt, 'SharesBurnt', { expectedArgs: { account: user1, - preRebaseTokenAmount: expectedPreDoubledAmount, - postRebaseTokenAmount: expectedPostDoubledAmount, - sharesAmount: ETH(0.5) + preRebaseTokenAmount: pre2SharePrice, + postRebaseTokenAmount: post2SharePrice, + sharesAmount: shares(1) } }) - assertBn(expectedPreTokenAmount.mul(bn(2)), expectedPreDoubledAmount) - assertBn(tokens(0), await app.getPooledEthByShares(ETH(0.5))) + assertBn(pre1SharePrice.muln(3), pre2SharePrice.muln(2)) + assertBn(await app.getPooledEthByShares(shares(1)), ETH(3)) // user1 has zero shares after all - assertBn(await app.sharesOf(user1), tokens(0)) + assertBn(await app.sharesOf(user1), shares(0)) // voting can't continue burning if user already has no shares await assertRevert(app.burnShares(user1, 1, { from: voting }), 'BURN_AMOUNT_EXCEEDS_BALANCE') From 8eafde451e6badc429a400a4d79fd87d55df2e7b Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 16:57:34 +0200 Subject: [PATCH 013/199] test: fix stethpermit tests --- test/0.4.24/stethpermit.test.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/0.4.24/stethpermit.test.js b/test/0.4.24/stethpermit.test.js index 62d99b28d..1cb7d5366 100644 --- a/test/0.4.24/stethpermit.test.js +++ b/test/0.4.24/stethpermit.test.js @@ -6,21 +6,28 @@ const { assertRevert } = require('../helpers/assertThrow') const { signPermit, signTransferAuthorization, makeDomainSeparator } = require('./helpers/permit_helpers') const { hexStringFromBuffer } = require('./helpers/sign_utils') const { ETH } = require('../helpers/utils') +const { EvmSnapshot } = require('../helpers/blockchain') const EIP712StETH = artifacts.require('EIP712StETH') const StETHPermit = artifacts.require('StETHPermitMock') contract('StETHPermit', ([deployer, ...accounts]) => { let stEthPermit, chainId, domainSeparator + const snapshot = new EvmSnapshot(hre.ethers.provider) - beforeEach('deploy mock token', async () => { + before('deploy mock token', async () => { const eip712StETH = await EIP712StETH.new({ from: deployer }) - stEthPermit = await StETHPermit.new({ from: deployer }) + stEthPermit = await StETHPermit.new({ from: deployer, value: ETH(1) }) await stEthPermit.initializeEIP712StETH(eip712StETH.address) chainId = await web3.eth.net.getId(); domainSeparator = makeDomainSeparator('Liquid staked Ether 2.0', '2', chainId, eip712StETH.address) + await snapshot.make() + }) + + afterEach(async () => { + await snapshot.rollback() }) context('permit', () => { From 5f752a1e2abeb192a23778c1f196fcac1c9dace8 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 16:58:11 +0200 Subject: [PATCH 014/199] test: fix wsteth tests --- test/0.6.12/wsteth.test.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/0.6.12/wsteth.test.js b/test/0.6.12/wsteth.test.js index 1eedee781..94afc5764 100644 --- a/test/0.6.12/wsteth.test.js +++ b/test/0.6.12/wsteth.test.js @@ -3,14 +3,23 @@ const { expect } = require('chai') const { ZERO_ADDRESS } = constants const { shouldBehaveLikeERC20 } = require('./helpers/ERC20.behavior') +const { EvmSnapshot } = require('../helpers/blockchain') const WstETH = artifacts.require('WstETHMock') const StETH = artifacts.require('StETHMockERC20') contract('WstETH', function ([deployer, initialHolder, recipient, anotherAccount, ...otherAccounts]) { - beforeEach(async function () { + const snapshot = new EvmSnapshot(hre.ethers.provider) + + before(async function () { this.steth = await StETH.new({ from: deployer }) this.wsteth = await WstETH.new(this.steth.address, { from: deployer }) + + await snapshot.make() + }) + + afterEach(async () => { + await snapshot.rollback() }) describe(`Wrapping / Unwrapping`, function () { From 3867cfdff21b48c2392b922122b3aaf37301d2f3 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 17:01:30 +0200 Subject: [PATCH 015/199] test: fix staking-router-deposits test --- test/0.8.9/staking-router-deposits.test.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/0.8.9/staking-router-deposits.test.js b/test/0.8.9/staking-router-deposits.test.js index 92e46c004..e113010d1 100644 --- a/test/0.8.9/staking-router-deposits.test.js +++ b/test/0.8.9/staking-router-deposits.test.js @@ -52,7 +52,7 @@ contract('StakingRouter', ([depositor, stranger]) => { const maxDepositsCount = 150 await web3.eth.sendTransaction({ value: ETH(maxDepositsCount * 32), to: lido.address, from: stranger }) - assert.equals(await lido.getBufferedEther(), ETH(maxDepositsCount * 32)) + assert.equals(await lido.getBufferedEther(), ETH(maxDepositsCount * 32 + 1)) const [curated] = await stakingRouter.getStakingModules() @@ -66,18 +66,19 @@ contract('StakingRouter', ([depositor, stranger]) => { }) it('Lido.deposit() :: check deposit with keys', async () => { - // balance are 0 - assert.equals(await web3.eth.getBalance(lido.address), 0) + // balance are initial + assert.equals(await web3.eth.getBalance(lido.address), ETH(1)) assert.equals(await web3.eth.getBalance(stakingRouter.address), 0) - const sendEthForKeys = ETH(101 * 32) + const sendEthForKeys = ETH(101 * 32 - 1) + const totalPooledEther = ETH(101 * 32) const maxDepositsCount = 100 await web3.eth.sendTransaction({ value: sendEthForKeys, to: lido.address, from: stranger }) - assert.equals(await lido.getBufferedEther(), sendEthForKeys) + assert.equals(await lido.getBufferedEther(), totalPooledEther) // updated balance are lido 100 && sr 0 - assert.equals(await web3.eth.getBalance(lido.address), sendEthForKeys) + assert.equals(await web3.eth.getBalance(lido.address), totalPooledEther) assert.equals(await web3.eth.getBalance(stakingRouter.address), 0) const [curated] = await stakingRouter.getStakingModules() From c257dd3bdd16d6394ad0b9b6a1012a059e7d369e Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 17:04:45 +0200 Subject: [PATCH 016/199] test: fix deposit_distribution test --- test/scenario/deposit_distribution.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/scenario/deposit_distribution.js b/test/scenario/deposit_distribution.js index 7315fae02..780881545 100644 --- a/test/scenario/deposit_distribution.js +++ b/test/scenario/deposit_distribution.js @@ -5,7 +5,7 @@ const { EvmSnapshot } = require('../helpers/blockchain') const { deployProtocol } = require('../helpers/protocol') const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') -contract('StakingRouter', ([depositor, stranger1, dsm, address1, address2]) => { +contract('StakingRouter', ([depositor, stranger1, address1, address2]) => { const snapshot = new EvmSnapshot(hre.ethers.provider) let depositContract, stakingRouter let lido, curated, anotherCurated, voting @@ -68,12 +68,12 @@ contract('StakingRouter', ([depositor, stranger1, dsm, address1, address2]) => { await curated.setNodeOperatorStakingLimit(0, 100000, { from: voting, gasPrice: 10 }) await anotherCurated.setNodeOperatorStakingLimit(0, 100000, { from: voting, gasPrice: 10 }) - // balance are 0 - assert.equals(await web3.eth.getBalance(lido.address), 0) + // balance are initial + assert.equals(await web3.eth.getBalance(lido.address), ETH(1)) assert.equals(await web3.eth.getBalance(stakingRouter.address), 0) await web3.eth.sendTransaction({ value: sendEthForKeys, to: lido.address, from: stranger1 }) - assert.equals(await lido.getBufferedEther(), sendEthForKeys) + assert.equals(await lido.getBufferedEther(), ETH(200 * 32 + 1)) const keysAllocation = await stakingRouter.getDepositsAllocation(200) @@ -87,10 +87,10 @@ contract('StakingRouter', ([depositor, stranger1, dsm, address1, address2]) => { assert.equals(await depositContract.totalCalls(), 100, 'invalid deposits count') // on deposit we return balance to Lido - assert.equals(await web3.eth.getBalance(lido.address), ETH(100 * 32), 'invalid lido balance') + assert.equals(await web3.eth.getBalance(lido.address), ETH(100 * 32 + 1), 'invalid lido balance') assert.equals(await web3.eth.getBalance(stakingRouter.address), 0, 'invalid staking_router balance') - assert.equals(await lido.getBufferedEther(), ETH(100 * 32), 'invalid total buffer') + assert.equals(await lido.getBufferedEther(), ETH(100 * 32 + 1), 'invalid total buffer') }) }) }) From f12d7852fcaf02d0f788cc9a47623dd6c731fb64 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 17:05:49 +0200 Subject: [PATCH 017/199] test: fix node-operators-registry test --- test/0.4.24/node-operators-registry.test.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index c4d8cc89d..180bb9ad0 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -9,9 +9,7 @@ const nodeOperators = require('../helpers/node-operators') const signingKeys = require('../helpers/signing-keys') const { web3, artifacts } = require('hardhat') const { getRandomLocatorConfig } = require('../helpers/locator') -const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') -const IStakingModule = artifacts.require('contracts/0.8.9/interfaces/IStakingModule.sol:IStakingModule') const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistryMock') const SigningKeys = artifacts.require('SigningKeys') const LidoLocator = artifacts.require('LidoLocator') @@ -85,7 +83,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob before('deploy base app', async () => { // Deploy the app's base contract. appBase = await NodeOperatorsRegistry.new() - steth = await StETH.new() + steth = await StETH.new({ value: ETH(1) }) const locatorConfig = getRandomLocatorConfig({ lido: steth.address }) @@ -2885,8 +2883,8 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals( totalSigningKeys, NODE_OPERATORS[secondNodeOperatorId].totalSigningKeysCount - - (NODE_OPERATORS[secondNodeOperatorId].vettedSigningKeysCount - - NODE_OPERATORS[secondNodeOperatorId].depositedSigningKeysCount) + (NODE_OPERATORS[secondNodeOperatorId].vettedSigningKeysCount - + NODE_OPERATORS[secondNodeOperatorId].depositedSigningKeysCount) ) assert.equals(stakingLimit, NODE_OPERATORS[secondNodeOperatorId].depositedSigningKeysCount) From f12b385f5add3f13fe66e524488066e27260a4bb Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 17:18:25 +0200 Subject: [PATCH 018/199] test: fix deposit test --- test/deposit.test.js | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/test/deposit.test.js b/test/deposit.test.js index c5bbbc078..9b3ee9c0d 100644 --- a/test/deposit.test.js +++ b/test/deposit.test.js @@ -53,7 +53,7 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d }, depositContractFactory: depositContractFactory, postSetup: async ({ pool, lidoLocator, eip712StETH, withdrawalQueue, appManager, voting }) => { - await pool.initialize(lidoLocator.address, eip712StETH.address) + await pool.initialize(lidoLocator.address, eip712StETH.address, { value: ETH(1) }) await withdrawalQueue.updateBunkerMode(false, 0, { from: appManager.address }) await pool.resumeProtocolAndStaking({ from: voting.address }) } @@ -102,31 +102,31 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 0, beaconBalance: 0 }) - assertBn(await app.getTotalPooledEther(), ETH(1)) - assertBn(await app.getBufferedEther(), ETH(1)) + assertBn(await app.getTotalPooledEther(), ETH(2)) + assertBn(await app.getBufferedEther(), ETH(2)) assertBn(await token.balanceOf(user1), tokens(1)) - assertBn(await token.totalSupply(), tokens(1)) + assertBn(await token.totalSupply(), tokens(2)) // +2 ETH await app.submit(ZERO_ADDRESS, { from: user2, value: ETH(2) }) // another form of a deposit call await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 0, beaconBalance: 0 }) assertBn(bn(await depositContract.get_deposit_count()), 0) - assertBn(await app.getTotalPooledEther(), ETH(3)) - assertBn(await app.getBufferedEther(), ETH(3)) + assertBn(await app.getTotalPooledEther(), ETH(4)) + assertBn(await app.getBufferedEther(), ETH(4)) assertBn(await token.balanceOf(user2), tokens(2)) - assertBn(await token.totalSupply(), tokens(3)) + assertBn(await token.totalSupply(), tokens(4)) // +30 ETH await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(30) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 1, beaconBalance: 0 }) - assertBn(await app.getTotalPooledEther(), ETH(33)) - assertBn(await app.getBufferedEther(), ETH(1)) + assertBn(await app.getTotalPooledEther(), ETH(34)) + assertBn(await app.getBufferedEther(), ETH(2)) assertBn(await token.balanceOf(user1), tokens(1)) assertBn(await token.balanceOf(user2), tokens(2)) assertBn(await token.balanceOf(user3), tokens(30)) - assertBn(await token.totalSupply(), tokens(33)) + assertBn(await token.totalSupply(), tokens(34)) assertBn(bn(changeEndianness(await depositContract.get_deposit_count())), 1) @@ -135,12 +135,12 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 4, beaconBalance: 0 }) - assertBn(await app.getTotalPooledEther(), ETH(133)) - assertBn(await app.getBufferedEther(), ETH(5)) + assertBn(await app.getTotalPooledEther(), ETH(134)) + assertBn(await app.getBufferedEther(), ETH(6)) assertBn(await token.balanceOf(user1), tokens(101)) assertBn(await token.balanceOf(user2), tokens(2)) assertBn(await token.balanceOf(user3), tokens(30)) - assertBn(await token.totalSupply(), tokens(133)) + assertBn(await token.totalSupply(), tokens(134)) assertBn(bn(changeEndianness(await depositContract.get_deposit_count())), 4) }) @@ -170,7 +170,7 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d await operators.setNodeOperatorStakingLimit(0, UNLIMITED, { from: voting }) await operators.setNodeOperatorStakingLimit(1, UNLIMITED, { from: voting }) - await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(33) }) + await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(32) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) assertBn(bn(changeEndianness(await depositContract.get_deposit_count())), 1) @@ -217,7 +217,7 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d await nodeOperators.addNodeOperator(operators, { name: 'short on keys', rewardAddress: ADDRESS_4 }, { from: voting }) // Deposit huge chunk - await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(32 * 3 + 50) }) + await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(32 * 3 + 50 - 1/* initial */) }) tx = await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) // assertEvent(tx, 'StakingRouterTransferReceived') @@ -353,7 +353,7 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d for (let i = 0; i < 14; i++) await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(10) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) - await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(6) }) + await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(5) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 3, beaconBalance: 0 }) @@ -479,7 +479,7 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d await operators.setNodeOperatorStakingLimit(3, UNLIMITED, { from: voting }) // #1 and #0 get the funds - await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(64) }) + await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(63) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 2, beaconBalance: 0 }) @@ -537,7 +537,7 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d await operators.setNodeOperatorStakingLimit(0, UNLIMITED, { from: voting }) await operators.setNodeOperatorStakingLimit(1, UNLIMITED, { from: voting }) - await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(amountToDeposit) }) + await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(amountToDeposit - 1) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor, gas: 20000000 }) @@ -571,7 +571,7 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d // Fix deposit tx price await web3.eth.sendTransaction({ to: user1, from: user2, value: ETH(2000) }) - await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(amountToDeposit) }) + await web3.eth.sendTransaction({ to: app.address, from: user1, value: ETH(amountToDeposit - 1 /* initial */) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor, gas: 20000000 }) From cced043b6e5c0eeaf82473ee11811c74fe34b2ad Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 17:20:24 +0200 Subject: [PATCH 019/199] test: fix lido_deposit_iteration_limit --- test/scenario/lido_deposit_iteration_limit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/scenario/lido_deposit_iteration_limit.js b/test/scenario/lido_deposit_iteration_limit.js index 26ce0a09e..78dee023e 100644 --- a/test/scenario/lido_deposit_iteration_limit.js +++ b/test/scenario/lido_deposit_iteration_limit.js @@ -83,7 +83,7 @@ contract('Lido: deposit loop iteration limit', ([user1, nobody, nodeOperator]) = it('a user submits 25 * 32 ETH', async () => { const depositAmount = 25 * 32 const referral = ZERO_ADDRESS - await pool.submit(referral, { from: user1, value: ETH(depositAmount) }) + await pool.submit(referral, { from: user1, value: ETH(depositAmount - 1) }) assertBn(await pool.getTotalPooledEther(), ETH(depositAmount), 'total controlled ether') // at this point, no deposit assignments were made and all ether is buffered From b985e6442d5e0b3a8495ef35f20a3f86091f8f80 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 17:25:27 +0200 Subject: [PATCH 020/199] test: fix lido_happy_path --- test/scenario/lido_happy_path.js | 38 +++++++++----------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/test/scenario/lido_happy_path.js b/test/scenario/lido_happy_path.js index e112cd687..1eaac7d52 100644 --- a/test/scenario/lido_happy_path.js +++ b/test/scenario/lido_happy_path.js @@ -9,29 +9,12 @@ const { DSMAttestMessage, DSMPauseMessage } = require('../helpers/signatures') const { waitBlocks } = require('../helpers/blockchain') const { deployProtocol } = require('../helpers/protocol') const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') -const { gwei, ZERO_HASH } = require('../helpers/utils') const { pushOracleReport } = require('../helpers/oracle') +const { INITIAL_HOLDER } = require('../0.4.24/helpers/constants') const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistry') const CURATED_MODULE_ID = 1 -const makeAccountingReport = ({refSlot, numValidators, clBalanceGwei}) => ({ - refSlot, - consensusVersion: 1, - numValidators: numValidators, - clBalanceGwei: clBalanceGwei, - stakingModuleIdsWithNewlyExitedValidators: [], - numExitedValidatorsByStakingModule: [], - withdrawalVaultBalance: 0, - elRewardsVaultBalance: 0, - lastWithdrawalRequestIdToFinalize: 0, - finalizationShareRate: 0, - isBunkerMode: false, - extraDataFormat: 0, - extraDataHash: ZERO_HASH, - extraDataItemsCount: 0, -}) - contract('Lido: happy path', (addresses) => { const [ // node operators @@ -177,7 +160,7 @@ contract('Lido: happy path', (addresses) => { }) it('the first user deposits 3 ETH to the pool', async () => { - await web3.eth.sendTransaction({ to: pool.address, from: user1, value: ETH(3) }) + await web3.eth.sendTransaction({ to: pool.address, from: user1, value: ETH(2) }) const block = await web3.eth.getBlock('latest') const keysOpIndex = await nodeOperatorsRegistry.getKeysOpIndex() @@ -214,7 +197,7 @@ contract('Lido: happy path', (addresses) => { // The amount of tokens corresponding to the deposited ETH value was minted to the user - assertBn(await token.balanceOf(user1), tokens(3), 'user1 tokens') + assertBn(await token.balanceOf(user1), tokens(2), 'user1 tokens') assertBn(await token.totalSupply(), tokens(3), 'token total supply') }) @@ -264,7 +247,7 @@ contract('Lido: happy path', (addresses) => { // The amount of tokens corresponding to the deposited ETH value was minted to the users - assertBn(await token.balanceOf(user1), tokens(3), 'user1 tokens') + assertBn(await token.balanceOf(user1), tokens(2), 'user1 tokens') assertBn(await token.balanceOf(user2), tokens(30), 'user2 tokens') assertBn(await token.totalSupply(), tokens(3 + 30), 'token total supply') @@ -370,7 +353,7 @@ contract('Lido: happy path', (addresses) => { // The amount of tokens corresponding to the deposited ETH value was minted to the users - assertBn(await token.balanceOf(user1), tokens(3), 'user1 tokens') + assertBn(await token.balanceOf(user1), tokens(2), 'user1 tokens') assertBn(await token.balanceOf(user2), tokens(30), 'user2 tokens') assertBn(await token.balanceOf(user3), tokens(64), 'user3 tokens') @@ -422,18 +405,19 @@ contract('Lido: happy path', (addresses) => { // Token user balances increased - assertBn(await token.balanceOf(user1), new BN('3008907216494845360'), 'user1 tokens') - assertBn(await token.balanceOf(user2), new BN('30089072164948453608'), 'user2 tokens') - assertBn(await token.balanceOf(user3), new BN('64190020618556701031'), 'user3 tokens') + assertBn(await token.balanceOf(INITIAL_HOLDER), '1002969072164948453', 'initial holder tokens') + assertBn(await token.balanceOf(user1), '2005938144329896907', 'user1 tokens') + assertBn(await token.balanceOf(user2), '30089072164948453608', 'user2 tokens') + assertBn(await token.balanceOf(user3), '64190020618556701031', 'user3 tokens') // Fee, in the form of minted tokens, was distributed between treasury, insurance fund // and node operators // treasuryTokenBalance ~= mintedAmount * treasuryFeePoints / 10000 // insuranceTokenBalance ~= mintedAmount * insuranceFeePoints / 10000 - assert.equalsDelta(await token.balanceOf(treasuryAddr), new BN('16000000000000000'), 1, 'treasury tokens') + assert.equalsDelta(await token.balanceOf(treasuryAddr), '16000000000000000', 1, 'treasury tokens') assert.equalsDelta( await token.balanceOf(nodeOperatorsRegistry.address), - new BN('16000000000000000'), + '16000000000000000', 1, 'insurance tokens' ) From 5e0eff27fc9fe1eb9d8deeec5e16b7b20034d9c5 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Tue, 14 Feb 2023 23:10:45 +0700 Subject: [PATCH 021/199] test: AccountingOracle.submitReportExtraDataList enforces the deadline --- ...ng-oracle-submit-report-extra-data.test.js | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index a20a347af..c89b8460e 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -56,7 +56,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra await consensus.addMember(member1, 1, { from: admin }) } - async function prepareNextReport({ extraData: extraDataArg = {}, reportFields: reportFieldsArg = {} }) { + async function prepareNextReport({ extraData: extraDataArg, reportFields: reportFieldsArg = {} } = {}) { const extraData = extraDataArg || getDefaultExtraData() const extraDataItems = encodeExtraDataItems(extraData) @@ -89,7 +89,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra } } - async function prepareNextReportInNextFrame({ extraData = {}, reportFields = {} }) { + async function prepareNextReportInNextFrame({ extraData, reportFields = {} } = {}) { const { refSlot } = await consensus.getCurrentFrame() const next = await prepareNextReport({ extraData, @@ -114,6 +114,23 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra context('submitReportExtraDataList', () => { beforeEach(deploy) + context('enforces the deadline', () => { + it('reverts with ProcessingDeadlineMissed if deadline missed', async () => { + const { extraDataList, deadline } = await prepareNextReportInNextFrame() + await consensus.advanceTimeToNextFrameStart() + await assert.revertsWithCustomError( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `ProcessingDeadlineMissed(${+deadline})` + ) + }) + + it('pass successsfully if time is equals exactly to deadline value', async () => { + const { extraDataList, deadline } = await prepareNextReportInNextFrame() + await consensus.setTime(deadline) + await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + }) + }) + context('enforces module ids sorting order', () => { beforeEach(deploy) From 5ead926b25ff0dad4ab2a8d67bdcef1cca1c286c Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Tue, 14 Feb 2023 23:26:36 +0700 Subject: [PATCH 022/199] test: AccountingOracle.submitReportExtraDataList checks extra data hash --- ...ng-oracle-submit-report-extra-data.test.js | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index c89b8460e..fc14eff44 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -118,19 +118,39 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra it('reverts with ProcessingDeadlineMissed if deadline missed', async () => { const { extraDataList, deadline } = await prepareNextReportInNextFrame() await consensus.advanceTimeToNextFrameStart() - await assert.revertsWithCustomError( + await assert.reverts( oracle.submitReportExtraDataList(extraDataList, { from: member1 }), `ProcessingDeadlineMissed(${+deadline})` ) }) - it('pass successsfully if time is equals exactly to deadline value', async () => { + it('pass successfully if time is equals exactly to deadline value', async () => { const { extraDataList, deadline } = await prepareNextReportInNextFrame() await consensus.setTime(deadline) await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) }) }) + context('checks extra data hash', () => { + it('reverts with UnexpectedDataHash if hash did not match', async () => { + const { extraDataHash } = await prepareNextReportInNextFrame() + const incorrectExtraData = getDefaultExtraData() + ++incorrectExtraData.stuckKeys[0].nodeOpIds[0] + const incorrectExtraDataItems = encodeExtraDataItems(incorrectExtraData) + const incorrectExtraDataList = packExtraDataList(incorrectExtraDataItems) + const incorrectExtraDataHash = calcExtraDataListHash(incorrectExtraDataList) + await assert.reverts( + oracle.submitReportExtraDataList(incorrectExtraDataList, { from: member1 }), + `UnexpectedDataHash("${extraDataHash}", "${incorrectExtraDataHash}")` + ) + }) + + it('pass successfully if data hash matches', async () => { + const { extraDataList } = await prepareNextReportInNextFrame() + await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + }) + }) + context('enforces module ids sorting order', () => { beforeEach(deploy) From 74f54044fe0332225b7fd248fabb06f43bf5f2a5 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 18:41:42 +0200 Subject: [PATCH 023/199] test: minor fixes for lido test --- test/0.4.24/helpers/constants.js | 2 +- test/0.4.24/lido.test.js | 8 +++----- test/helpers/constants.js | 5 ++++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/test/0.4.24/helpers/constants.js b/test/0.4.24/helpers/constants.js index 2e92dbe51..4d33269a4 100644 --- a/test/0.4.24/helpers/constants.js +++ b/test/0.4.24/helpers/constants.js @@ -16,5 +16,5 @@ const ACCOUNTS_AND_KEYS = [ module.exports = { ZERO_ADDRESS, MAX_UINT256, - ACCOUNTS_AND_KEYS + ACCOUNTS_AND_KEYS, } diff --git a/test/0.4.24/lido.test.js b/test/0.4.24/lido.test.js index 6f3c5710a..5b60d2ae1 100644 --- a/test/0.4.24/lido.test.js +++ b/test/0.4.24/lido.test.js @@ -16,7 +16,7 @@ const nodeOperators = require('../helpers/node-operators') const { deployProtocol } = require('../helpers/protocol') const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') const { pushOracleReport } = require('../helpers/oracle') -const { SECONDS_PER_FRAME, MAX_UINT256 } = require('../helpers/constants') +const { SECONDS_PER_FRAME, INITIAL_HOLDER, MAX_UINT256 } = require('../helpers/constants') const { oracleReportSanityCheckerStubFactory } = require('../helpers/factories') const { newApp } = require('../helpers/dao') @@ -33,8 +33,6 @@ const ADDRESS_2 = '0x0000000000000000000000000000000000000002' const ADDRESS_3 = '0x0000000000000000000000000000000000000003' const ADDRESS_4 = '0x0000000000000000000000000000000000000004' -const INITIAL_HOLDER = '0x000000000000000000000000000000000000dead' - const UNLIMITED = 1000000000 const TOTAL_BASIS_POINTS = 10000 @@ -767,7 +765,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody let receipt - await verifyStakeLimitState(0, 0, MAX_UINT256, false, false) + await verifyStakeLimitState(0, 0, bn(MAX_UINT256), false, false) receipt = await app.submit(ZERO_ADDRESS, { from: user2, value: ETH(2) }) assertEvent(receipt, 'Submitted', { expectedArgs: { sender: user2, amount: ETH(2), referral: ZERO_ADDRESS } }) @@ -782,7 +780,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await assertRevert(app.resumeStaking(), 'APP_AUTH_FAILED') receipt = await app.resumeStaking({ from: voting }) assertEvent(receipt, 'StakingResumed') - await verifyStakeLimitState(0, 0, MAX_UINT256, false, false) + await verifyStakeLimitState(0, 0, bn(MAX_UINT256), false, false) await web3.eth.sendTransaction({ to: app.address, from: user2, value: ETH(1.1) }) receipt = await app.submit(ZERO_ADDRESS, { from: user2, value: ETH(1.4) }) diff --git a/test/helpers/constants.js b/test/helpers/constants.js index d15d0d603..fcddbf468 100644 --- a/test/helpers/constants.js +++ b/test/helpers/constants.js @@ -1,4 +1,5 @@ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' +const INITIAL_HOLDER = '0x000000000000000000000000000000000000dead' const ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000' const MAX_UINT256 = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' @@ -12,6 +13,7 @@ const SECONDS_PER_EPOCH = SLOTS_PER_EPOCH * SECONDS_PER_SLOT const SECONDS_PER_FRAME = SECONDS_PER_EPOCH * EPOCHS_PER_FRAME const SLOTS_PER_FRAME = EPOCHS_PER_FRAME * SLOTS_PER_EPOCH + module.exports = { ZERO_ADDRESS, ZERO_BYTES32, @@ -22,5 +24,6 @@ module.exports = { SECONDS_PER_EPOCH, SECONDS_PER_FRAME, SLOTS_PER_FRAME, - CONSENSUS_VERSION + CONSENSUS_VERSION, + INITIAL_HOLDER, } From faae58ad24ee3e7ea7df240f17d6b056a978d7ae Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Tue, 14 Feb 2023 23:48:27 +0700 Subject: [PATCH 024/199] test: AccountingOracle.submitReportExtraDataList check successes by events --- .../accounting-oracle-submit-report-extra-data.test.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index fc14eff44..014c045dc 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -125,9 +125,10 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) it('pass successfully if time is equals exactly to deadline value', async () => { - const { extraDataList, deadline } = await prepareNextReportInNextFrame() + const { extraDataList, deadline, reportFields } = await prepareNextReportInNextFrame() await consensus.setTime(deadline) - await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + const tx = await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) }) }) @@ -146,8 +147,9 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) it('pass successfully if data hash matches', async () => { - const { extraDataList } = await prepareNextReportInNextFrame() - await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + const { extraDataList, reportFields } = await prepareNextReportInNextFrame() + const tx = await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) }) }) From 39842a418fcb72025866437c6abeb38799f718f2 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 19:20:32 +0200 Subject: [PATCH 025/199] test: fix nor-penalty test --- .../node-operators-registry-penalty.test.js | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/test/0.4.24/node-operators-registry-penalty.test.js b/test/0.4.24/node-operators-registry-penalty.test.js index cfb05752b..8d97246c9 100644 --- a/test/0.4.24/node-operators-registry-penalty.test.js +++ b/test/0.4.24/node-operators-registry-penalty.test.js @@ -1,7 +1,7 @@ const hre = require('hardhat') const { assert } = require('../helpers/assert') const { assertRevert } = require('../helpers/assertThrow') -const { toBN, padRight, printEvents } = require('../helpers/utils') +const { padRight, ETH } = require('../helpers/utils') const { BN } = require('bn.js') const { AragonDAO } = require('./helpers/dao') const { EvmSnapshot } = require('../helpers/blockchain') @@ -9,7 +9,6 @@ const { ZERO_ADDRESS, getEventAt, bn } = require('@aragon/contract-helpers-test' const nodeOperators = require('../helpers/node-operators') const signingKeys = require('../helpers/signing-keys') const { web3 } = require('hardhat') -const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') const { getRandomLocatorConfig } = require('../helpers/locator') const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistryMock') @@ -66,22 +65,6 @@ const NODE_OPERATORS = [ // bytes32 0x63757261746564 const CURATED_TYPE = padRight(web3.utils.fromAscii('curated'), 32) - -const pad = (hex, bytesLength) => { - const absentZeroes = bytesLength * 2 + 2 - hex.length - if (absentZeroes > 0) hex = '0x' + '0'.repeat(absentZeroes) + hex.substr(2) - return hex -} - -const hexConcat = (first, ...rest) => { - let result = first.startsWith('0x') ? first : '0x' + first - rest.forEach((item) => { - result += item.startsWith('0x') ? item.substr(2) : item - }) - return result -} - -const ETH = (value) => web3.utils.toWei(value + '', 'ether') const StETH = artifacts.require('StETHMock') contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, user4, no1, treasury]) => { @@ -91,7 +74,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use before('deploy base app', async () => { // Deploy the app's base contract. appBase = await NodeOperatorsRegistry.new() - steth = await StETH.new() + steth = await StETH.new({ value: ETH(1) }) burner = await Burner.new( voting, treasury, steth.address, bn(0), bn(0), { from: appManager } From 0e8c1ada9c9ee81d29100e1df45e7cb336d45992 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 19:21:37 +0200 Subject: [PATCH 026/199] test: fix happy path --- test/scenario/lido_happy_path.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/scenario/lido_happy_path.js b/test/scenario/lido_happy_path.js index 1eaac7d52..8b844aecd 100644 --- a/test/scenario/lido_happy_path.js +++ b/test/scenario/lido_happy_path.js @@ -10,7 +10,7 @@ const { waitBlocks } = require('../helpers/blockchain') const { deployProtocol } = require('../helpers/protocol') const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') const { pushOracleReport } = require('../helpers/oracle') -const { INITIAL_HOLDER } = require('../0.4.24/helpers/constants') +const { INITIAL_HOLDER } = require('../helpers/constants') const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistry') const CURATED_MODULE_ID = 1 From 28a548c6e8d73fd423149a9cf533805b2ea5a16e Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 19:34:23 +0200 Subject: [PATCH 027/199] test: fix withdrawal-queue test --- test/0.8.9/withdrawal-queue.test.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/test/0.8.9/withdrawal-queue.test.js b/test/0.8.9/withdrawal-queue.test.js index 377f65df4..bb859d0f4 100644 --- a/test/0.8.9/withdrawal-queue.test.js +++ b/test/0.8.9/withdrawal-queue.test.js @@ -2,7 +2,7 @@ const hre = require('hardhat') const { artifacts, contract, ethers } = require('hardhat') const { bn, getEventArgument, ZERO_ADDRESS } = require('@aragon/contract-helpers-test') -const { ETH, StETH, shareRate, shares } = require('../helpers/utils') +const { ETH, StETH, shareRate, shares, setBalance } = require('../helpers/utils') const { assert } = require('../helpers/assert') const withdrawals = require('../helpers/withdrawals') const { signPermit, makeDomainSeparator } = require('../0.6.12/helpers/permit_helpers') @@ -18,7 +18,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { const snapshot = new EvmSnapshot(ethers.provider) before('Deploy', async () => { - steth = await StETHMock.new({ value: ETH(601) }) + steth = await StETHMock.new({ value: ETH(1) }) wsteth = await WstETH.new(steth.address) withdrawalQueue = (await withdrawals.deploy(daoAgent, wsteth.address)).queue @@ -26,11 +26,13 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { await withdrawalQueue.initialize(daoAgent, daoAgent, daoAgent, steth.address, steth.address) await withdrawalQueue.resume({ from: daoAgent }) - await steth.setTotalPooledEther(ETH(300)) + await steth.setTotalPooledEther(ETH(600)) + await setBalance(steth.address, ETH(600)) await steth.mintShares(user, shares(1)) await steth.approve(withdrawalQueue.address, StETH(300), { from: user }) impersonate(ethers.provider, steth.address) + snapshot.make(); }) @@ -125,7 +127,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { it('One can request MAX', async () => { const max = await withdrawalQueue.MAX_STETH_WITHDRAWAL_AMOUNT() - await steth.setTotalPooledEther(max) + await steth.setTotalPooledEther(max.muln(2)) await steth.approve(withdrawalQueue.address, max, { from: user }) const receipt = await withdrawalQueue.requestWithdrawals([max], owner, { from: user }) @@ -195,7 +197,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) it('Same discounts is squashed into one', async () => { - await steth.setTotalPooledEther(ETH(600)) + await steth.setTotalPooledEther(ETH(900)) await steth.mintShares(user, shares(1)) await steth.approve(withdrawalQueue.address, StETH(300), { from: user }) @@ -209,7 +211,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) it('One can finalize a batch of requests at once', async () => { - await steth.setTotalPooledEther(ETH(600)) + await steth.setTotalPooledEther(ETH(900)) await steth.mintShares(user, shares(1)) await steth.approve(withdrawalQueue.address, StETH(300), { from: user }) @@ -225,7 +227,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) it('One can finalize part of the queue', async () => { - await steth.setTotalPooledEther(ETH(600)) + await steth.setTotalPooledEther(ETH(900)) await steth.mintShares(user, shares(1)) await steth.approve(withdrawalQueue.address, StETH(600), { from: user }) @@ -281,7 +283,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) it('Cant claim request with a wrong hint', async () => { - await steth.setTotalPooledEther(ETH(600)) + await steth.setTotalPooledEther(ETH(900)) await steth.mintShares(user, shares(1)) await steth.approve(withdrawalQueue.address, StETH(600), { from: user }) @@ -314,7 +316,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) it('One can claim a lot of withdrawals with different discounts', async () => { - await steth.setTotalPooledEther(ETH(21)) + await steth.setTotalPooledEther(ETH(22)) await steth.mintShares(user, shares(21)) await steth.approve(withdrawalQueue.address, StETH(21), { from: user }) @@ -771,12 +773,12 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) it("One can't change someone else's request", async () => { - await assert.reverts(withdrawalQueue.transferFrom(user, owner, requestId, { from: stranger }), + await assert.reverts(withdrawalQueue.transferFrom(user, owner, requestId, { from: stranger }), `NotOwnerOrApproved("${stranger}")`) }) it("One can't pass zero owner", async () => { - await assert.reverts(withdrawalQueue.transferFrom(user, ZERO_ADDRESS, requestId, { from: user }), + await assert.reverts(withdrawalQueue.transferFrom(user, ZERO_ADDRESS, requestId, { from: user }), 'TransferToZeroAddress()') }) From 1d61164804067698a3b321007b567299cec96e5f Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 19:38:24 +0200 Subject: [PATCH 028/199] test: fix withdrawal-request-nft test --- test/0.8.9/withdrawal-request-nft.test.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/0.8.9/withdrawal-request-nft.test.js b/test/0.8.9/withdrawal-request-nft.test.js index 1dd851933..0a6e412f4 100644 --- a/test/0.8.9/withdrawal-request-nft.test.js +++ b/test/0.8.9/withdrawal-request-nft.test.js @@ -1,7 +1,7 @@ const hre = require('hardhat') const { assert } = require('../helpers/assert') const { EvmSnapshot } = require('../helpers/blockchain') -const { shares, ETH, shareRate } = require('../helpers/utils') +const { shares, ETH, shareRate, setBalance } = require('../helpers/utils') const withdrawals = require('../helpers/withdrawals') const StETH = hre.artifacts.require('StETHMock') @@ -16,7 +16,9 @@ hre.contract( const snapshot = new EvmSnapshot(hre.ethers.provider) before(async () => { - stETH = await StETH.new({ value: ETH(100), from: deployer }) + stETH = await StETH.new({ value: ETH(1), from: deployer }) + await setBalance(stETH.address, ETH(100)) + wstETH = await WstETH.new(stETH.address, { from: deployer }) erc721ReceiverMock = await ERC721ReceiverMock.new({ from: deployer }) withdrawalRequestNFT = (await withdrawals.deploy(deployer, wstETH.address)).queue @@ -29,7 +31,7 @@ hre.contract( ) await withdrawalRequestNFT.resume({ from: deployer }) - await stETH.setTotalPooledEther(ETH(100)) + await stETH.setTotalPooledEther(ETH(101)) await stETH.mintShares(stEthHolder, shares(50)) await stETH.mintShares(wstETH.address, shares(50)) await wstETH.mint(wstEthHolder, ETH(25)) From 7aa6355b3276e5960cf5201060a97d8955949220 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Wed, 15 Feb 2023 00:47:03 +0700 Subject: [PATCH 029/199] test: AccountingOracle.submitReportExtraDataList checks ref slot --- ...ng-oracle-submit-report-extra-data.test.js | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 014c045dc..1a0b9e44e 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -9,8 +9,7 @@ const { packExtraDataList, calcExtraDataListHash, calcReportDataHash, - EXTRA_DATA_FORMAT_LIST, - SLOTS_PER_FRAME + EXTRA_DATA_FORMAT_LIST } = require('./accounting-oracle-deploy.test') const getDefaultExtraData = () => ({ @@ -56,7 +55,8 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra await consensus.addMember(member1, 1, { from: admin }) } - async function prepareNextReport({ extraData: extraDataArg, reportFields: reportFieldsArg = {} } = {}) { + // note: reportFieldsArg.refSlot is required to pass here + function getReportData({ extraData: extraDataArg, reportFields: reportFieldsArg } = {}) { const extraData = extraDataArg || getDefaultExtraData() const extraDataItems = encodeExtraDataItems(extraData) @@ -72,11 +72,6 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra const reportItems = getReportDataItems(reportFields) const reportHash = calcReportDataHash(reportItems) - await consensus.advanceTimeToNextFrameStart() - await consensus.submitReport(reportFields.refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) - const deadline = (await oracle.getConsensusReport()).processingDeadlineTime - await oracle.submitReportData(reportItems, oracleVersion, { from: member1 }) - return { extraData, extraDataItems, @@ -84,18 +79,32 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra extraDataHash, reportFields, reportItems, - reportHash, + reportHash + } + } + + async function prepareNextReport({ extraData, reportFields = {} } = {}) { + const data = getReportData({ extraData, reportFields }) + + await consensus.submitReport(data.reportFields.refSlot, data.reportHash, CONSENSUS_VERSION, { from: member1 }) + await oracle.submitReportData(data.reportItems, oracleVersion, { from: member1 }) + + const deadline = (await oracle.getConsensusReport()).processingDeadlineTime + + return { + ...data, deadline } } async function prepareNextReportInNextFrame({ extraData, reportFields = {} } = {}) { + await consensus.advanceTimeToNextFrameStart() const { refSlot } = await consensus.getCurrentFrame() const next = await prepareNextReport({ extraData, reportFields: { ...reportFields, - refSlot: +refSlot + SLOTS_PER_FRAME + refSlot } }) return next @@ -132,6 +141,29 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) }) + context('checks ref slot', () => { + it('reverts with CannotSubmitExtraDataBeforeMainData in attempt of try to pass extra data ahead of submitReportData', async () => { + const { refSlot } = await consensus.getCurrentFrame() + const { reportHash, extraDataList } = getReportData({ reportFields: { refSlot } }) + await consensus.submitReport(refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) + // No submitReportData here — trying to send extra data ahead of it + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `CannotSubmitExtraDataBeforeMainData()` + ) + }) + + it('pass successfully ', async () => { + const { refSlot } = await consensus.getCurrentFrame() + const { reportFields, reportItems, reportHash, extraDataList } = getReportData({ reportFields: { refSlot } }) + await consensus.submitReport(refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) + // Now submitReportData on it's place + await oracle.submitReportData(reportItems, oracleVersion, { from: member1 }) + const tx = await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) + }) + }) + context('checks extra data hash', () => { it('reverts with UnexpectedDataHash if hash did not match', async () => { const { extraDataHash } = await prepareNextReportInNextFrame() From 3af9c5b9457573db7a83ae96369a2e6c4d03ba84 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Wed, 15 Feb 2023 00:49:30 +0700 Subject: [PATCH 030/199] test: description fix --- test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js index ea0c5851a..8446c4196 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js @@ -253,7 +253,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra ) }) - it('should revert if incorrect stakingModuleIdsWithNewlyExitedValidators order (when next number in list is less than previous)', async () => { + it('should revert if incorrect stakingModuleIdsWithNewlyExitedValidators order (when next number in list equals to previous)', async () => { const { newReportItems } = await prepareNextReportInNextFrame({ ...reportFields, stakingModuleIdsWithNewlyExitedValidators: [1, 1], From 5f20bb91c913091a530c5df158669d3382e884e2 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 14 Feb 2023 20:31:41 +0200 Subject: [PATCH 031/199] test: fix steth test --- test/0.4.24/steth.test.js | 171 ++++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 83 deletions(-) diff --git a/test/0.4.24/steth.test.js b/test/0.4.24/steth.test.js index 9dd12219a..2dbe6fd34 100644 --- a/test/0.4.24/steth.test.js +++ b/test/0.4.24/steth.test.js @@ -2,16 +2,25 @@ const { assert } = require('chai') const { assertBn, assertEvent, assertAmountOfEvents } = require('@aragon/contract-helpers-test/src/asserts') const { assertRevert } = require('../helpers/assertThrow') const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') +const { tokens, ETH } = require('./../helpers/utils') +const { EvmSnapshot } = require('../helpers/blockchain') +const { INITIAL_HOLDER } = require('../helpers/constants') -const StETH = artifacts.require('StETHMock') - -const tokens = (value) => web3.utils.toWei(value + '', 'ether') +const StETHMock = artifacts.require('StETHMock') contract('StETH', ([_, __, user1, user2, user3, nobody]) => { let stEth + const snapshot = new EvmSnapshot(hre.ethers.provider) + + before('deploy mock token', async () => { + stEth = await StETHMock.new({ value: ETH(1) }) + await stEth.setTotalPooledEther(ETH(1)) - beforeEach('deploy mock token', async () => { - stEth = await StETH.new() + await snapshot.make() + }) + + afterEach(async () => { + await snapshot.rollback() }) context('ERC20 methods', () => { @@ -23,7 +32,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { context('zero supply', async () => { it('initial total supply is correct', async () => { - assertBn(await stEth.totalSupply(), tokens(0)) + assertBn(await stEth.totalSupply(), tokens(1)) }) it('initial balances are correct', async () => { @@ -51,16 +60,6 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { assertBn(await stEth.allowance(user1, user2), tokens(1)) }) - it(`transfers works with no pooled ehter, balances aren't changed`, async () => { - stEth.transfer(user1, tokens(1), { from: user2 }) - stEth.transfer(user2, tokens(100), { from: user3 }) - stEth.transfer(user3, tokens(1000), { from: user1 }) - - assertBn(await stEth.balanceOf(user1), tokens(0)) - assertBn(await stEth.balanceOf(user2), tokens(0)) - assertBn(await stEth.balanceOf(user3), tokens(0)) - }) - it(`balances aren't changed even if total pooled ether increased`, async () => { await stEth.setTotalPooledEther(tokens(100)) assertBn(await stEth.totalSupply(), tokens(100)) @@ -74,7 +73,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { context('with non-zero supply', async () => { beforeEach(async () => { await stEth.setTotalPooledEther(tokens(100)) - await stEth.mintShares(user1, tokens(100)) + await stEth.mintShares(user1, tokens(99)) }) it('total supply is correct', async () => { @@ -82,7 +81,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { }) it('balances are correct', async () => { - assertBn(await stEth.balanceOf(user1), tokens(100)) + assertBn(await stEth.balanceOf(user1), tokens(99)) assertBn(await stEth.balanceOf(user2), tokens(0)) assertBn(await stEth.balanceOf(user3), tokens(0)) }) @@ -106,7 +105,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: user2, value: amount } }) assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: user2, sharesValue: sharesAmount } }) assertBn(await stEth.balanceOf(user1), tokens(0)) - assertBn(await stEth.balanceOf(user2), tokens(100)) + assertBn(await stEth.balanceOf(user2), tokens(99)) }) it('transfer zero tokens works and emits event', async () => { @@ -117,7 +116,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { assertAmountOfEvents(receipt, 'TransferShares', { expectedAmount: 1 }) assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: user2, value: amount } }) assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: user2, sharesValue: sharesAmount } }) - assertBn(await stEth.balanceOf(user1), tokens(100)) + assertBn(await stEth.balanceOf(user1), tokens(99)) assertBn(await stEth.balanceOf(user2), tokens(0)) }) }) @@ -186,7 +185,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: user3, value: amount } }) assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: user3, sharesValue: sharesAmount } }) assertBn(await stEth.allowance(user2, user1), bn(0)) - assertBn(await stEth.balanceOf(user1), tokens(50)) + assertBn(await stEth.balanceOf(user1), tokens(49)) assertBn(await stEth.balanceOf(user3), tokens(50)) }) }) @@ -267,7 +266,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { context('with non-zero supply', async () => { beforeEach(async () => { await stEth.setTotalPooledEther(tokens(100)) - await stEth.mintShares(user1, tokens(100)) + await stEth.mintShares(user1, tokens(99)) // 1 ETH is initial hold }) it('stop/resume works', async () => { @@ -301,7 +300,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { assert.equal(await stEth.isStopped(), false) await stEth.transfer(user2, tokens(2), { from: user1 }) - assertBn(await stEth.balanceOf(user1), tokens(96)) + assertBn(await stEth.balanceOf(user1), tokens(95)) assertBn(await stEth.balanceOf(user2), tokens(4)) }) @@ -310,19 +309,19 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { await stEth.setTotalPooledEther(tokens(50)) - assertBn(await stEth.balanceOf(user1), tokens(50)) - assertBn(await stEth.sharesOf(user1), tokens(100)) + assertBn(await stEth.balanceOf(user1), tokens(49.5)) + assertBn(await stEth.sharesOf(user1), tokens(99)) assertBn(await stEth.allowance(user1, user2), tokens(75)) await assertRevert(stEth.transferFrom(user1, user2, tokens(75), { from: user2 })) await assertRevert(stEth.transferFrom(user1, user2, bn(tokens(50)).addn(10), { from: user2 })) - await stEth.transferFrom(user1, user2, tokens(50), { from: user2 }) + await stEth.transferFrom(user1, user2, tokens(49.5), { from: user2 }) assertBn(await stEth.balanceOf(user1), tokens(0)) assertBn(await stEth.sharesOf(user1), tokens(0)) - assertBn(await stEth.balanceOf(user2), tokens(50)) - assertBn(await stEth.sharesOf(user2), tokens(100)) + assertBn(await stEth.balanceOf(user2), tokens(49.5)) + assertBn(await stEth.sharesOf(user2), tokens(99)) }) context('mint', () => { @@ -332,20 +331,20 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { await stEth.setTotalPooledEther(tokens(112)) assertBn(await stEth.totalSupply(), tokens(112)) - assertBn(await stEth.balanceOf(user1), tokens(112)) + assertBn(await stEth.balanceOf(user1), tokens(111)) assertBn(await stEth.balanceOf(user2), tokens(0)) assertBn(await stEth.getTotalShares(), tokens(112)) - assertBn(await stEth.sharesOf(user1), tokens(112)) + assertBn(await stEth.sharesOf(user1), tokens(111)) assertBn(await stEth.sharesOf(user2), tokens(0)) await stEth.mintShares(user2, tokens(4)) await stEth.setTotalPooledEther(tokens(116)) assertBn(await stEth.totalSupply(), tokens(116)) - assertBn(await stEth.balanceOf(user1), tokens(112)) + assertBn(await stEth.balanceOf(user1), tokens(111)) assertBn(await stEth.balanceOf(user2), tokens(4)) assertBn(await stEth.getTotalShares(), tokens(116)) - assertBn(await stEth.sharesOf(user1), tokens(112)) + assertBn(await stEth.sharesOf(user1), tokens(111)) assertBn(await stEth.sharesOf(user2), tokens(4)) }) @@ -356,9 +355,9 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { context('burn', () => { beforeEach(async () => { - // user1 already had 100 tokens - // 100 + 100 + 100 = 300 - await stEth.setTotalPooledEther(tokens(300)) + // user1 already had 99 tokens + // 1 + 99 + 100 + 100 = 300 + await stEth.setTotalPooledEther(ETH(300)) await stEth.mintShares(user2, tokens(100)) await stEth.mintShares(user3, tokens(100)) }) @@ -383,11 +382,11 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { }) assertBn(await stEth.totalSupply(), tokens(300)) - assertBn(await stEth.balanceOf(user1), tokens(100)) + assertBn(await stEth.balanceOf(user1), tokens(99)) assertBn(await stEth.balanceOf(user2), tokens(100)) assertBn(await stEth.balanceOf(user3), tokens(100)) assertBn(await stEth.getTotalShares(), tokens(300)) - assertBn(await stEth.sharesOf(user1), tokens(100)) + assertBn(await stEth.sharesOf(user1), tokens(99)) assertBn(await stEth.sharesOf(user2), tokens(100)) assertBn(await stEth.sharesOf(user3), tokens(100)) }) @@ -395,19 +394,21 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { it('burning works (redistributes tokens)', async () => { const totalShares = await stEth.getTotalShares() const totalSupply = await stEth.totalSupply() - const user1Balance = await stEth.balanceOf(user1) - const user1Shares = await stEth.sharesOf(user1) + const user2Balance = await stEth.balanceOf(user2) + const user2Shares = await stEth.sharesOf(user2) const sharesToBurn = totalShares.sub( - totalSupply.mul(totalShares.sub(user1Shares)).div(totalSupply.sub(user1Balance).add(bn(tokens(10)))) + totalSupply + .mul(totalShares.sub(user2Shares)) + .div(totalSupply.sub(user2Balance).add(bn(tokens(10)))) ) const expectedPreTokenAmount = await stEth.getPooledEthByShares(sharesToBurn) - const receipt = await stEth.burnShares(user1, sharesToBurn) + const receipt = await stEth.burnShares(user2, sharesToBurn) const expectedPostTokenAmount = await stEth.getPooledEthByShares(sharesToBurn) assertEvent(receipt, 'SharesBurnt', { expectedArgs: { - account: user1, + account: user2, preRebaseTokenAmount: expectedPreTokenAmount, postRebaseTokenAmount: expectedPostTokenAmount, sharesAmount: sharesToBurn @@ -415,62 +416,64 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { }) assertBn(await stEth.totalSupply(), tokens(300)) - assertBn(await stEth.balanceOf(user1), bn(tokens(90)).subn(1)) // expected round error - assertBn(await stEth.balanceOf(user2), tokens(105)) + assertBn((await stEth.balanceOf(user1)).add(await stEth.balanceOf(INITIAL_HOLDER)), tokens(105)) + assertBn(await stEth.balanceOf(user2), bn(tokens(90)).subn(1)) // expected round error assertBn(await stEth.balanceOf(user3), tokens(105)) assertBn(await stEth.getTotalShares(), bn('285714285714285714285')) - assertBn(await stEth.sharesOf(user1), bn('85714285714285714285')) - assertBn(await stEth.sharesOf(user2), tokens(100)) + assertBn(await stEth.sharesOf(INITIAL_HOLDER), tokens(1)) + assertBn(await stEth.sharesOf(user1), tokens(99)) + assertBn(await stEth.sharesOf(user2), bn('85714285714285714285')) assertBn(await stEth.sharesOf(user3), tokens(100)) }) it('allowance behavior is correct after burning', async () => { - await stEth.approve(user2, tokens(75), { from: user1 }) + await stEth.approve(user3, tokens(75), { from: user2 }) const totalShares = await stEth.getTotalShares() const totalSupply = await stEth.totalSupply() - const user1Balance = await stEth.balanceOf(user1) - const user1Shares = await stEth.sharesOf(user1) + const user2Balance = await stEth.balanceOf(user2) + const user2Shares = await stEth.sharesOf(user2) const sharesToBurn = totalShares.sub( - totalSupply.mul(totalShares.sub(user1Shares)).div(totalSupply.sub(user1Balance).add(bn(tokens(50)))) + totalSupply.mul(totalShares.sub(user2Shares)) + .div(totalSupply.sub(user2Balance).add(bn(tokens(50)))) ) const expectedPreTokenAmount = await stEth.getPooledEthByShares(sharesToBurn) - const receipt = await stEth.burnShares(user1, sharesToBurn) + const receipt = await stEth.burnShares(user2, sharesToBurn) const expectedPostTokenAmount = await stEth.getPooledEthByShares(sharesToBurn) assertEvent(receipt, 'SharesBurnt', { expectedArgs: { - account: user1, + account: user2, preRebaseTokenAmount: expectedPreTokenAmount, postRebaseTokenAmount: expectedPostTokenAmount, sharesAmount: sharesToBurn } }) - assertBn(await stEth.balanceOf(user1), tokens(50)) + assertBn(await stEth.balanceOf(user2), tokens(50)) - assertBn(await stEth.allowance(user1, user2), tokens(75)) + assertBn(await stEth.allowance(user2, user3), tokens(75)) - await assertRevert(stEth.transferFrom(user1, user2, tokens(75), { from: user2 })) - await assertRevert(stEth.transferFrom(user1, user2, bn(tokens(50)).addn(10), { from: user2 })) - await stEth.transferFrom(user1, user2, tokens(50), { from: user2 }) + await assertRevert(stEth.transferFrom(user2, user3, tokens(75), { from: user3 })) + await assertRevert(stEth.transferFrom(user2, user3, bn(tokens(50)).addn(10), { from: user3 })) + await stEth.transferFrom(user2, user3, tokens(50), { from: user3 }) }) }) }) context('share-related getters and transfers', async () => { - context('with zero totalPooledEther (supply)', async () => { + context('with initial totalPooledEther (supply)', async () => { it('getTotalSupply', async () => { - assertBn(await stEth.totalSupply({ from: nobody }), tokens(0)) + assertBn(await stEth.totalSupply({ from: nobody }), tokens(1)) }) it('getTotalShares', async () => { - assertBn(await stEth.getTotalShares(), tokens(0)) + assertBn(await stEth.getTotalShares(), tokens(1)) }) it('getTotalPooledEther', async () => { - assertBn(await stEth.getTotalPooledEther(), tokens(0)) + assertBn(await stEth.getTotalPooledEther(), tokens(1)) }) it('sharesOf', async () => { @@ -479,8 +482,8 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { it('getPooledEthByShares', async () => { assertBn(await stEth.getPooledEthByShares(tokens(0)), tokens(0)) - assertBn(await stEth.getPooledEthByShares(tokens(1)), tokens(0)) - assertBn(await stEth.getPooledEthByShares(tokens(100)), tokens(0)) + assertBn(await stEth.getPooledEthByShares(tokens(1)), tokens(1)) + assertBn(await stEth.getPooledEthByShares(tokens(100)), tokens(100)) }) it('balanceOf', async () => { @@ -488,9 +491,9 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { }) it('getSharesByPooledEth', async () => { - assertBn(await stEth.getSharesByPooledEth(tokens(1)), tokens(0)) + assertBn(await stEth.getSharesByPooledEth(tokens(1)), tokens(1)) assertBn(await stEth.getSharesByPooledEth(tokens(0)), tokens(0)) - assertBn(await stEth.getSharesByPooledEth(tokens(100)), tokens(0)) + assertBn(await stEth.getSharesByPooledEth(tokens(100)), tokens(100)) }) it('transferShares', async () => { @@ -514,10 +517,10 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { }) }) - context('with non-zero totalPooledEther (supply)', async () => { + context('with additional totalPooledEther (supply)', async () => { beforeEach(async () => { await stEth.setTotalPooledEther(tokens(100)) - await stEth.mintShares(user1, tokens(100)) + await stEth.mintShares(user1, tokens(99)) }) it('getTotalSupply', async () => { @@ -533,7 +536,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { }) it('sharesOf', async () => { - assertBn(await stEth.sharesOf(user1), tokens(100)) + assertBn(await stEth.sharesOf(user1), tokens(99)) }) it('getPooledEthByShares', async () => { @@ -543,7 +546,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { }) it('balanceOf', async () => { - assertBn(await stEth.balanceOf(user1), tokens(100)) + assertBn(await stEth.balanceOf(user1), tokens(99)) assertBn(await stEth.balanceOf(user2), tokens(0)) }) @@ -554,7 +557,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { }) it('transferShares', async () => { - assertBn(await stEth.balanceOf(user1), tokens(100)) + assertBn(await stEth.balanceOf(user1), tokens(99)) assertBn(await stEth.balanceOf(nobody), tokens(0)) let receipt = await stEth.transferShares(nobody, tokens(0), { from: user1 }) @@ -563,7 +566,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: nobody, value: tokens(0) } }) assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: nobody, sharesValue: tokens(0) } }) - assertBn(await stEth.balanceOf(user1), tokens(100)) + assertBn(await stEth.balanceOf(user1), tokens(99)) assertBn(await stEth.balanceOf(nobody), tokens(0)) receipt = await stEth.transferShares(nobody, tokens(30), { from: user1 }) @@ -572,25 +575,27 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: nobody, value: tokens(30) } }) assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: nobody, sharesValue: tokens(30) } }) - assertBn(await stEth.balanceOf(user1), tokens(70)) + assertBn(await stEth.balanceOf(user1), tokens(69)) assertBn(await stEth.balanceOf(nobody), tokens(30)) await assertRevert(stEth.transferShares(nobody, tokens(75), { from: user1 }), 'TRANSFER_AMOUNT_EXCEEDS_BALANCE') await stEth.setTotalPooledEther(tokens(120)) - receipt = await stEth.transferShares(nobody, tokens(70), { from: user1 }) + const tokensToTransfer = tokens(120 * 69 / 100) + + receipt = await stEth.transferShares(nobody, tokens(69), { from: user1 }) assertAmountOfEvents(receipt, 'Transfer', { expectedAmount: 1 }) assertAmountOfEvents(receipt, 'TransferShares', { expectedAmount: 1 }) - assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: nobody, value: tokens(84) } }) - assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: nobody, sharesValue: tokens(70) } }) + assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: nobody, value: tokensToTransfer } }) + assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: nobody, sharesValue: tokens(69) } }) assertBn(await stEth.balanceOf(user1), tokens(0)) - assertBn(await stEth.balanceOf(nobody), tokens(120)) + assertBn(await stEth.balanceOf(nobody), '118800000000000000000') }) it('transferSharesFrom', async () => { - assertBn(await stEth.balanceOf(user1), tokens(100)) + assertBn(await stEth.balanceOf(user1), tokens(99)) assertBn(await stEth.balanceOf(nobody), tokens(0)) let receipt = await stEth.transferSharesFrom(user1, nobody, tokens(0), { from: user2 }) @@ -599,7 +604,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: nobody, value: tokens(0) } }) assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: nobody, sharesValue: tokens(0) } }) - assertBn(await stEth.balanceOf(user1), tokens(100)) + assertBn(await stEth.balanceOf(user1), tokens(99)) assertBn(await stEth.balanceOf(nobody), tokens(0)) await assertRevert( @@ -613,7 +618,7 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: nobody, value: tokens(30) } }) assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: nobody, sharesValue: tokens(30) } }) - assertBn(await stEth.balanceOf(user1), tokens(70)) + assertBn(await stEth.balanceOf(user1), tokens(69)) assertBn(await stEth.balanceOf(nobody), tokens(30)) await assertRevert(stEth.transferSharesFrom(user1, nobody, tokens(75), { from: user2 }), 'TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE') @@ -625,14 +630,14 @@ contract('StETH', ([_, __, user1, user2, user3, nobody]) => { await assertRevert(stEth.transferSharesFrom(user1, nobody, tokens(70), { from: user2 }), 'TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE') await stEth.approve(user2, tokens(84), { from: user1 }) - receipt = await stEth.transferSharesFrom(user1, nobody, tokens(70), { from: user2 }) + receipt = await stEth.transferSharesFrom(user1, nobody, tokens(69), { from: user2 }) assertAmountOfEvents(receipt, 'Transfer', { expectedAmount: 1 }) assertAmountOfEvents(receipt, 'TransferShares', { expectedAmount: 1 }) - assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: nobody, value: tokens(84) } }) - assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: nobody, sharesValue: tokens(70) } }) + assertEvent(receipt, 'Transfer', { expectedArgs: { from: user1, to: nobody, value: '82800000000000000000' } }) + assertEvent(receipt, 'TransferShares', { expectedArgs: { from: user1, to: nobody, sharesValue: tokens(69) } }) assertBn(await stEth.balanceOf(user1), tokens(0)) - assertBn(await stEth.balanceOf(nobody), tokens(120)) + assertBn(await stEth.balanceOf(nobody), '118800000000000000000') }) }) }) From 3db21843fd1f688c3eb9bece3c0b038da04316df Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Wed, 15 Feb 2023 02:22:15 +0700 Subject: [PATCH 032/199] test: AccountingOracle.submitReportExtraDataList delivers the data to staking router --- ...ng-oracle-submit-report-extra-data.test.js | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 1a0b9e44e..1dc435cd4 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -1,10 +1,11 @@ const { assert } = require('../../helpers/assert') -const { e9, e18, e27 } = require('../../helpers/utils') +const { e9, e18, e27, hex } = require('../../helpers/utils') const { CONSENSUS_VERSION, deployAndConfigureAccountingOracle, getReportDataItems, + encodeExtraDataItem, encodeExtraDataItems, packExtraDataList, calcExtraDataListHash, @@ -46,11 +47,13 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra let consensus = null let oracle = null let oracleVersion = null + let stakingRouter = null const deploy = async (options = undefined) => { const deployed = await deployAndConfigureAccountingOracle(admin) oracle = deployed.oracle consensus = deployed.consensus + stakingRouter = deployed.stakingRouter oracleVersion = +(await oracle.getContractVersion()) await consensus.addMember(member1, 1, { from: admin }) } @@ -251,5 +254,39 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) }) }) + + context('delivers the data to staking router', () => { + it('calling reportStakingModuleStuckValidatorsCountByNodeOperator on StakingRouter', async () => { + const { extraData, extraDataList } = await prepareNextReportInNextFrame() + await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + + const callsCount = await stakingRouter.totalCalls_reportStuckKeysByNodeOperator() + assert.equals(callsCount, extraData.stuckKeys.length) + + for (let i = 0; i < callsCount; i++) { + const call = await stakingRouter.calls_reportStuckKeysByNodeOperator(i) + const item = extraData.stuckKeys[i] + assert.equals(+call.stakingModuleId, item.moduleId) + assert.equals(call.nodeOperatorIds, '0x' + item.nodeOpIds.map((id) => hex(id, 8)).join('')) + assert.equals(call.keysCounts, '0x' + item.keysCounts.map((count) => hex(count, 16)).join('')) + } + }) + + it('calling reportStakingModuleExitedValidatorsCountByNodeOperator on StakingRouter', async () => { + const { extraData, extraDataList } = await prepareNextReportInNextFrame() + await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + + const callsCount = await stakingRouter.totalCalls_reportExitedKeysByNodeOperator() + assert.equals(callsCount, extraData.exitedKeys.length) + + for (let i = 0; i < callsCount; i++) { + const call = await stakingRouter.calls_reportExitedKeysByNodeOperator(i) + const item = extraData.exitedKeys[i] + assert.equals(+call.stakingModuleId, item.moduleId) + assert.equals(call.nodeOperatorIds, '0x' + item.nodeOpIds.map((id) => hex(id, 8)).join('')) + assert.equals(call.keysCounts, '0x' + item.keysCounts.map((count) => hex(count, 16)).join('')) + } + }) + }) }) }) From e841c747f946f08922b16ce6492e853fc024f644 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Wed, 15 Feb 2023 02:41:42 +0700 Subject: [PATCH 033/199] test: AccountingOracle.submitReportExtraDataList updates extra data processing state --- ...ng-oracle-submit-report-extra-data.test.js | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 1dc435cd4..8ad824daf 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -5,7 +5,6 @@ const { CONSENSUS_VERSION, deployAndConfigureAccountingOracle, getReportDataItems, - encodeExtraDataItem, encodeExtraDataItems, packExtraDataList, calcExtraDataListHash, @@ -288,5 +287,33 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra } }) }) + + it('updates extra data processing state', async () => { + const { extraDataItems, extraDataHash, reportFields, extraDataList } = await prepareNextReportInNextFrame() + + const stateBefore = await oracle.getExtraDataProcessingState() + + assert.equals(+stateBefore.refSlot, reportFields.refSlot) + assert.equals(+stateBefore.dataFormat, EXTRA_DATA_FORMAT_LIST) + assert.equals(+stateBefore.itemsCount, extraDataItems.length) + assert.equals(+stateBefore.itemsProcessed, 0) + assert.equals(+stateBefore.lastSortingKey, '0') + assert.equals(stateBefore.dataHash, extraDataHash) + + await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + + const stateAfter = await oracle.getExtraDataProcessingState() + + assert.equals(+stateAfter.refSlot, reportFields.refSlot) + assert.equals(+stateAfter.dataFormat, EXTRA_DATA_FORMAT_LIST) + assert.equals(+stateAfter.itemsCount, extraDataItems.length) + assert.equals(stateAfter.itemsProcessed, extraDataItems.length) + // TODO: figure out how to build this value and test it properly + assert.equals( + stateAfter.lastSortingKey, + '3533694129556768659166595001485837031654967793751237971583444623713894401' + ) + assert.equals(stateAfter.dataHash, extraDataHash) + }) }) }) From 576e2dd6a0e12a2cf0d7bf602069fed68167b148 Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Wed, 15 Feb 2023 04:34:06 +0400 Subject: [PATCH 034/199] Remove hardhat-foundry due to incompatibility with solidity-coverage --- foundry.toml | 4 +- foundry/skip-sol-tests-compilation.js | 54 +++++++++ hardhat.config.js | 5 +- package.json | 6 +- yarn.lock | 154 ++++++++++++++++---------- 5 files changed, 156 insertions(+), 67 deletions(-) create mode 100644 foundry/skip-sol-tests-compilation.js diff --git a/foundry.toml b/foundry.toml index f1aa5cf0d..e1d54c101 100644 --- a/foundry.toml +++ b/foundry.toml @@ -17,5 +17,5 @@ cache = true # The cache directory if enabled cache_path = 'foundry/cache' -# only run tests in contracts matching the specified regex pattern -match_path = 'test/*.test.sol' \ No newline at end of file +# Only run tests in contracts matching the specified glob pattern +match_path = '**/test/**/*.test.sol' \ No newline at end of file diff --git a/foundry/skip-sol-tests-compilation.js b/foundry/skip-sol-tests-compilation.js new file mode 100644 index 000000000..4704c865e --- /dev/null +++ b/foundry/skip-sol-tests-compilation.js @@ -0,0 +1,54 @@ +const fs = require('fs') +const path = require('path') +const minimatch = require('minimatch') +const { subtask } = require('hardhat/config') +const { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } = require('hardhat/builtin-tasks/task-names') + +/** + * Excludes Foundry test files from the Hardhat compilation. This step is required to avoid + * compilation errors when Hardhat can't find Foundry-specific solidity files. + * + * This function is used instead of the "hardhat-foundry" plugin because the last one is not + * compatible with the "solidity-coverage" plugin. After enabling "hardhat-foundry" coverage + * reports are always empty. + */ +subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(async (_, __, runSuper) => { + const foundryTomlPath = path.join(__dirname, '..', 'foundry.toml') + const matchPath = parseTomlValue(readTomlValue(await readTextFile(foundryTomlPath), 'match_path')) + const paths = await runSuper() + if (!matchPath) { + console.warn( + [ + 'WARNING:', + "'foundry.toml' file doesn't contain the 'match_path' property, or its value is empty.", + "If you don't use Foundry tests, the 'skip-sol-tests-compilation' subtask might be removed from hardhat.config.js" + ].join(' ') + ) + return paths + } + return paths.filter((path) => !minimatch(path, matchPath)) +}) + +function readTextFile(filePath) { + return new Promise((resolve, reject) => { + fs.readFile(filePath, 'utf8', (err, data) => { + if (err) reject(err) + resolve(data) + }) + }) +} + +function readTomlValue(tomlFile, key) { + const line = tomlFile.split('\n').find((line) => line.startsWith(key)) + if (line === undefined) return null + return line.split('=')[1].trim() +} + +function parseTomlValue(value) { + // TOML allows to use both "" and '' quotes for strings + if ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"'))) { + return value.slice(1, value.length - 1) + } else { + throw new Error(`Unsupported or invalid TOML parser value: ${value}`) + } +} diff --git a/hardhat.config.js b/hardhat.config.js index 74687eb28..ee6a712ad 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -11,7 +11,7 @@ require('hardhat-gas-reporter') require('solidity-coverage') require('hardhat-contract-sizer') require('hardhat-ignore-warnings') -require('@nomicfoundation/hardhat-foundry') +require('./foundry/skip-sol-tests-compilation') const NETWORK_NAME = getNetworkName() const ETH_ACCOUNT_NAME = process.env.ETH_ACCOUNT_NAME @@ -216,9 +216,6 @@ module.exports = { runOnCompile: true, strict: true, except: ['test_helpers', 'template', 'mocks', '@aragon', 'openzeppelin'], - }, - paths: { - sources: 'contracts' } } diff --git a/package.json b/package.json index f78d7ef89..6c53130d5 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "@babel/node": "^7.12.1", "@babel/preset-env": "^7.11.5", "@babel/register": "^7.12.1", - "@nomicfoundation/hardhat-foundry": "^1.0.0", "@nomiclabs/hardhat-ethers": "^2.0.4", "@nomiclabs/hardhat-etherscan": "^2.1.8", "@nomiclabs/hardhat-ganache": "^2.0.1", @@ -104,7 +103,7 @@ "ethereumjs-testrpc-sc": "^6.5.1-sc.1", "hardhat": "2.12.7", "hardhat-contract-sizer": "^2.5.0", - "hardhat-gas-reporter": "1.0.8", + "hardhat-gas-reporter": "^1.0.8", "hardhat-ignore-warnings": "skozin/hardhat-ignore-warnings#0ecf2ae85bddb83594193ee5c463cb4ae54cde7d", "husky": "^8.0.2", "ipfs-http-client": "^55.0.0", @@ -114,7 +113,7 @@ "prettier-plugin-solidity": "^1.1.0", "solhint": "^3.3.7", "solhint-plugin-lido": "^0.0.4", - "solidity-coverage": "^0.7.22", + "solidity-coverage": "^0.8.2", "truffle": "^5.1.43", "truffle-extract": "^1.2.1", "truffle-flattener": "^1.5.0", @@ -130,6 +129,7 @@ "concurrently": "^6.4.0", "ethereumjs-util": "^7.0.8", "ethers": "^5.1.4", + "minimatch": "^6.2.0", "node-gyp": "^8.4.1", "openzeppelin-solidity": "2.0.0", "solhint-plugin-lido": "^0.0.4", diff --git a/yarn.lock b/yarn.lock index f3284cbe9..48d24ce95 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1804,7 +1804,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.0.0-beta.146, @ethersproject/abi@npm:^5.7.0": +"@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.0.0-beta.146, @ethersproject/abi@npm:^5.0.9, @ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" dependencies: @@ -3539,7 +3539,6 @@ __metadata: "@babel/node": ^7.12.1 "@babel/preset-env": ^7.11.5 "@babel/register": ^7.12.1 - "@nomicfoundation/hardhat-foundry": ^1.0.0 "@nomiclabs/hardhat-ethers": ^2.0.4 "@nomiclabs/hardhat-etherscan": ^2.1.8 "@nomiclabs/hardhat-ganache": ^2.0.1 @@ -3570,19 +3569,20 @@ __metadata: ethers: ^5.1.4 hardhat: 2.12.7 hardhat-contract-sizer: ^2.5.0 - hardhat-gas-reporter: 1.0.8 + hardhat-gas-reporter: ^1.0.8 hardhat-ignore-warnings: "skozin/hardhat-ignore-warnings#0ecf2ae85bddb83594193ee5c463cb4ae54cde7d" husky: ^8.0.2 ipfs-http-client: ^55.0.0 lerna: ^3.22.1 lint-staged: ">=10" + minimatch: ^6.2.0 node-gyp: ^8.4.1 openzeppelin-solidity: 2.0.0 prettier: ^2.8.1 prettier-plugin-solidity: ^1.1.0 solhint: ^3.3.7 solhint-plugin-lido: ^0.0.4 - solidity-coverage: ^0.7.22 + solidity-coverage: ^0.8.2 truffle: ^5.1.43 truffle-extract: ^1.2.1 truffle-flattener: ^1.5.0 @@ -3843,17 +3843,6 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/hardhat-foundry@npm:^1.0.0": - version: 1.0.0 - resolution: "@nomicfoundation/hardhat-foundry@npm:1.0.0" - dependencies: - chalk: ^2.4.2 - peerDependencies: - hardhat: ^2.12.6 - checksum: ca4768663b9d6345c1a83ecbbbc4272c5f5920d7c366963aab3ed92048c08a59838e9b9a97422ad687fe0d730b5fd1be971572139641c673448983b8798a4c3f - languageName: node - linkType: hard - "@nomicfoundation/solidity-analyzer-darwin-arm64@npm:0.1.0": version: 0.1.0 resolution: "@nomicfoundation/solidity-analyzer-darwin-arm64@npm:0.1.0" @@ -4890,13 +4879,6 @@ __metadata: languageName: node linkType: hard -"@truffle/error@npm:^0.0.12": - version: 0.0.12 - resolution: "@truffle/error@npm:0.0.12" - checksum: 0065c5c8fd5023a54886a8962250e05fd570c52bc947420130a9ff824fe916f695f5efe342ecf8e0c16aaf70be5a35fa36d126ca3bbc18bcb345f60c3d0854b6 - languageName: node - linkType: hard - "@truffle/error@npm:^0.0.8": version: 0.0.8 resolution: "@truffle/error@npm:0.0.8" @@ -4946,29 +4928,6 @@ __metadata: languageName: node linkType: hard -"@truffle/interface-adapter@npm:^0.4.19": - version: 0.4.19 - resolution: "@truffle/interface-adapter@npm:0.4.19" - dependencies: - bn.js: ^5.1.3 - ethers: ^4.0.32 - source-map-support: ^0.5.19 - web3: 1.2.9 - checksum: 434f1ab60621d03a3aef82ea4eea5034231b78a6ff36990e43e5f0596e2dd641967d35dd262f3bc9197abd4282dd9f263561dde0bf13fcd2f690708900cf206b - languageName: node - linkType: hard - -"@truffle/provider@npm:^0.2.24": - version: 0.2.26 - resolution: "@truffle/provider@npm:0.2.26" - dependencies: - "@truffle/error": ^0.0.12 - "@truffle/interface-adapter": ^0.4.19 - web3: 1.2.9 - checksum: bbec2ab2724ef7fdb1017a38202de6807ff33dae0fc7cfd9d92e23a0cdc72b1202e8cb6fcd577c566f17a33ed09de57fb770aeccb68968f93f5c269d74c59f94 - languageName: node - linkType: hard - "@trufflesuite/chromafi@npm:^2.2.0": version: 2.2.0 resolution: "@trufflesuite/chromafi@npm:2.2.0" @@ -10387,6 +10346,15 @@ __metadata: languageName: node linkType: hard +"difflib@npm:^0.2.4": + version: 0.2.4 + resolution: "difflib@npm:0.2.4" + dependencies: + heap: ">= 0.2.0" + checksum: e65f90b03773277b0b1137b22fccb8abc70e8dcee3d8402370966188a31934eb8ea463a81ffab2a0803c45409314b78ed865494bee66c39ce72a1649b6192682 + languageName: node + linkType: hard + "dir-glob@npm:^2.2.2": version: 2.2.2 resolution: "dir-glob@npm:2.2.2" @@ -11632,7 +11600,7 @@ __metadata: languageName: node linkType: hard -"eth-gas-reporter@npm:^0.2.24": +"eth-gas-reporter@npm:^0.2.25": version: 0.2.25 resolution: "eth-gas-reporter@npm:0.2.25" dependencies: @@ -14330,16 +14298,16 @@ fsevents@~2.3.2: languageName: node linkType: hard -"hardhat-gas-reporter@npm:1.0.8": - version: 1.0.8 - resolution: "hardhat-gas-reporter@npm:1.0.8" +"hardhat-gas-reporter@npm:^1.0.8": + version: 1.0.9 + resolution: "hardhat-gas-reporter@npm:1.0.9" dependencies: array-uniq: 1.0.3 - eth-gas-reporter: ^0.2.24 + eth-gas-reporter: ^0.2.25 sha1: ^1.1.1 peerDependencies: hardhat: ^2.0.2 - checksum: cbee5088e797a149360a2e38ef40edb7234de272993c3ef426b4635991cb176964fd816caa8f40ec3931025b2164d46b7e3f6b24e9a14d110ac26d1f3ca65a25 + checksum: 97997c5c146bbb89b1915692c06a4100898d67b5d0a5e205f4e21a59f900b728486ea6e5cd3d0c8edf3004a3787ca30fd0041815622392c4f5c02c32f4dfdbac languageName: node linkType: hard @@ -14584,6 +14552,13 @@ fsevents@~2.3.2: languageName: node linkType: hard +"heap@npm:>= 0.2.0": + version: 0.2.7 + resolution: "heap@npm:0.2.7" + checksum: bedbcb978c6e3845af2b6484ac0fdfc131dd95c99a4e905791ceb80e883a6264d9583983cc9e509665b629c3d8e7813b55a5fa689e9fd2166feaadd6f55eac34 + languageName: node + linkType: hard + "hex-color-regex@npm:^1.1.0": version: 1.1.0 resolution: "hex-color-regex@npm:1.1.0" @@ -18677,6 +18652,15 @@ fsevents@~2.3.2: languageName: node linkType: hard +"minimatch@npm:^6.2.0": + version: 6.2.0 + resolution: "minimatch@npm:6.2.0" + dependencies: + brace-expansion: ^2.0.1 + checksum: 675bc5a2f94ee6a762fd70baf777520c841cdca16cf6e9fc918171ca436cf4ebb8f3fb1ccaa5fd20e370ae60044fb6bfe653ceee4f18aec7fa51a79984a71316 + languageName: node + linkType: hard + "minimist-options@npm:4.1.0": version: 4.1.0 resolution: "minimist-options@npm:4.1.0" @@ -18876,6 +18860,41 @@ fsevents@~2.3.2: languageName: node linkType: hard +"mocha@npm:7.1.2": + version: 7.1.2 + resolution: "mocha@npm:7.1.2" + dependencies: + ansi-colors: 3.2.3 + browser-stdout: 1.3.1 + chokidar: 3.3.0 + debug: 3.2.6 + diff: 3.5.0 + escape-string-regexp: 1.0.5 + find-up: 3.0.0 + glob: 7.1.3 + growl: 1.10.5 + he: 1.2.0 + js-yaml: 3.13.1 + log-symbols: 3.0.0 + minimatch: 3.0.4 + mkdirp: 0.5.5 + ms: 2.1.1 + node-environment-flags: 1.0.6 + object.assign: 4.1.0 + strip-json-comments: 2.0.1 + supports-color: 6.0.0 + which: 1.3.1 + wide-align: 1.1.3 + yargs: 13.3.2 + yargs-parser: 13.1.2 + yargs-unparser: 1.6.0 + bin: + _mocha: bin/_mocha + mocha: bin/mocha + checksum: 19d87fa1f957b1f3ec725e110ab5cf4c117b9716a307f53823dbe5d1e94173638804ca3263700ffd07645f39339f501f4c17fd0d27f93d2dcdc2e51e5843bb98 + languageName: node + linkType: hard + "mocha@npm:8.1.2": version: 8.1.2 resolution: "mocha@npm:8.1.2" @@ -24339,31 +24358,35 @@ resolve@1.1.x: languageName: node linkType: hard -"solidity-coverage@npm:^0.7.22": - version: 0.7.22 - resolution: "solidity-coverage@npm:0.7.22" +"solidity-coverage@npm:^0.8.2": + version: 0.8.2 + resolution: "solidity-coverage@npm:0.8.2" dependencies: - "@solidity-parser/parser": ^0.14.0 - "@truffle/provider": ^0.2.24 + "@ethersproject/abi": ^5.0.9 + "@solidity-parser/parser": ^0.14.1 chalk: ^2.4.2 death: ^1.1.0 detect-port: ^1.3.0 + difflib: ^0.2.4 fs-extra: ^8.1.0 ghost-testrpc: ^0.0.2 global-modules: ^2.0.0 globby: ^10.0.1 jsonschema: ^1.2.4 lodash: ^4.17.15 + mocha: 7.1.2 node-emoji: ^1.10.0 pify: ^4.0.1 recursive-readdir: ^2.2.2 sc-istanbul: ^0.4.5 semver: ^7.3.4 shelljs: ^0.8.3 - web3-utils: ^1.3.0 + web3-utils: ^1.3.6 + peerDependencies: + hardhat: ^2.11.0 bin: solidity-coverage: plugins/bin.js - checksum: a29d97d451b0196a0a0de9b9dace2a80b55bd43272038aea23a1db8f9ed547ec0e3843f6073f3005fd73ce2aa054ad8e43f7f25c57bb1bd9c8a50dea015859d9 + checksum: 3cf570696a74c3fa9b45625ea11b73c9539a5a22400fe81449856d106697418cb55c0225c3ad9257caee6731503c5f63a2979658ab28c6e715c6b179a741e26b languageName: node linkType: hard @@ -27892,6 +27915,21 @@ resolve@1.1.x: languageName: node linkType: hard +"web3-utils@npm:^1.3.6": + version: 1.8.2 + resolution: "web3-utils@npm:1.8.2" + dependencies: + bn.js: ^5.2.1 + ethereum-bloom-filters: ^1.0.6 + ethereumjs-util: ^7.1.0 + ethjs-unit: 0.1.6 + number-to-bn: 1.7.0 + randombytes: ^2.1.0 + utf8: 3.0.0 + checksum: bf401b4fa55da722c552299f459365edd2afffa71995479eb39dc233e74c267f584c13a6b288a344a866950dba1dcaa75620f1b5f6c46bd96afc523ccc1685a7 + languageName: node + linkType: hard + "web3@npm:1.2.1": version: 1.2.1 resolution: "web3@npm:1.2.1" From 8e529e769ced977a3a99c72366e71a86aadf3a85 Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Wed, 15 Feb 2023 04:43:22 +0400 Subject: [PATCH 035/199] Update test:gas command network argument --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c53130d5..6a3ea0df0 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "test-sequential": "yarn run test:unit-sequential", "test:unit": "hardhat test --parallel --network hardhat", "test:unit-sequential": "hardhat test --network hardhat", - "test:gas": "REPORT_GAS=true hardhat test --network localhost", + "test:gas": "REPORT_GAS=true hardhat test --network hardhat", "test:coverage": "hardhat coverage --testfiles test", "test:e2e": "npm run compile && ava -T 1000000 -v", "estimate-deposit-loop-gas": "yarn run test:unit ./estimate_deposit_loop_gas.js", From be71608dd1bce2b98fd74f11e72a6118a004f31e Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Wed, 15 Feb 2023 10:23:18 +0200 Subject: [PATCH 036/199] test: fix lido handleOracleReport test --- test/0.4.24/lido-handle-oracle-report.test.js | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/test/0.4.24/lido-handle-oracle-report.test.js b/test/0.4.24/lido-handle-oracle-report.test.js index a94fb0913..9568d0b25 100644 --- a/test/0.4.24/lido-handle-oracle-report.test.js +++ b/test/0.4.24/lido-handle-oracle-report.test.js @@ -1,9 +1,9 @@ const hre = require('hardhat') const { assert } = require('../helpers/assert') -const { ETH, toBN, genKeys, setBalance } = require('../helpers/utils') +const { ETH, toBN, genKeys, setBalance, StETH } = require('../helpers/utils') const { deployProtocol } = require('../helpers/protocol') const { EvmSnapshot } = require('../helpers/blockchain') -const { ZERO_ADDRESS } = require('../helpers/constants') +const { ZERO_ADDRESS, INITIAL_HOLDER } = require('../helpers/constants') const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') const ONE_YEAR = 3600 * 24 * 365 @@ -55,8 +55,9 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another withdrawalVault = deployed.withdrawalVault.address elRewardsVault = deployed.elRewardsVault.address + assert.equals(await lido.balanceOf(INITIAL_HOLDER), StETH(1)) await lido.submit(ZERO_ADDRESS, { from: stranger, value: ETH(30) }) - await lido.submit(ZERO_ADDRESS, { from: anotherStranger, value: ETH(70) }) + await lido.submit(ZERO_ADDRESS, { from: anotherStranger, value: ETH(69) }) await checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: 0 }) @@ -180,7 +181,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(1), treasuryBalanceDiff: ETH(0.05), strangerBalanceDiff: ETH(0.3 * 0.9), - anotherStrangerBalanceDiff: ETH(0.7 * 0.9), + anotherStrangerBalanceDiff: ETH(0.69 * 0.9), curatedModuleBalanceDiff: ETH(0.05) }) }) @@ -211,7 +212,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another ) }) - it('withdrawal vault balance check', async () => { + it('withdrawal vault balance check 2', async () => { await assert.reverts( lido.handleOracleReport(0, 0, 0, 0, 1, 0, 0, 0, { from: oracle }), 'IncorrectWithdrawalsVaultBalance(0)' @@ -271,7 +272,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(-0.96), treasuryBalanceDiff: ETH(0), strangerBalanceDiff: ETH(-30 * 0.0096), - anotherStrangerBalanceDiff: toBN(ETH(0.0096)).mul(toBN(-70)).toString(), + anotherStrangerBalanceDiff: toBN(ETH(0.0096)).mul(toBN(-69)).toString(), curatedModuleBalanceDiff: ETH(0) }) }) @@ -339,7 +340,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(0.96), treasuryBalanceDiff: ETH(0.96 * 0.05), strangerBalanceDiff: ETH(30 * 0.0096 * 0.9), - anotherStrangerBalanceDiff: ETH(70 * 0.0096 * 0.9), + anotherStrangerBalanceDiff: ETH(69 * 0.0096 * 0.9), curatedModuleBalanceDiff: ETH(0.96 * 0.05) }) }) @@ -470,7 +471,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(4), treasuryBalanceDiff: ETH(4 * 0.05), strangerBalanceDiff: ETH(4 * 0.3 * 0.9), - anotherStrangerBalanceDiff: ETH(4 * 0.7 * 0.9), + anotherStrangerBalanceDiff: ETH(4 * 0.69 * 0.9), curatedModuleBalanceDiff: ETH(4 * 0.05) }) }) @@ -497,7 +498,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(1), treasuryBalanceDiff: ETH(0.05), strangerBalanceDiff: ETH(0.3 * 0.9), - anotherStrangerBalanceDiff: ETH(0.7 * 0.9), + anotherStrangerBalanceDiff: ETH(0.69 * 0.9), curatedModuleBalanceDiff: ETH(0.05) }) assert.equals(await ethers.provider.getBalance(withdrawalVault), 0) @@ -525,7 +526,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(1), treasuryBalanceDiff: ETH(0.05), strangerBalanceDiff: ETH(0.3 * 0.9), - anotherStrangerBalanceDiff: ETH(0.7 * 0.9), + anotherStrangerBalanceDiff: ETH(0.69 * 0.9), curatedModuleBalanceDiff: ETH(0.05) }) @@ -555,14 +556,14 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(1), treasuryBalanceDiff: 0, strangerBalanceDiff: ETH(0.3), - anotherStrangerBalanceDiff: ETH(0.7), + anotherStrangerBalanceDiff: ETH(0.69), curatedModuleBalanceDiff: 0 }) assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0)) }) - it('does not smooth el rewards if report in limit without lido fee', async () => { + it('does not smooth el rewards if report in limit without lido fee 2', async () => { await setBalance(elRewardsVault, ETH(1.5)) await oracleReportSanityChecker.setOracleReportLimits( @@ -584,7 +585,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(1), treasuryBalanceDiff: 0, strangerBalanceDiff: ETH(0.3), - anotherStrangerBalanceDiff: ETH(0.7), + anotherStrangerBalanceDiff: ETH(0.69), curatedModuleBalanceDiff: 0 }) @@ -613,7 +614,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(1), treasuryBalanceDiff: 0, strangerBalanceDiff: ETH(0.3), - anotherStrangerBalanceDiff: ETH(0.7), + anotherStrangerBalanceDiff: ETH(0.69), curatedModuleBalanceDiff: 0 }) @@ -643,7 +644,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(1), treasuryBalanceDiff: ETH(0.05), strangerBalanceDiff: ETH(0.3 * 0.9), - anotherStrangerBalanceDiff: ETH(0.7 * 0.9), + anotherStrangerBalanceDiff: ETH(0.69 * 0.9), curatedModuleBalanceDiff: ETH(0.05) }) @@ -672,7 +673,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another totalPooledEtherDiff: ETH(1), treasuryBalanceDiff: ETH(0.05), strangerBalanceDiff: ETH(0.3 * 0.9), - anotherStrangerBalanceDiff: ETH(0.7 * 0.9), + anotherStrangerBalanceDiff: ETH(0.69 * 0.9), curatedModuleBalanceDiff: ETH(0.05) }) From 35dd3270bb13e2a28287665f9ec7d0c0f280b0a4 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Wed, 15 Feb 2023 10:38:44 +0200 Subject: [PATCH 037/199] test: fix burner tests --- test/0.8.9/burner.test.js | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/test/0.8.9/burner.test.js b/test/0.8.9/burner.test.js index 54e89d588..14da006d8 100644 --- a/test/0.8.9/burner.test.js +++ b/test/0.8.9/burner.test.js @@ -5,6 +5,7 @@ const { EvmSnapshot } = require('../helpers/blockchain') const { ETH, StETH } = require('../helpers/utils') const { assert } = require('../helpers/assert') const { deployProtocol } = require('../helpers/protocol') +const { INITIAL_HOLDER } = require('../helpers/constants') const Burner = artifacts.require('Burner.sol') @@ -50,12 +51,13 @@ contract('Burner', ([deployer, _, anotherAccount]) => { // stake ether to get an stETH in exchange await web3.eth.sendTransaction({ from: anotherAccount, to: lido.address, value: ETH(20) }) await web3.eth.sendTransaction({ from: deployer, to: lido.address, value: ETH(30) }) - await web3.eth.sendTransaction({ from: voting, to: lido.address, value: ETH(25) }) + await web3.eth.sendTransaction({ from: voting, to: lido.address, value: ETH(24) }) - // check stETH balances + // check stETH balances 1 + 20 + 30 + 24 = 75 + assert.equals(await lido.balanceOf(INITIAL_HOLDER), StETH(1)) assert.equals(await lido.balanceOf(anotherAccount), StETH(20)) assert.equals(await lido.balanceOf(deployer), StETH(30)) - assert.equals(await lido.balanceOf(voting), StETH(25)) + assert.equals(await lido.balanceOf(voting), StETH(24)) }) it(`init with already burnt counters works`, async () => { @@ -162,7 +164,7 @@ contract('Burner', ([deployer, _, anotherAccount]) => { // check stETH balances assert.equals(await lido.balanceOf(burner.address), StETH(8)) - assert.equals(await lido.balanceOf(voting), StETH(17)) + assert.equals(await lido.balanceOf(voting), StETH(16)) const sharesAmount12 = sharesAmount8StETH.mul(bn(3)).div(bn(2)) await lido.approve(burner.address, StETH(13), { from: voting }) @@ -177,7 +179,7 @@ contract('Burner', ([deployer, _, anotherAccount]) => { // check stETH balances again, we didn't execute the actual burn assert.equals(await lido.balanceOf(burner.address), StETH(20)) - assert.equals(await lido.balanceOf(voting), StETH(5)) + assert.equals(await lido.balanceOf(voting), StETH(4)) }) it(`invoke commitSharesToBurn without requested burn works`, async () => { @@ -344,26 +346,27 @@ contract('Burner', ([deployer, _, anotherAccount]) => { }) it(`a positive rebase happens after the burn application`, async () => { - await lido.approve(burner.address, StETH(25), { from: voting }) - await burner.requestBurnMyStETHForCover(StETH(25), { from: voting }) + await lido.approve(burner.address, StETH(24), { from: voting }) + await burner.requestBurnMyStETHForCover(StETH(24), { from: voting }) - assert.equals(await lido.balanceOf(burner.address), StETH(25)) + assert.equals(await lido.balanceOf(burner.address), StETH(24)) assert.equals(await lido.balanceOf(voting), StETH(0)) assert.equals(await lido.balanceOf(anotherAccount), StETH(20)) assert.equals(await lido.balanceOf(deployer), StETH(30)) await burner.commitSharesToBurn(ETH(50), { from: lido.address }) - await lido.burnShares(burner.address, await lido.getPooledEthByShares(StETH(25))) + await lido.burnShares(burner.address, await lido.getPooledEthByShares(StETH(24))) assert.equals(await lido.balanceOf(burner.address), StETH(0)) assert.equals(await lido.balanceOf(voting), StETH(0)) - // 1/3 of the shares amount was burnt, so remaining stETH becomes more 'expensive' - // totalShares become 2/3 of the previous value - // so the new share price increases by 3/2 - assert.equals(await lido.balanceOf(deployer), bn(StETH(30)).mul(bn(3)).div(bn(2))) - assert.equals(await lido.balanceOf(anotherAccount), bn(StETH(20)).mul(bn(3)).div(bn(2))) + // 24/75 of the shares amount was burnt, so remaining stETH becomes more 'expensive' + // totalShares become 51/75 of the previous value + // so the new share price increases by 75/51 + + assert.equals(await lido.balanceOf(deployer), bn(StETH(30 * 75)).divn(51)) + assert.equals(await lido.balanceOf(anotherAccount), bn(StETH(20 * 75)).divn(51)) }) it(`limit burn shares per run works (cover)`, async () => { @@ -378,7 +381,7 @@ contract('Burner', ([deployer, _, anotherAccount]) => { assert.emits( receipt, `StETHBurnt`, { - isCover: true, amountOfStETH: StETH(0.9), amountOfShares: stETHShares(0.9) + isCover: true, amountOfStETH: StETH(0.9), amountOfShares: stETHShares(0.9) }) assert.emitsNumberOfEvents(receipt, `StETHBurnt`, 1) await lido.burnShares(burner.address, stETHShares(0.9)) @@ -408,7 +411,7 @@ contract('Burner', ([deployer, _, anotherAccount]) => { assert.emits( receiptN, `StETHBurnt`, { - isCover: true, amountOfStETH: await lido.getPooledEthByShares(burnt), amountOfShares: burnt + isCover: true, amountOfStETH: await lido.getPooledEthByShares(burnt), amountOfShares: burnt }) await lido.burnShares(burner.address, burnt) From f0c43c1dd55c66c2d5eead944b7e2a249dfb0ded Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Wed, 15 Feb 2023 13:04:12 +0200 Subject: [PATCH 038/199] accounting oracle: fix docs, define consensus rules for empty extra data --- contracts/0.8.9/oracle/AccountingOracle.sol | 35 +++++++++++++++++-- ...ng-oracle-submit-report-extra-data.test.js | 2 +- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/contracts/0.8.9/oracle/AccountingOracle.sol b/contracts/0.8.9/oracle/AccountingOracle.sol index c9bf7b61c..b84150cef 100644 --- a/contracts/0.8.9/oracle/AccountingOracle.sol +++ b/contracts/0.8.9/oracle/AccountingOracle.sol @@ -98,7 +98,9 @@ contract AccountingOracle is BaseOracle { error CannotSubmitExtraDataBeforeMainData(); error ExtraDataAlreadyProcessed(); error ExtraDataListOnlySupportsSingleTx(); + error UnexpectedExtraDataHash(bytes32 consensusHash, bytes32 receivedHash); error UnexpectedExtraDataFormat(uint256 expectedFormat, uint256 receivedFormat); + error ExtraDataItemsCountCannotBeZeroForNonEmptyData(); error UnexpectedExtraDataItemsCount(uint256 expectedCount, uint256 receivedCount); error UnexpectedExtraDataIndex(uint256 expectedIndex, uint256 receivedIndex); error InvalidExtraDataItem(uint256 itemIndex); @@ -320,21 +322,35 @@ contract AccountingOracle is BaseOracle { /// Extra data array can be passed in different formats, see below. /// - /// @dev Format of the extra data. Currently, only the EXTRA_DATA_FORMAT_LIST=0 is - /// supported. See the constant defining a specific extra data format for more info. + /// @dev Format of the extra data. + /// + /// Currently, only the EXTRA_DATA_FORMAT_EMPTY=0 and EXTRA_DATA_FORMAT_LIST=1 + /// formats are supported. See the constant defining a specific data format for + /// more info. + /// uint256 extraDataFormat; /// @dev Hash of the extra data. See the constant defining a specific extra data /// format for the info on how to calculate the hash. + /// + /// Must be set to a zero hash if the oracle report contains no extra data. + /// bytes32 extraDataHash; /// @dev Number of the extra data items. + /// + /// Must be set to zero if the oracle report contains no extra data. + /// uint256 extraDataItemsCount; } uint256 public constant EXTRA_DATA_TYPE_STUCK_VALIDATORS = 1; uint256 public constant EXTRA_DATA_TYPE_EXITED_VALIDATORS = 2; + /// @notice The extra data format used to signify that the oracle report contains no extra data. + /// + uint256 public constant EXTRA_DATA_FORMAT_EMPTY = 0; + /// @notice The list format for the extra data array. Used when all extra data processing /// fits into a single transaction. /// @@ -523,10 +539,23 @@ contract AccountingOracle is BaseOracle { } function _handleConsensusReportData(ReportData calldata data, uint256 prevRefSlot) internal { + if (data.extraDataFormat == EXTRA_DATA_FORMAT_EMPTY) { + if (data.extraDataHash != bytes32(0)) { + revert UnexpectedExtraDataHash(bytes32(0), data.extraDataHash); + } + if (data.extraDataItemsCount != 0) { + revert UnexpectedExtraDataItemsCount(0, data.extraDataItemsCount); + } + } + if (data.extraDataFormat != EXTRA_DATA_FORMAT_LIST) { revert UnsupportedExtraDataFormat(data.extraDataFormat); } + if (data.extraDataItemsCount == 0) { + revert ExtraDataItemsCountCannotBeZeroForNonEmptyData(); + } + IOracleReportSanityChecker(LOCATOR.oracleReportSanityChecker()) .checkAccountingExtraDataListItemsCount(data.extraDataItemsCount); @@ -657,7 +686,7 @@ contract AccountingOracle is BaseOracle { bytes32 dataHash = keccak256(items); if (dataHash != procState.dataHash) { - revert UnexpectedDataHash(procState.dataHash, dataHash); + revert UnexpectedExtraDataHash(procState.dataHash, dataHash); } ExtraDataIterState memory iter = ExtraDataIterState({ diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 8ad824daf..b3c1730c2 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -176,7 +176,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra const incorrectExtraDataHash = calcExtraDataListHash(incorrectExtraDataList) await assert.reverts( oracle.submitReportExtraDataList(incorrectExtraDataList, { from: member1 }), - `UnexpectedDataHash("${extraDataHash}", "${incorrectExtraDataHash}")` + `UnexpectedExtraDataHash("${extraDataHash}", "${incorrectExtraDataHash}")` ) }) From b0553c0169dea6ca2b9caf4643fa77ce31a448a6 Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Wed, 15 Feb 2023 13:04:38 +0200 Subject: [PATCH 039/199] exit bus oracle: fix docs --- contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol index 9ac99f019..16acdef2a 100644 --- a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol +++ b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol @@ -147,11 +147,15 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil { /// /// @dev Total number of validator exit requests in this report. Must not be greater - /// than limit checked in OracleReportSanityChecker.checkExitBusOracleReport + /// than limit checked in OracleReportSanityChecker.checkExitBusOracleReport. + /// + /// Cannot be zero: in the case there's no newly exited or stuck validators at the moment + /// of the reference slot that staking module contracts are not aware of at the same moment, + /// oracles should skip submitting the report. uint256 requestsCount; /// @dev Format of the validator exit requests data. Currently, only the - /// DATA_FORMAT_LIST=0 is supported. + /// DATA_FORMAT_LIST=1 is supported. uint256 dataFormat; /// @dev Validator exit requests data. Can differ based on the data format, From 54627a56c19c2a0977bd493dc8042d689e26573e Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Wed, 15 Feb 2023 13:05:21 +0200 Subject: [PATCH 040/199] accounting oracle: fix a forgotten test --- test/0.8.9/oracle/accounting-oracle-happy-path.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/0.8.9/oracle/accounting-oracle-happy-path.test.js b/test/0.8.9/oracle/accounting-oracle-happy-path.test.js index eeb22e24f..b9838fac2 100644 --- a/test/0.8.9/oracle/accounting-oracle-happy-path.test.js +++ b/test/0.8.9/oracle/accounting-oracle-happy-path.test.js @@ -282,7 +282,7 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { const invalidExtraDataHash = calcExtraDataListHash(invalidExtraDataList) await assertRevert( oracle.submitReportExtraDataList(invalidExtraDataList, {from: member2}), - `UnexpectedDataHash("${extraDataHash}", "${invalidExtraDataHash}")` + `UnexpectedExtraDataHash("${extraDataHash}", "${invalidExtraDataHash}")` ) }) From 40ace2e93175efacf80f5cdbe90003cc98f30a2f Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Wed, 15 Feb 2023 13:14:38 +0200 Subject: [PATCH 041/199] accounting oracle: fix the code added in f0c43c1d --- contracts/0.8.9/oracle/AccountingOracle.sol | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/contracts/0.8.9/oracle/AccountingOracle.sol b/contracts/0.8.9/oracle/AccountingOracle.sol index b84150cef..0359c94a3 100644 --- a/contracts/0.8.9/oracle/AccountingOracle.sol +++ b/contracts/0.8.9/oracle/AccountingOracle.sol @@ -546,14 +546,13 @@ contract AccountingOracle is BaseOracle { if (data.extraDataItemsCount != 0) { revert UnexpectedExtraDataItemsCount(0, data.extraDataItemsCount); } - } - - if (data.extraDataFormat != EXTRA_DATA_FORMAT_LIST) { - revert UnsupportedExtraDataFormat(data.extraDataFormat); - } - - if (data.extraDataItemsCount == 0) { - revert ExtraDataItemsCountCannotBeZeroForNonEmptyData(); + } else { + if (data.extraDataFormat != EXTRA_DATA_FORMAT_LIST) { + revert UnsupportedExtraDataFormat(data.extraDataFormat); + } + if (data.extraDataItemsCount == 0) { + revert ExtraDataItemsCountCannotBeZeroForNonEmptyData(); + } } IOracleReportSanityChecker(LOCATOR.oracleReportSanityChecker()) From 9c951ee12d9b262a97ad10a29eaa20ac94225124 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Wed, 15 Feb 2023 18:28:28 +0700 Subject: [PATCH 042/199] =?UTF-8?q?test:=20AccountingOracle.submitReportEx?= =?UTF-8?q?traDataList=20enforces=20data=20safety=20boundaries=20=E2=80=94?= =?UTF-8?q?=20UnexpectedExtraDataIndex=20cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oracle/accounting-oracle-deploy.test.js | 18 +--- ...ng-oracle-submit-report-extra-data.test.js | 88 +++++++++++++++++-- 2 files changed, 84 insertions(+), 22 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-deploy.test.js b/test/0.8.9/oracle/accounting-oracle-deploy.test.js index 588a1d06c..bb4b2a56b 100644 --- a/test/0.8.9/oracle/accounting-oracle-deploy.test.js +++ b/test/0.8.9/oracle/accounting-oracle-deploy.test.js @@ -82,20 +82,10 @@ function encodeExtraDataItem(itemIndex, itemType, moduleId, nodeOperatorIds, key function encodeExtraDataItems({ stuckKeys, exitedKeys }) { const items = [] - let itemType = EXTRA_DATA_TYPE_STUCK_VALIDATORS - - for (let i = 0; i < stuckKeys.length; ++i) { - const item = stuckKeys[i] - items.push(encodeExtraDataItem(items.length, itemType, item.moduleId, item.nodeOpIds, item.keysCounts)) - } - - itemType = EXTRA_DATA_TYPE_EXITED_VALIDATORS - - for (let i = 0; i < exitedKeys.length; ++i) { - const item = exitedKeys[i] - items.push(encodeExtraDataItem(items.length, itemType, item.moduleId, item.nodeOpIds, item.keysCounts)) - } - + const encodeItem = (item, type) => + encodeExtraDataItem(items.length, type, item.moduleId, item.nodeOpIds, item.keysCounts) + stuckKeys.forEach((item) => items.push(encodeItem(item, EXTRA_DATA_TYPE_STUCK_VALIDATORS))) + exitedKeys.forEach((item) => items.push(encodeItem(item, EXTRA_DATA_TYPE_EXITED_VALIDATORS))) return items } diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index b3c1730c2..efd44523f 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -5,11 +5,13 @@ const { CONSENSUS_VERSION, deployAndConfigureAccountingOracle, getReportDataItems, + encodeExtraDataItem, encodeExtraDataItems, packExtraDataList, calcExtraDataListHash, calcReportDataHash, - EXTRA_DATA_FORMAT_LIST + EXTRA_DATA_FORMAT_LIST, + EXTRA_DATA_TYPE_STUCK_VALIDATORS } = require('./accounting-oracle-deploy.test') const getDefaultExtraData = () => ({ @@ -58,10 +60,13 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra } // note: reportFieldsArg.refSlot is required to pass here - function getReportData({ extraData: extraDataArg, reportFields: reportFieldsArg } = {}) { + function getReportData({ + extraData: extraDataArg, + extraDataItems: extraDataItemsArgs, + reportFields: reportFieldsArg + } = {}) { const extraData = extraDataArg || getDefaultExtraData() - - const extraDataItems = encodeExtraDataItems(extraData) + const extraDataItems = extraDataItemsArgs || encodeExtraDataItems(extraData) const extraDataList = packExtraDataList(extraDataItems) const extraDataHash = calcExtraDataListHash(extraDataList) @@ -85,8 +90,8 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra } } - async function prepareNextReport({ extraData, reportFields = {} } = {}) { - const data = getReportData({ extraData, reportFields }) + async function prepareNextReport({ extraData, extraDataItems, reportFields = {} } = {}) { + const data = getReportData({ extraData, extraDataItems, reportFields }) await consensus.submitReport(data.reportFields.refSlot, data.reportHash, CONSENSUS_VERSION, { from: member1 }) await oracle.submitReportData(data.reportItems, oracleVersion, { from: member1 }) @@ -99,11 +104,11 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra } } - async function prepareNextReportInNextFrame({ extraData, reportFields = {} } = {}) { + async function prepareNextReportInNextFrame({ reportFields = {}, ...prepareArgs } = {}) { await consensus.advanceTimeToNextFrameStart() const { refSlot } = await consensus.getCurrentFrame() const next = await prepareNextReport({ - extraData, + ...prepareArgs, reportFields: { ...reportFields, refSlot @@ -254,6 +259,73 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) }) + context('enforces data safety boundaries', () => { + context('checks encoded data indexes for UnexpectedExtraDataIndex reverts', () => { + // contextual helper to prepeare wrong indexed data + const getExtraWithCustomLastIndex = (itemsCount, lastIndexCustom) => { + const dummyArr = Array.from(Array(itemsCount)) + const stuckKeys = dummyArr.map((_, i) => ({ moduleId: i + 1, nodeOpIds: [0], keysCounts: [i + 1] })) + const extraData = { stuckKeys, exitedKeys: [] } + const extraDataItems = [] + const type = EXTRA_DATA_TYPE_STUCK_VALIDATORS + dummyArr.forEach((_, i) => { + const item = extraData.stuckKeys[i] + const index = i < itemsCount - 1 ? i : lastIndexCustom + extraDataItems.push(encodeExtraDataItem(index, type, item.moduleId, item.nodeOpIds, item.keysCounts)) + }) + return { + extraData, + extraDataItems, + lastIndexDefault: itemsCount - 1, + lastIndexCustom + } + } + + it('if first item index is not zero', async () => { + const { extraData, extraDataItems, lastIndexDefault, lastIndexCustom } = getExtraWithCustomLastIndex(1, 1) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `UnexpectedExtraDataIndex(${lastIndexDefault}, ${lastIndexCustom})` + ) + }) + + it('if next index is greater than previous for more than +1', async () => { + const { extraData, extraDataItems, lastIndexDefault, lastIndexCustom } = getExtraWithCustomLastIndex(2, 2) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `UnexpectedExtraDataIndex(${lastIndexDefault}, ${lastIndexCustom})` + ) + }) + + it('if next index equals to previous', async () => { + const { extraData, extraDataItems, lastIndexDefault, lastIndexCustom } = getExtraWithCustomLastIndex(3, 1) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `UnexpectedExtraDataIndex(${lastIndexDefault}, ${lastIndexCustom})` + ) + }) + + it('if next index less than previous', async () => { + const { extraData, extraDataItems, lastIndexDefault, lastIndexCustom } = getExtraWithCustomLastIndex(3, 0) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `UnexpectedExtraDataIndex(${lastIndexDefault}, ${lastIndexCustom})` + ) + }) + + it('succeeds if indexes were passed sequentially', async () => { + const { extraData, extraDataItems } = getExtraWithCustomLastIndex(3, 2) + const { extraDataList, reportFields } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + const tx = await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) + }) + }) + }) + context('delivers the data to staking router', () => { it('calling reportStakingModuleStuckValidatorsCountByNodeOperator on StakingRouter', async () => { const { extraData, extraDataList } = await prepareNextReportInNextFrame() From c4f4b07f47186cf6bb70c39fe38ce053279156e0 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Wed, 15 Feb 2023 18:29:05 +0700 Subject: [PATCH 043/199] =?UTF-8?q?test:=20AccountingOracle.submitReportEx?= =?UTF-8?q?traDataList=20enforces=20data=20safety=20boundaries=20=E2=80=94?= =?UTF-8?q?=20UnsupportedExtraDataType=20cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ng-oracle-submit-report-extra-data.test.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index efd44523f..6c5fbf6d3 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -324,6 +324,57 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) }) }) + + context('checks data type for UnsupportedExtraDataType reverts (only supported types are `1` and `2`)', () => { + // contextual helper to prepeare wrong typed data + const getExtraWithCustomType = (typeCustom) => { + const extraData = { + stuckKeys: [{ moduleId: 1, nodeOpIds: [1], keysCounts: [2] }], + exitedKeys: [] + } + const item = extraData.stuckKeys[0] + const extraDataItems = [] + extraDataItems.push(encodeExtraDataItem(0, typeCustom, item.moduleId, item.nodeOpIds, item.keysCounts)) + return { + extraData, + extraDataItems, + wrongTypedIndex: 0, + typeCustom + } + } + + it('if type `0` was passed', async () => { + const { extraData, extraDataItems, wrongTypedIndex, typeCustom } = getExtraWithCustomType(0) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `UnsupportedExtraDataType(${wrongTypedIndex}, ${typeCustom})` + ) + }) + + it('if type `3` was passed', async () => { + const { extraData, extraDataItems, wrongTypedIndex, typeCustom } = getExtraWithCustomType(3) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `UnsupportedExtraDataType(${wrongTypedIndex}, ${typeCustom})` + ) + }) + + it('succeeds if `1` was passed', async () => { + const { extraData, extraDataItems } = getExtraWithCustomType(1) + const { extraDataList, reportFields } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + const tx = await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) + }) + + it('succeeds if `2` was passed', async () => { + const { extraData, extraDataItems } = getExtraWithCustomType(2) + const { extraDataList, reportFields } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + const tx = await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) + }) + }) }) context('delivers the data to staking router', () => { From f1a8842fcaddd078bbc31118439469f6d8af6e28 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Wed, 15 Feb 2023 15:02:24 +0200 Subject: [PATCH 044/199] test: fix lido penalties and slashing test --- test/scenario/lido_penalties_slashing.js | 380 ++++++++++------------- 1 file changed, 161 insertions(+), 219 deletions(-) diff --git a/test/scenario/lido_penalties_slashing.js b/test/scenario/lido_penalties_slashing.js index 2690c7d02..214207d7e 100644 --- a/test/scenario/lido_penalties_slashing.js +++ b/test/scenario/lido_penalties_slashing.js @@ -1,21 +1,20 @@ const hre = require('hardhat') -const { BN } = require('bn.js') const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') -const { getEventArgument } = require('@aragon/contract-helpers-test') +const { getEventArgument, bn } = require('@aragon/contract-helpers-test') const { assert } = require('../helpers/assert') -const { pad, ETH, tokens, toBN } = require('../helpers/utils') +const { pad, ETH, tokens, StETH, shares } = require('../helpers/utils') const { waitBlocks } = require('../helpers/blockchain') const { deployProtocol } = require('../helpers/protocol') const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') -const { SLOTS_PER_FRAME, SECONDS_PER_FRAME } = require('../helpers/constants') +const { SECONDS_PER_FRAME } = require('../helpers/constants') const { pushOracleReport } = require('../helpers/oracle') const { oracleReportSanityCheckerStubFactory } = require('../helpers/factories') const { DSMAttestMessage, DSMPauseMessage, signDepositData } = require('../helpers/signatures') const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistry') -contract('Lido: penalties, slashing, operator stops', (addresses) => { +contract.only('Lido: penalties, slashing, operator stops', (addresses) => { const [ // node operators operator_1, @@ -35,51 +34,50 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { let elRewardsVault before('DAO, node operators registry, token, pool and deposit security module are deployed and initialized', async () => { - const deployed = await deployProtocol({ - oracleReportSanityCheckerFactory: oracleReportSanityCheckerStubFactory, - stakingModulesFactory: async (protocol) => { - const curatedModule = await setupNodeOperatorsRegistry(protocol) - return [ - { - module: curatedModule, - name: 'Curated', - targetShares: 10000, - moduleFee: 500, - treasuryFee: 500 - } - ] - } - }) - - // contracts/StETH.sol - token = deployed.pool - - // contracts/Lido.sol - pool = deployed.pool - - // contracts/nos/NodeOperatorsRegistry.sol - nodeOperatorsRegistry = deployed.stakingModules[0] - - // mocks - oracle = deployed.oracle - consensus = deployed.consensusContract - depositContractMock = deployed.depositContract - - stakingRouter = deployed.stakingRouter - - // addresses - treasuryAddr = deployed.treasury.address - depositSecurityModule = deployed.depositSecurityModule - guardians = deployed.guardians - voting = deployed.voting.address - elRewardsVault = deployed.elRewardsVault - - depositRoot = await depositContractMock.get_deposit_root() - withdrawalCredentials = pad('0x0202', 32) - - await stakingRouter.setWithdrawalCredentials(withdrawalCredentials, { from: voting }) - } - ) + const deployed = await deployProtocol({ + oracleReportSanityCheckerFactory: oracleReportSanityCheckerStubFactory, + stakingModulesFactory: async (protocol) => { + const curatedModule = await setupNodeOperatorsRegistry(protocol) + return [ + { + module: curatedModule, + name: 'Curated', + targetShares: 10000, + moduleFee: 500, + treasuryFee: 500 + } + ] + } + }) + + // contracts/StETH.sol + token = deployed.pool + + // contracts/Lido.sol + pool = deployed.pool + + // contracts/nos/NodeOperatorsRegistry.sol + nodeOperatorsRegistry = deployed.stakingModules[0] + + // mocks + oracle = deployed.oracle + consensus = deployed.consensusContract + depositContractMock = deployed.depositContract + + stakingRouter = deployed.stakingRouter + + // addresses + treasuryAddr = deployed.treasury.address + depositSecurityModule = deployed.depositSecurityModule + guardians = deployed.guardians + voting = deployed.voting.address + elRewardsVault = deployed.elRewardsVault + + depositRoot = await depositContractMock.get_deposit_root() + withdrawalCredentials = pad('0x0202', 32) + + await stakingRouter.setWithdrawalCredentials(withdrawalCredentials, { from: voting }) + }) const pushReport = async (clValidators, clBalance) => { const elRewards = await web3.eth.getBalance(elRewardsVault.address) @@ -88,8 +86,10 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { await ethers.provider.send('evm_mine') } - let awaitingTotalShares = new BN(0) - let awaitingUser1Balance = new BN(0) + // storing incremental calculated values that changes all across the test suite + let expectedTotalShares = shares(0) + let expectedUser1Balance = StETH(0) + let expectedUser1Shares = shares(0) // Each node operator has its Ethereum 1 address, a name and a set of registered // validators, each of them defined as a (public key, signature) pair @@ -143,10 +143,8 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { }) it('the user deposits 32 ETH to the pool', async () => { - const depositAmount = ETH(32) - awaitingTotalShares = new BN(depositAmount) - awaitingUser1Balance = new BN(depositAmount) - await web3.eth.sendTransaction({ to: pool.address, from: user1, value: depositAmount }) + await web3.eth.sendTransaction({ to: pool.address, from: user1, value: ETH(32) }) + const block = await web3.eth.getBlock('latest') const keysOpIndex = await nodeOperatorsRegistry.getKeysOpIndex() @@ -182,18 +180,19 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { assertBn(ether2Stat.depositedValidators, 0, 'no validators have received the ether2') assertBn(ether2Stat.beaconBalance, 0, 'remote ether2 not reported yet') - // All Ether was buffered within the pool contract atm - - assertBn(await pool.getBufferedEther(), ETH(32), `all ether is buffered until there's a validator to deposit it`) - assertBn(await pool.getTotalPooledEther(), ETH(32), 'total pooled ether') + assertBn(await pool.getBufferedEther(), ETH(33), `All Ether was buffered within the pool contract atm`) + assertBn(await pool.getTotalPooledEther(), ETH(33), 'total pooled ether') - // The amount of tokens corresponding to the deposited ETH value was minted to the user + expectedUser1Balance = StETH(32) + expectedUser1Shares = shares(32) - assertBn(await token.balanceOf(user1), awaitingUser1Balance, 'user1 tokens') + assertBn(await token.sharesOf(user1), shares(32), "User1 holds 32 shares") + assertBn(await token.balanceOf(user1), expectedUser1Balance, + 'The amount of tokens corresponding to the deposited ETH value was minted to the user') + assertBn(await token.totalSupply(), StETH(33), 'token total supply') - assertBn(await token.totalSupply(), tokens(32), 'token total supply') - // Total shares are equal to deposited eth before ratio change and fee mint - assertBn(await token.getTotalShares(), awaitingTotalShares, 'total shares') + assertBn(await token.getTotalShares(), shares(33), + 'Total shares are equal to deposited eth before ratio change and fee mint') }) it(`voting grants first operator right to have one validator`, async () => { @@ -201,8 +200,8 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { }) it(`new validator doesn't get buffered ether even if there's 32 ETH deposit in the pool`, async () => { - assertBn(await pool.getBufferedEther(), ETH(32), `all ether is buffered until there's a validator to deposit it`) - assertBn(await pool.getTotalPooledEther(), ETH(32), 'total pooled ether') + assertBn(await pool.getBufferedEther(), ETH(33), `all ether is buffered until there's a validator to deposit it`) + assertBn(await pool.getTotalPooledEther(), ETH(33), 'total pooled ether') assertBn(await nodeOperatorsRegistry.getUnusedSigningKeyCount(0), 1, 'one key available for the first validator') }) @@ -235,103 +234,62 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { }) it('new validator gets the 32 ETH deposit from the pool', async () => { - assertBn(await pool.getBufferedEther(), ETH(0), `all ether is buffered until there's a validator to deposit it`) - assertBn(await pool.getTotalPooledEther(), ETH(32), 'total pooled ether') + assertBn(await pool.getBufferedEther(), ETH(1), `only initial eth is left`) + assertBn(await pool.getTotalPooledEther(), ETH(33), 'total pooled ether') assertBn(await nodeOperatorsRegistry.getUnusedSigningKeyCount(0), 0, 'no more available keys for the first validator') }) it('first oracle report is taken as-is for Lido', async () => { - const oldTotalShares = await token.getTotalShares() + assertBn(await pool.getTotalPooledEther(), ETH(33), '32 ETH deposit + 1 ETH initial') - // Old total pooled Ether - - const oldTotalPooledEther = await pool.getTotalPooledEther() - assertBn(oldTotalPooledEther, ETH(32), 'total pooled ether') - - const refSlot = 1 * SLOTS_PER_FRAME // Reporting 1 ETH balance loss (32 => 31) - const balanceReported = ETH(31) - awaitingTotalShares = oldTotalShares - awaitingUser1Balance = new BN(balanceReported) - - await pushReport(1, balanceReported) - - // Total shares stay the same because no fee shares are added + await pushReport(1, ETH(31)) - const newTotalShares = await token.getTotalShares() - assertBn(newTotalShares, awaitingTotalShares, `total shares don't change on no reward`) + assertBn(await token.getTotalShares(), shares(33), + 'Total shares stay the same because no fee shares are added') - // Total pooled Ether decreased + assertBn(await pool.getTotalPooledEther(), ETH(32), 'Total pooled Ether decreased') - const newTotalPooledEther = await pool.getTotalPooledEther() - assertBn(newTotalPooledEther, balanceReported, 'total pooled ether equals the reported balance') - - // Ether2 stat reported by the pool changed correspondingly - - const ether2Stat = await pool.getBeaconStat() - assertBn(ether2Stat.depositedValidators, 1, 'deposited ether2') - assertBn(ether2Stat.beaconBalance, balanceReported, 'remote ether2 balance equals the reported value') + const clStat = await pool.getBeaconStat() + assertBn(clStat.depositedValidators, 1, 'validators count') + assertBn(clStat.beaconBalance, ETH(31), 'Ether2 stat reported by the pool changed correspondingly') - // Buffered Ether amount didn't change + assertBn(await pool.getBufferedEther(), ETH(1), 'Initial stake remains in the buffer') + assertBn(await token.totalSupply(), StETH(32), 'Token total supply penalized') - assertBn(await pool.getBufferedEther(), ETH(0), 'buffered ether') + assertBn(await token.sharesOf(user1), shares(32), "User1 still holds 32 shares") + expectedUser1Balance = bn(shares(32)).muln(32).divn(33) // 32/33 ETH/share is a new price + assertBn(await token.balanceOf(user1), expectedUser1Balance, `Token user balances decreased`) - // Total supply accounts for penalties taken by the validator - assertBn(await token.totalSupply(), tokens(31), 'token total supply') - - // Token user balances decreased - assertBn(await token.balanceOf(user1), awaitingUser1Balance, `user1 balance decreased`) - - // No fees distributed yet - assertBn(await token.balanceOf(treasuryAddr), new BN(0), 'treasury tokens') - assertBn(await token.balanceOf(nodeOperator1.address), new BN(0), 'operator_1 tokens') + assertBn(await token.balanceOf(treasuryAddr), 0, 'No fees distributed yet: treasury') + assertBn(await token.balanceOf(nodeOperator1.address), 0, 'No fees distributed yet: operator_1') }) - it('the oracle reports balance loss on Ethereum2 side', async () => { - // Total shares are equal to deposited eth before ratio change and fee mint - assertBn(await token.getTotalShares(), awaitingTotalShares, 'old total shares') - - // Old total pooled Ether - - const oldTotalPooledEther = await pool.getTotalPooledEther() - assertBn(oldTotalPooledEther, ETH(31), 'old total pooled ether') - - const balanceReported = ETH(29) - awaitingUser1Balance = new BN(balanceReported) + it('the oracle reports balance loss on CL side', async () => { + assertBn(await token.getTotalShares(), shares(33), + 'Total shares are equal to deposited eth before ratio change and fee mint') + assertBn(await pool.getTotalPooledEther(), ETH(32), + 'Old total pooled Ether 31 ETH od previous report + 1 ETH initial') // Reporting 2 ETH balance loss (31 => 29) - await pushReport(1, balanceReported) - - // Total shares stay the same because no fee shares are added + await pushReport(1, ETH(29)) - const newTotalShares = await token.getTotalShares() - assertBn(newTotalShares, awaitingTotalShares, `total shares don't change without rewards`) - - // Total pooled Ether decreased - - const newTotalPooledEther = await pool.getTotalPooledEther() - assertBn(newTotalPooledEther, balanceReported, 'new total pooled ether') - - // Ether2 stat reported by the pool changed correspondingly + assertBn(await token.getTotalShares(), shares(33), + `Total shares stay the same because no fee shares are added`) + assertBn(await pool.getTotalPooledEther(), ETH(30), 'Total pooled Ether decreased') const ether2Stat = await pool.getBeaconStat() - assertBn(ether2Stat.depositedValidators, 1, 'deposited ether2') - assertBn(ether2Stat.beaconBalance, balanceReported, 'remote ether2') - - // Buffered Ether amount didn't change + assertBn(ether2Stat.depositedValidators, 1, 'deposited validators') + assertBn(ether2Stat.beaconBalance, ETH(29), 'Ether2 stat reported by the pool changed correspondingly') - assertBn(await pool.getBufferedEther(), ETH(0), 'buffered ether') + assertBn(await pool.getBufferedEther(), ETH(1), 'Buffered Ether amount didnt change') + assertBn(await token.totalSupply(), StETH(30), 'Total supply accounts for penalties taken by the validator') - // Total supply accounts for penalties taken by the validator - assertBn(await token.totalSupply(), tokens(29), 'token total supply shrunk by loss taken') + expectedUser1Balance = bn(shares(32)).muln(30).divn(33) // New share price is 30/33 ETH/share + assertBn(await token.balanceOf(user1), expectedUser1Balance, 'Token user1 balances decreased') - // Token user balances decreased - assertBn(await token.balanceOf(user1), awaitingUser1Balance, 'user1 tokens shrunk by loss taken') - - // No fees distributed yet - assertBn(await token.balanceOf(treasuryAddr), new BN(0), 'no treasury tokens on no reward') - - assertBn(await token.balanceOf(nodeOperator1.address), new BN(0), 'no operator_1 reward') + assertBn(await token.balanceOf(treasuryAddr), 0, 'No fees distributed yet: treasury') + assertBn(await token.balanceOf(nodeOperator1.address), 0, 'No fees distributed yet: operator_1') }) const nodeOperator2 = { @@ -382,10 +340,10 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { }) it('the user deposits another 32 ETH to the pool', async () => { - const depositAmount = ETH(32) - awaitingUser1Balance = awaitingUser1Balance.add(new BN(depositAmount)) - const tokenSupplyBefore = await token.totalSupply() - await web3.eth.sendTransaction({ to: pool.address, from: user1, value: depositAmount }) + assertBn(await token.totalSupply(), StETH(30), 'token total supply before') + assertBn(await token.getTotalShares(), shares(33), 'token total supply before') + + await web3.eth.sendTransaction({ to: pool.address, from: user1, value: ETH(32) }) const block = await waitBlocks(await depositSecurityModule.getMinDepositBlockDistance()) const keysOpIndex = await nodeOperatorsRegistry.getKeysOpIndex() const signatures = [ @@ -418,68 +376,49 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { assertBn(ether2Stat.depositedValidators, 2, 'deposited ether2') assertBn(ether2Stat.beaconBalance, ETH(29), 'remote ether2 as reported last time') - // All Ether was buffered within the pool contract atm + assertBn(await pool.getBufferedEther(), ETH(1), 'Only initial ether is in the buffer') + assertBn(await pool.getTotalPooledEther(), ETH(62), 'total pooled ether') + assertBn(await token.totalSupply(), StETH(62), 'token total supply') - assertBn(await pool.getBufferedEther(), ETH(0), 'buffered ether') - assertBn(await pool.getTotalPooledEther(), ETH(61), 'total pooled ether') + // 32 ETH deposit to shares if price is 30/33 ETH/shares + const sharesAdded = bn(ETH(32)).mul(bn(ETH(33))).div(bn(shares(30))) + expectedUser1Shares = bn(expectedUser1Shares).add(sharesAdded) + assertBn(await token.sharesOf(user1), expectedUser1Shares, "User1 acquires new shares by new share price") + assertBn(await token.getTotalShares(), bn(shares(1)).add(expectedUser1Shares), 'total shares are changed proportionally') - // The amount of tokens corresponding to the deposited ETH value was minted to the user - - assertBn(await token.balanceOf(user1), awaitingUser1Balance, 'user1 tokens') - - assertBn(await token.totalSupply(), tokens(61), 'token total supply') - - const oldShares = awaitingTotalShares - const newDeposit = new BN(depositAmount) - const sharesAdded = newDeposit.mul(oldShares).div(tokenSupplyBefore) - awaitingTotalShares = awaitingTotalShares.add(sharesAdded) - assertBn(await token.getTotalShares(), new BN(depositAmount).add(sharesAdded), 'total shares are changed proportionally') - assertBn(await token.balanceOf(user1), awaitingUser1Balance, `user1 balance increased by deposited ETH`) + expectedUser1Balance = bn(expectedUser1Balance).add(bn(StETH(32))) + assertBn(await token.balanceOf(user1), expectedUser1Balance, 'user1 tokens') }) it('the oracle reports balance loss for the third time', async () => { - // Old total pooled Ether - const oldTotalPooledEther = await pool.getTotalPooledEther() - assertBn(oldTotalPooledEther, ETH(61), 'old total pooled ether') - - const lossReported = ETH(1) - awaitingUser1Balance = awaitingUser1Balance.sub(new BN(lossReported)) + assertBn(await pool.getTotalPooledEther(), ETH(62), 'Old total pooled Ether') + const expectedTotalShares = bn(shares(1)).add(bn(expectedUser1Shares)) + assertBn(await token.getTotalShares(), expectedTotalShares, 'Old total shares') // Reporting 1 ETH balance loss ( total pooled 61 => 60) - await pushReport(1, ETH(28)) - // Total shares stay the same because no fee shares are added - - const newTotalShares = await token.getTotalShares() - assertBn(newTotalShares, awaitingTotalShares, `total shares don't change on no reward`) - - // Total pooled Ether decreased - - const newTotalPooledEther = await pool.getTotalPooledEther() - assertBn(newTotalPooledEther, ETH(60), 'new total pooled ether') - - // Ether2 stat reported by the pool changed correspondingly + assertBn(await token.getTotalShares(), bn(shares(1)).add(expectedUser1Shares), + 'Total shares stay the same because no fee shares are added') + assertBn(await pool.getTotalPooledEther(), ETH(61), 'Total pooled Ether decreased') const ether2Stat = await pool.getBeaconStat() - assertBn(ether2Stat.depositedValidators, 2, 'deposited ether2') - assertBn(ether2Stat.beaconBalance, ETH(28), 'remote ether2') - - // Buffered Ether amount didn't change - - assertBn(await pool.getBufferedEther(), ETH(0), 'buffered ether') - - // Total supply accounts for penalties taken by the validator - assertBn(await token.totalSupply(), tokens(60), 'token total supply shrunk by loss taken') - - // Token user balances decreased - assertBn(await token.balanceOf(user1), awaitingUser1Balance, 'user1 tokens shrunk by loss taken') - - // No fees distributed yet - assertBn(await token.balanceOf(treasuryAddr), new BN(0), 'no treasury tokens on no reward') - - assertBn(await token.balanceOf(nodeOperator1.address), new BN(0), 'no operator_1 reward') - assertBn(await token.balanceOf(user1), ETH(60), `user1 balance decreased by lost ETH`) + assertBn(ether2Stat.depositedValidators, 2, 'Another validator is deposited') + assertBn(ether2Stat.beaconBalance, ETH(28), 'Ether2 stat reported by the pool changed correspondingly') + + assertBn(await pool.getBufferedEther(), ETH(1), 'Only initial ETH in the buffer') + assertBn(await pool.getTotalPooledEther(), ETH(61), 'Total pooled Ether') + assertBn(await token.totalSupply(), StETH(61), 'token total supply shrunk by loss taken') + assertBn(await token.getTotalShares(), expectedTotalShares, 'total shares stays same') + + assertBn(await token.sharesOf(user1), expectedUser1Shares, 'User1 shares stays same') + expectedUser1Balance = bn(expectedUser1Shares) // New price + .mul(bn(StETH(61))) + .div(expectedTotalShares) + assertBn(await token.balanceOf(user1), expectedUser1Balance, 'Token user balances decreased') + + assertBn(await token.balanceOf(treasuryAddr), 0, 'No fees distributed yet: treasury') + assertBn(await token.balanceOf(nodeOperator1.address), 0, 'No fees distributed yet: operator_1') }) it(`the oracle can't report less validators than previously`, async () => { @@ -487,11 +426,11 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { }) it(`user deposits another 32 ETH to the pool`, async () => { - const totalPooledEther = await pool.getTotalPooledEther() - const depositAmount = ETH(32) - awaitingTotalShares = awaitingTotalShares.add(new BN(depositAmount).mul(awaitingTotalShares).div(totalPooledEther)) - awaitingUser1Balance = awaitingUser1Balance.add(new BN(depositAmount)) - await web3.eth.sendTransaction({ to: pool.address, from: user1, value: depositAmount }) + assertBn(await pool.getTotalPooledEther(), ETH(61), 'Old total pooled Ether') + const oldTotalShares = bn(shares(1)).add(bn(expectedUser1Shares)) + assertBn(await token.getTotalShares(), oldTotalShares, 'Old total shares') + + await web3.eth.sendTransaction({ to: pool.address, from: user1, value: ETH(32) }) await hre.network.provider.send("hardhat_mine", ['0x100']) @@ -521,22 +460,25 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { const ether2Stat = await pool.getBeaconStat() assertBn(ether2Stat.depositedValidators, 2, 'no validators have received the current deposit') - // The amount of tokens corresponding to the deposited ETH value was minted to the user - - assertBn(await token.balanceOf(user1), awaitingUser1Balance, 'user1 tokens') + assertBn(await pool.getBufferedEther(), ETH(33), '33 ETH is pooled') + assertBn(await pool.getTotalPooledEther(), ETH(93), 'Total pooled Ether') + assertBn(await token.totalSupply(), StETH(93), 'token total supply') - assertBn(await token.totalSupply(), tokens(92), 'token total supply') - // Total shares are equal to deposited eth before ratio change and fee mint - assertBn(await token.getTotalShares(), awaitingTotalShares, 'total shares') + const sharesAdded = bn(ETH(32)).mul(oldTotalShares).div(bn(ETH(61))) + assertBn(await token.getTotalShares(), oldTotalShares.add(sharesAdded), + 'Total shares are equal to deposited eth before ratio change and fee mint') - // All Ether was buffered within the pool contract atm - assertBn(await pool.getBufferedEther(), ETH(32), `32 ETH is pooled`) + expectedUser1Shares = bn(expectedUser1Shares).add(sharesAdded) + assertBn(await token.sharesOf(user1), expectedUser1Shares, "User1 bought shares on 32 ETH") + expectedUser1Balance = expectedUser1Balance.add(bn(StETH(32))) + assertBn(await token.balanceOf(user1), expectedUser1Balance, + 'The amount of tokens corresponding to the deposited ETH value was minted to the user') }) it(`voting stops the staking module`, async () => { await stakingRouter.setStakingModuleStatus(1, 2, { from: voting }) - assertBn(await stakingRouter.getStakingModulesCount(), new BN(1), 'only 1 module exists') - assertBn(await stakingRouter.getStakingModuleStatus(1), new BN(2), 'no active staking modules') + assertBn(await stakingRouter.getStakingModulesCount(), 1, 'only 1 module exists') + assertBn(await stakingRouter.getStakingModuleStatus(1), 2, 'no active staking modules') }) it(`first operator adds a second validator`, async () => { @@ -564,15 +506,15 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { const activeOperatorsBefore = await nodeOperatorsRegistry.getActiveNodeOperatorsCount() await nodeOperatorsRegistry.deactivateNodeOperator(0, { from: voting }) const activeOperatorsAfter = await nodeOperatorsRegistry.getActiveNodeOperatorsCount() - assertBn(activeOperatorsAfter, activeOperatorsBefore.sub(new BN(1)), 'deactivated one operator') + assertBn(activeOperatorsAfter, activeOperatorsBefore.subn(1), 'deactivated one operator') }) it(`voting stops the second operator`, async () => { const activeOperatorsBefore = await nodeOperatorsRegistry.getActiveNodeOperatorsCount() await nodeOperatorsRegistry.deactivateNodeOperator(1, { from: voting }) const activeOperatorsAfter = await nodeOperatorsRegistry.getActiveNodeOperatorsCount() - assertBn(activeOperatorsAfter, activeOperatorsBefore.sub(new BN(1)), 'deactivated one operator') - assertBn(activeOperatorsAfter, new BN(0), 'no active operators') + assertBn(activeOperatorsAfter, activeOperatorsBefore.subn(1), 'deactivated one operator') + assertBn(activeOperatorsAfter, 0, 'no active operators') }) it(`without active staking modules fee is sent to treasury`, async () => { @@ -602,8 +544,8 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { assertBn(nodeOperator2TokenSharesAfter, nodeOperator2TokenSharesBefore, `second node operator hasn't got fees`) assertBn(nodeOperatorsRegistrySharesAfter, nodeOperatorsRegistrySharesBefore, `NOR stakingModule hasn't got fees`) - const tenKBN = new BN(10000) - const totalFeeToDistribute = new BN(beaconBalanceIncrement.toString()).mul(new BN(totalFeePoints)).div(tenKBN) + const tenKBN = bn(10000) + const totalFeeToDistribute = bn(beaconBalanceIncrement.toString()).mul(bn(totalFeePoints)).div(tenKBN) const totalPooledEther = await pool.getTotalPooledEther() let sharesToMint = totalFeeToDistribute @@ -617,8 +559,8 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { it(`voting starts staking module`, async () => { await stakingRouter.setStakingModuleStatus(1, 0, { from: voting }) - assertBn(await stakingRouter.getStakingModulesCount(), new BN(1), 'only 1 module exists') - assertBn(await stakingRouter.getStakingModuleStatus(1), new BN(0), 'no active staking modules') + assertBn(await stakingRouter.getStakingModulesCount(), 1, 'only 1 module exists') + assertBn(await stakingRouter.getStakingModuleStatus(1), 0, 'no active staking modules') }) it(`oracle reports profit, previously stopped staking module gets the fee`, async () => { From 97c132aca7cdf8decbe475c11e31c1e25472c715 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Wed, 15 Feb 2023 15:07:28 +0200 Subject: [PATCH 045/199] chore: remove forgotten .only --- test/scenario/lido_penalties_slashing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/scenario/lido_penalties_slashing.js b/test/scenario/lido_penalties_slashing.js index 214207d7e..34d36a78b 100644 --- a/test/scenario/lido_penalties_slashing.js +++ b/test/scenario/lido_penalties_slashing.js @@ -14,7 +14,7 @@ const { DSMAttestMessage, DSMPauseMessage, signDepositData } = require('../helpe const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistry') -contract.only('Lido: penalties, slashing, operator stops', (addresses) => { +contract('Lido: penalties, slashing, operator stops', (addresses) => { const [ // node operators operator_1, From c1b8e584c7d5fd6c6b20c81f998d53af643eb73a Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Wed, 15 Feb 2023 20:21:36 +0700 Subject: [PATCH 046/199] =?UTF-8?q?test:=20AccountingOracle.submitReportEx?= =?UTF-8?q?traDataList=20enforces=20data=20safety=20boundaries=20=E2=80=94?= =?UTF-8?q?=20InvalidExtraDataItem=20cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ng-oracle-submit-report-extra-data.test.js | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 6c5fbf6d3..3704e8917 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -375,6 +375,85 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) }) }) + + context('checks for InvalidExtraDataItem reverts', () => { + it('reverts if some item not long enough to contain all necessary data — early cut', async () => { + const invalidItemIndex = 1 + const extraData = { + stuckKeys: [ + { moduleId: 1, nodeOpIds: [1], keysCounts: [2] }, + { moduleId: 2, nodeOpIds: [1], keysCounts: [2] } + ], + exitedKeys: [] + } + const extraDataItems = encodeExtraDataItems(extraData) + // Cutting item to provoke error on early stage + // of `_processExtraDataItem` function, check on 776 line in AccountingOracle + const cutStop = 36 + extraDataItems[invalidItemIndex] = extraDataItems[invalidItemIndex].slice(0, cutStop) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `InvalidExtraDataItem(${invalidItemIndex})` + ) + }) + + it('reverts if some item not long enough to contain all necessary data — late cut', async () => { + const invalidItemIndex = 1 + const extraData = { + stuckKeys: [ + { moduleId: 1, nodeOpIds: [1], keysCounts: [2] }, + { moduleId: 2, nodeOpIds: [1, 2, 3, 4], keysCounts: [2] } + ], + exitedKeys: [] + } + const extraDataItems = encodeExtraDataItems(extraData) + // Providing long items and cutting them from end to provoke error on late stage + // of `_processExtraDataItem` function, check on 812 line in AccountingOracle, first condition + const cutStop = extraDataItems[invalidItemIndex].length - 2 + extraDataItems[invalidItemIndex] = extraDataItems[invalidItemIndex].slice(0, cutStop) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `InvalidExtraDataItem(${invalidItemIndex})` + ) + }) + + it('moduleId cannot be zero', async () => { + const invalidItemIndex = 1 + const extraData = { + stuckKeys: [ + { moduleId: 1, nodeOpIds: [1], keysCounts: [2] }, + { moduleId: 0, nodeOpIds: [1], keysCounts: [2] } + ], + exitedKeys: [] + } + const { extraDataList } = await prepareNextReportInNextFrame({ extraData }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `InvalidExtraDataItem(${invalidItemIndex})` + ) + }) + + it('checks node ops count to be non-zero', async () => { + const invalidItemIndex = 0 + // Empty nodeOpIds list should provoke check fail + // in `_processExtraDataItem` function, 812 line in AccountingOracle, second condition + const extraData = { + stuckKeys: [ + { moduleId: 1, nodeOpIds: [], keysCounts: [2] }, + { moduleId: 2, nodeOpIds: [1], keysCounts: [2] } + ], + exitedKeys: [] + } + const extraDataItems = encodeExtraDataItems(extraData) + const { extraDataList } = await prepareNextReportInNextFrame({ extraData, extraDataItems }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `InvalidExtraDataItem(${invalidItemIndex})` + ) + }) + }) }) context('delivers the data to staking router', () => { From 3e2fbd1fab3c7d8e2135c476fdea8d099d1bf254 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Wed, 15 Feb 2023 20:59:27 +0700 Subject: [PATCH 047/199] test: AccountingOracle.submitReportExtraDataList should cueck node operators count with OracleReportSanityChecker --- ...ng-oracle-submit-report-extra-data.test.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 3704e8917..3a7c49b55 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -49,12 +49,14 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra let oracle = null let oracleVersion = null let stakingRouter = null + let oracleReportSanityChecker = null const deploy = async (options = undefined) => { const deployed = await deployAndConfigureAccountingOracle(admin) oracle = deployed.oracle consensus = deployed.consensus stakingRouter = deployed.stakingRouter + oracleReportSanityChecker = deployed.oracleReportSanityChecker oracleVersion = +(await oracle.getContractVersion()) await consensus.addMember(member1, 1, { from: admin }) } @@ -376,6 +378,36 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) }) + context('should check node operators processing limits with OracleReportSanityChecker', () => { + it('by reverting TooManyNodeOpsPerExtraDataItem if there was too much node operators', async () => { + const problematicItemIdx = 0 + const extraData = { + stuckKeys: [{ moduleId: 1, nodeOpIds: [1, 2], keysCounts: [2, 3] }], + exitedKeys: [] + } + const problematicItemsCount = extraData.stuckKeys[problematicItemIdx].nodeOpIds.length + const { extraDataList } = await prepareNextReportInNextFrame({ extraData }) + await oracleReportSanityChecker.setMaxAccountingExtraDataListItemsCount(problematicItemsCount - 1) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `TooManyNodeOpsPerExtraDataItem(${problematicItemIdx}, ${problematicItemsCount})` + ) + }) + + it('should not revert in case when items count exactly equals limit', async () => { + const problematicItemIdx = 0 + const extraData = { + stuckKeys: [{ moduleId: 1, nodeOpIds: [1, 2], keysCounts: [2, 3] }], + exitedKeys: [] + } + const problematicItemsCount = extraData.stuckKeys[problematicItemIdx].nodeOpIds.length + const { extraDataList, reportFields } = await prepareNextReportInNextFrame({ extraData }) + await oracleReportSanityChecker.setMaxAccountingExtraDataListItemsCount(problematicItemsCount) + const tx = await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) + }) + }) + context('checks for InvalidExtraDataItem reverts', () => { it('reverts if some item not long enough to contain all necessary data — early cut', async () => { const invalidItemIndex = 1 From 0023e4b67b4ece7764b682cec20f25d8b5ca014c Mon Sep 17 00:00:00 2001 From: Artyom Veremeenko Date: Wed, 15 Feb 2023 18:56:57 +0400 Subject: [PATCH 048/199] ValidatorExitBusOracle: add pauser and resumer to initialize() --- contracts/0.8.9/WithdrawalQueue.sol | 3 +-- contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol | 8 ++++++-- contracts/0.8.9/utils/PausableUntil.sol | 4 ---- lib/abi/ValidatorsExitBusOracle.json | 2 +- .../oracle/validators-exit-bus-oracle-deploy.test.js | 4 ++++ 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index b39d57215..d0de7d890 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -326,7 +326,7 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit internal { _initializeQueue(); - _initializePausable(); + _pause(PAUSE_INFINITELY); _initializeContractVersionTo(1); @@ -336,7 +336,6 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit _grantRole(FINALIZE_ROLE, _finalizer); _grantRole(BUNKER_MODE_REPORT_ROLE, _bunkerReporter); - RESUME_SINCE_TIMESTAMP_POSITION.setStorageUint256(PAUSE_INFINITELY); // pause it explicitly BUNKER_MODE_SINCE_TIMESTAMP_POSITION.setStorageUint256(BUNKER_MODE_DISABLED_TIMESTAMP); emit InitializedV1(_admin, _pauser, _resumer, _finalizer, msg.sender); diff --git a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol index 9ac99f019..f4ab43871 100644 --- a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol +++ b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol @@ -92,15 +92,19 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil { function initialize( address admin, + address pauser, + address resumer, address consensusContract, uint256 consensusVersion, uint256 lastProcessingRefSlot ) external { if (admin == address(0)) revert AdminCannotBeZero(); _setupRole(DEFAULT_ADMIN_ROLE, admin); - _initializePausable(); + _grantRole(PAUSE_ROLE, pauser); + _grantRole(RESUME_ROLE, resumer); + + _pause(PAUSE_INFINITELY); _initialize(consensusContract, consensusVersion, lastProcessingRefSlot); - RESUME_SINCE_TIMESTAMP_POSITION.setStorageUint256(PAUSE_INFINITELY); // pause it explicitly } /// @notice Resume accepting validator exit requests diff --git a/contracts/0.8.9/utils/PausableUntil.sol b/contracts/0.8.9/utils/PausableUntil.sol index b4aff4e93..3bbd1b570 100644 --- a/contracts/0.8.9/utils/PausableUntil.sol +++ b/contracts/0.8.9/utils/PausableUntil.sol @@ -43,10 +43,6 @@ contract PausableUntil { return block.timestamp < RESUME_SINCE_TIMESTAMP_POSITION.getStorageUint256(); } - function _initializePausable() internal { - emit Paused(PAUSE_INFINITELY); - } - function _resume() internal { RESUME_SINCE_TIMESTAMP_POSITION.setStorageUint256(block.timestamp); diff --git a/lib/abi/ValidatorsExitBusOracle.json b/lib/abi/ValidatorsExitBusOracle.json index 40656d47b..7ac4b56fb 100644 --- a/lib/abi/ValidatorsExitBusOracle.json +++ b/lib/abi/ValidatorsExitBusOracle.json @@ -1 +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":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidRequestsData","type":"error"},{"inputs":[],"name":"InvalidRequestsDataLength","type":"error"},{"inputs":[],"name":"InvalidRequestsDataSortOrder","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ProcessingDeadlineMissed","type":"error"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"ResumedExpected","type":"error"},{"inputs":[],"name":"SenderNotAllowed","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":[],"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":"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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"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":"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":[],"name":"getLastProcessingRefSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256[]","name":"nodeOpIds","type":"uint256[]"}],"name":"getLastRequestedValidatorIndices","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"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":[{"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"}],"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":"pause","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":"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":"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"}] \ No newline at end of file +[{"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":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidRequestsData","type":"error"},{"inputs":[],"name":"InvalidRequestsDataLength","type":"error"},{"inputs":[],"name":"InvalidRequestsDataSortOrder","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ProcessingDeadlineMissed","type":"error"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"ResumedExpected","type":"error"},{"inputs":[],"name":"SenderNotAllowed","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":[],"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":"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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"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":"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":[],"name":"getLastProcessingRefSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256[]","name":"nodeOpIds","type":"uint256[]"}],"name":"getLastRequestedValidatorIndices","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"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":[{"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":"pauser","type":"address"},{"internalType":"address","name":"resumer","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"lastProcessingRefSlot","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":"pause","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":"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":"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"}] \ No newline at end of file diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js index afac6493f..8a6c3eb47 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js @@ -81,6 +81,8 @@ async function deployExitBusOracle(admin, { dataSubmitter = null, lastProcessingRefSlot = 0, resumeAfterDeploy = false, + pauser = ZERO_ADDRESS, + resumer = ZERO_ADDRESS, } = {}) { const locator = (await deployLocatorWithDummyAddressesImplementation(admin)).address @@ -100,6 +102,8 @@ async function deployExitBusOracle(admin, { const tx = await oracle.initialize( admin, + pauser, + resumer, consensus.address, CONSENSUS_VERSION, lastProcessingRefSlot, From 542f849a0b935e6583a803d238b1c477c8872b19 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Wed, 15 Feb 2023 21:35:54 +0300 Subject: [PATCH 049/199] feat: pub getter for the eip712 steth helper --- contracts/0.4.24/StETHPermit.sol | 8 ++++---- lib/abi/Lido.json | 2 +- lib/abi/StETHPermit.json | 2 +- test/0.4.24/stethpermit.test.js | 10 +++++++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/contracts/0.4.24/StETHPermit.sol b/contracts/0.4.24/StETHPermit.sol index 092137285..1c2ef1f40 100644 --- a/contracts/0.4.24/StETHPermit.sol +++ b/contracts/0.4.24/StETHPermit.sol @@ -100,7 +100,7 @@ contract StETHPermit is IERC2612, StETH { abi.encode(PERMIT_TYPEHASH, _owner, _spender, _value, _useNonce(_owner), _deadline) ); - bytes32 hash = IEIP712(_getEIP712StETH()).hashTypedDataV4(structHash); + bytes32 hash = IEIP712(getEIP712StETH()).hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, _v, _r, _s); require(signer == _owner, "ERC20Permit: invalid signature"); @@ -124,7 +124,7 @@ contract StETHPermit is IERC2612, StETH { */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32) { - return IEIP712(_getEIP712StETH()).domainSeparatorV4(); + return IEIP712(getEIP712StETH()).domainSeparatorV4(); } /** @@ -140,7 +140,7 @@ contract StETHPermit is IERC2612, StETH { */ function _initializeEIP712StETH(address _eip712StETH) internal { require(_eip712StETH != address(0), "StETHPermit: zero eip712StETH"); - require(_getEIP712StETH() == address(0), "StETHPermit: eip712StETH already set"); + require(getEIP712StETH() == address(0), "StETHPermit: eip712StETH already set"); EIP712_STETH_POSITION.setStorageAddress(_eip712StETH); @@ -150,7 +150,7 @@ contract StETHPermit is IERC2612, StETH { /** * @dev Get EIP712 message utils contract */ - function _getEIP712StETH() internal view returns (address) { + function getEIP712StETH() public view returns (address) { return EIP712_STETH_POSITION.getStorageAddress(); } } diff --git a/lib/abi/Lido.json b/lib/abi/Lido.json index 7d0de5b65..f7b9bbbec 100644 --- a/lib/abi/Lido.json +++ b/lib/abi/Lido.json @@ -1 +1 @@ -[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_clValidators","type":"uint256"},{"name":"_clBalance","type":"uint256"},{"name":"_withdrawalVaultBalance","type":"uint256"},{"name":"_elRewardsVaultBalance","type":"uint256"},{"name":"_lastFinalizableRequestId","type":"uint256"},{"name":"_simulatedShareRate","type":"uint256"}],"name":"handleOracleReport","outputs":[{"name":"postTotalPooledEther","type":"uint256"},{"name":"postTotalShares","type":"uint256"},{"name":"withdrawals","type":"uint256"},{"name":"elRewards","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"receiveStakingRouterDepositRemainder","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"totalFee","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getDepositableEther","outputs":[{"name":"depositableEth","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"StakingRouterDepositRemainderReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}] \ No newline at end of file +[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getEIP712StETH","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_clValidators","type":"uint256"},{"name":"_clBalance","type":"uint256"},{"name":"_withdrawalVaultBalance","type":"uint256"},{"name":"_elRewardsVaultBalance","type":"uint256"},{"name":"_lastFinalizableRequestId","type":"uint256"},{"name":"_simulatedShareRate","type":"uint256"}],"name":"handleOracleReport","outputs":[{"name":"postTotalPooledEther","type":"uint256"},{"name":"postTotalShares","type":"uint256"},{"name":"withdrawals","type":"uint256"},{"name":"elRewards","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"receiveStakingRouterDepositRemainder","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"totalFee","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getDepositableEther","outputs":[{"name":"depositableEth","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"StakingRouterDepositRemainderReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}] \ No newline at end of file diff --git a/lib/abi/StETHPermit.json b/lib/abi/StETHPermit.json index 29b2631b9..9ea8f13d1 100644 --- a/lib/abi/StETHPermit.json +++ b/lib/abi/StETHPermit.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}] \ No newline at end of file +[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getEIP712StETH","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}] \ No newline at end of file diff --git a/test/0.4.24/stethpermit.test.js b/test/0.4.24/stethpermit.test.js index 62d99b28d..eaf744454 100644 --- a/test/0.4.24/stethpermit.test.js +++ b/test/0.4.24/stethpermit.test.js @@ -11,16 +11,16 @@ const EIP712StETH = artifacts.require('EIP712StETH') const StETHPermit = artifacts.require('StETHPermitMock') contract('StETHPermit', ([deployer, ...accounts]) => { - let stEthPermit, chainId, domainSeparator + let stEthPermit, eip712StETH, chainId, domainSeparator beforeEach('deploy mock token', async () => { - const eip712StETH = await EIP712StETH.new({ from: deployer }) + eip712StETH = await EIP712StETH.new({ from: deployer }) stEthPermit = await StETHPermit.new({ from: deployer }) await stEthPermit.initializeEIP712StETH(eip712StETH.address) chainId = await web3.eth.net.getId(); - domainSeparator = makeDomainSeparator('Liquid staked Ether 2.0', '2', chainId, eip712StETH.address) + domainSeparator = makeDomainSeparator('Liquid staked Ether 2.0', '2', chainId, await stEthPermit.getEIP712StETH()) }) context('permit', () => { @@ -43,6 +43,10 @@ contract('StETHPermit', ([deployer, ...accounts]) => { await stEthPermit.mintShares(permitParams.owner, initialBalance, { from: deployer }) }) + it('EIP-712 signature helper contract matches the stored one', async () => { + assert.equal(await stEthPermit.getEIP712StETH(), eip712StETH.address) + }) + it('grants allowance when a valid permit is given', async () => { const { owner, spender, deadline } = permitParams let { value } = permitParams From 53c84b89fe3c87e4aecdc999dbca94db428e1bbd Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Wed, 15 Feb 2023 23:36:44 +0300 Subject: [PATCH 050/199] test: `MAX_NODE_OPERATORS_COUNT` reward distr gas --- test/0.4.24/node-operators-registry.test.js | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index ba8ae291a..182e6307d 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -10,6 +10,8 @@ const signingKeys = require('../helpers/signing-keys') const { web3, artifacts } = require('hardhat') const { getRandomLocatorConfig } = require('../helpers/locator') const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') +const { randomBytes } = require('crypto') +const { toChecksumAddress } = require('ethereumjs-util') const IStakingModule = artifacts.require('contracts/0.8.9/interfaces/IStakingModule.sol:IStakingModule') const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistryMock') @@ -3190,6 +3192,32 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.emits(receipt, 'RewardsDistributed', { rewardAddress: user2, sharesAmount: ETH(7) }) assert.notEmits(receipt, 'RewardsDistributed', { rewardAddress: user3, sharesAmount: 0 }) }) + + it('able to distribute rewards to the `MAX_NODE_OPERATORS_COUNT` operators', async () => { + const maxNodeOperatorsCount = await app.MAX_NODE_OPERATORS_COUNT() + + function generateRandomAddress() { + return toChecksumAddress('0x' + randomBytes(20).toString('hex')) + } + + // already have three operators added + for (let i = 3; i < maxNodeOperatorsCount; ++i) { + await app.testing_addNodeOperator(`Node Operator #${i}`, generateRandomAddress(), 5, 5, 5, 0, { from: voting }) + } + assert.equals(await app.getNodeOperatorsCount(), maxNodeOperatorsCount) + + await steth.setTotalPooledEther(ETH(100)) + await steth.mintShares(app.address, ETH(10)) + + // calls distributeRewards() inside + const tx = await app.onAllValidatorCountersUpdated({ from: voting }) + + // just show the used gas + console.log(`gas used to distribute rewards for ${maxNodeOperatorsCount} NOs:`, +tx.receipt.gasUsed) + + // check that gas is lower than 10M + assert.isTrue(+tx.receipt.gasUsed < 10 * 10**6) + }) }) describe('getTotalSigningKeyCount(nodeOperatorId)', () => { From 2c083fc9a73e964f9a6110267205ff0676c471e1 Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Thu, 16 Feb 2023 01:51:32 +0400 Subject: [PATCH 051/199] Add Foundry tests for MinFirstAllocationStrategy --- foundry.toml | 2 +- foundry/skip-sol-tests-compilation.js | 42 +-- test/common/lib/mem-utils.test.sol | 15 +- ...-first-allocation-strategy.0.4.24.test.sol | 16 ++ ...n-first-allocation-strategy.0.8.9.test.sol | 16 ++ .../min-first-allocation-strategy.helpers.sol | 243 ++++++++++++++++++ 6 files changed, 286 insertions(+), 48 deletions(-) create mode 100644 test/common/lib/min-first-allocation-strategy.0.4.24.test.sol create mode 100644 test/common/lib/min-first-allocation-strategy.0.8.9.test.sol create mode 100644 test/common/lib/min-first-allocation-strategy.helpers.sol diff --git a/foundry.toml b/foundry.toml index e1d54c101..8dfa20b7c 100644 --- a/foundry.toml +++ b/foundry.toml @@ -18,4 +18,4 @@ cache = true cache_path = 'foundry/cache' # Only run tests in contracts matching the specified glob pattern -match_path = '**/test/**/*.test.sol' \ No newline at end of file +match_path = '**/test/**/*.test.sol' diff --git a/foundry/skip-sol-tests-compilation.js b/foundry/skip-sol-tests-compilation.js index 4704c865e..974d6ed1b 100644 --- a/foundry/skip-sol-tests-compilation.js +++ b/foundry/skip-sol-tests-compilation.js @@ -1,11 +1,9 @@ -const fs = require('fs') -const path = require('path') const minimatch = require('minimatch') const { subtask } = require('hardhat/config') const { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } = require('hardhat/builtin-tasks/task-names') /** - * Excludes Foundry test files from the Hardhat compilation. This step is required to avoid + * Excludes Solidity test files from the Hardhat compilation. This step is required to avoid * compilation errors when Hardhat can't find Foundry-specific solidity files. * * This function is used instead of the "hardhat-foundry" plugin because the last one is not @@ -13,42 +11,6 @@ const { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } = require('hardhat/builtin-task * reports are always empty. */ subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(async (_, __, runSuper) => { - const foundryTomlPath = path.join(__dirname, '..', 'foundry.toml') - const matchPath = parseTomlValue(readTomlValue(await readTextFile(foundryTomlPath), 'match_path')) const paths = await runSuper() - if (!matchPath) { - console.warn( - [ - 'WARNING:', - "'foundry.toml' file doesn't contain the 'match_path' property, or its value is empty.", - "If you don't use Foundry tests, the 'skip-sol-tests-compilation' subtask might be removed from hardhat.config.js" - ].join(' ') - ) - return paths - } - return paths.filter((path) => !minimatch(path, matchPath)) + return paths.filter((path) => !minimatch(path, '**/test/**/*.sol')) }) - -function readTextFile(filePath) { - return new Promise((resolve, reject) => { - fs.readFile(filePath, 'utf8', (err, data) => { - if (err) reject(err) - resolve(data) - }) - }) -} - -function readTomlValue(tomlFile, key) { - const line = tomlFile.split('\n').find((line) => line.startsWith(key)) - if (line === undefined) return null - return line.split('=')[1].trim() -} - -function parseTomlValue(value) { - // TOML allows to use both "" and '' quotes for strings - if ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"'))) { - return value.slice(1, value.length - 1) - } else { - throw new Error(`Unsupported or invalid TOML parser value: ${value}`) - } -} diff --git a/test/common/lib/mem-utils.test.sol b/test/common/lib/mem-utils.test.sol index d13db1607..8bc94713d 100644 --- a/test/common/lib/mem-utils.test.sol +++ b/test/common/lib/mem-utils.test.sol @@ -1,16 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Lido +// SPDX-License-Identifier: GPL-3.0 + pragma solidity 0.8.9; -import { MemUtils } from "contracts/common/lib/MemUtils.sol"; import "forge-std/Test.sol"; +import { MemUtils } from "contracts/common/lib/MemUtils.sol"; contract MemUtilsTestFoundry is Test { - uint256 testNumber; - - function setUp() public { - testNumber = 42; - } + /// + /// unsafeAllocateBytes + /// - function testUnsafeAlloc_allocates_empty_byte_array() external { + function test_unsafeAlloc_allocates_empty_byte_array() external { // disable all compiler optimizations by including an assembly block not marked as mem-safe assembly { mstore(0x00, 0x1) diff --git a/test/common/lib/min-first-allocation-strategy.0.4.24.test.sol b/test/common/lib/min-first-allocation-strategy.0.4.24.test.sol new file mode 100644 index 000000000..b59740113 --- /dev/null +++ b/test/common/lib/min-first-allocation-strategy.0.4.24.test.sol @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2023 Lido +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity 0.4.24; + +import { MinFirstAllocationStrategyFuzzTesting, MinFirstAllocationStrategyAllocateTestWrapper} from "./min-first-allocation-strategy.helpers.sol"; +import {MinFirstAllocationStrategy} from "contracts/common/lib/MinFirstAllocationStrategy.sol"; + +/// @dev this contract is required to make Foundry invariants testing work +contract MinFirstAllocationStrategyAllocateTestWrapper_0_4_24 is MinFirstAllocationStrategyAllocateTestWrapper {} + +contract MinFirstAllocationStrategyFuzzTesting_0_4_24 is MinFirstAllocationStrategyFuzzTesting { + function setUp() external { + testWrapper = new MinFirstAllocationStrategyAllocateTestWrapper_0_4_24(); + } +} diff --git a/test/common/lib/min-first-allocation-strategy.0.8.9.test.sol b/test/common/lib/min-first-allocation-strategy.0.8.9.test.sol new file mode 100644 index 000000000..cdafa0c26 --- /dev/null +++ b/test/common/lib/min-first-allocation-strategy.0.8.9.test.sol @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2023 Lido +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity 0.8.9; + +import { MinFirstAllocationStrategyFuzzTesting, MinFirstAllocationStrategyAllocateTestWrapper} from "./min-first-allocation-strategy.helpers.sol"; +import {MinFirstAllocationStrategy} from "contracts/common/lib/MinFirstAllocationStrategy.sol"; + +/// @dev this contract is required to make Foundry invariants testing work +contract MinFirstAllocationStrategyAllocateTestWrapper_0_8_9 is MinFirstAllocationStrategyAllocateTestWrapper {} + +contract MinFirstAllocationStrategyFuzzTesting_0_8_9 is MinFirstAllocationStrategyFuzzTesting { + function setUp() external { + testWrapper = new MinFirstAllocationStrategyAllocateTestWrapper_0_8_9(); + } +} diff --git a/test/common/lib/min-first-allocation-strategy.helpers.sol b/test/common/lib/min-first-allocation-strategy.helpers.sol new file mode 100644 index 000000000..e10748a9f --- /dev/null +++ b/test/common/lib/min-first-allocation-strategy.helpers.sol @@ -0,0 +1,243 @@ +// SPDX-FileCopyrightText: 2023 Lido +// SPDX-License-Identifier: GPL-3.0 + +// solhint-disable-next-line +pragma solidity >=0.4.24 <0.9.0; + +import {console2} from "forge-std/console2.sol"; + +import {Math256} from "contracts/common/lib/Math256.sol"; +import {MinFirstAllocationStrategy} from "contracts/common/lib/MinFirstAllocationStrategy.sol"; + +contract MinFirstAllocationStrategyFuzzTesting { + uint256 private constant MAX_BUCKETS_COUNT = 32; + uint256 private constant MAX_BUCKET_VALUE = 8192; + uint256 private constant MAX_CAPACITY_VALUE = 8192; + uint256 private constant MAX_ALLOCATION_SIZE = 1024; + + MinFirstAllocationStrategyTestWrapper internal testWrapper; + + function invariant_allocated_output() external view { + (, , uint256 allocatedActual) = testWrapper.getActualOutput(); + (, , uint256 allocatedExpected) = testWrapper.getExpectedOutput(); + _assertAllocated(allocatedExpected, allocatedActual); + } + + function invariant_buckets_output() external view { + (uint256[] memory bucketsActual, , ) = testWrapper.getActualOutput(); + (uint256[] memory bucketsExpected, , ) = testWrapper.getExpectedOutput(); + _assertBucketsAllocation(bucketsExpected, bucketsActual); + } + + function invariant_allocated_bucket_values_not_exceed_capacities() external view { + (uint256[] memory inputBuckets, uint256[] memory inputCapacities, ) = testWrapper.getInput(); + (uint256[] memory buckets, uint256[] memory capacities, ) = testWrapper.getActualOutput(); + for (uint256 i = 0; i < buckets.length; ++i) { + // when bucket initially overloaded skip it from the check + if (inputBuckets[i] > inputCapacities[i]) continue; + if (buckets[i] > capacities[i]) { + console2.log("Bucket value exceeds capacity"); + console2.log("bucket index: ", i); + console2.log("bucket value:", buckets[i]); + console2.log("capacity value:", capacities[i]); + revert("BUCKET_VALUE_EXCEEDS_CAPACITY"); + } + } + } + + // invariant 5. the sum of new allocation minus the sum of prev allocation equal to distributed + function invariant_allocated_matches_bucket_changes() external view { + (uint256[] memory inputBuckets, , ) = testWrapper.getInput(); + (uint256[] memory buckets, , uint256 allocated) = testWrapper.getActualOutput(); + uint256 inputSum = 0; + uint256 outputSum = 0; + for (uint256 i = 0; i < buckets.length; ++i) { + inputSum += inputBuckets[i]; + outputSum += buckets[i]; + } + if (outputSum != inputSum + allocated) { + console2.log("Sum of all buckets is incorrect"); + console2.log("expected buckets sum:", inputSum + allocated); + console2.log("actual buckets sum:", outputSum); + revert("INVALID_BUCKETS_SUM"); + } + } + + function invariant_allocated_less_then_allocation_size_only_when_all_buckets_filled() external view { + (, , uint256 allocationSize) = testWrapper.getInput(); + (uint256[] memory buckets, uint256[] memory capacities , uint256 allocated) = testWrapper.getActualOutput(); + if (allocationSize == allocated) return; + for (uint256 i = 0; i < buckets.length; ++i) { + if (buckets[i] < capacities[i]) { + console2.log("The bucket is unfilled"); + console2.log("bucket index:", i); + console2.log("bucket value:", buckets[i]); + console2.log("bucket capacity:", capacities[i]); + revert("BUCKET_IS_UNFILLED"); + } + } + } + + function _assertAllocated(uint256 _expected, uint256 _actual) internal view { + if (_expected != _actual) { + console2.log("Invalid allocated value"); + console2.log("expected allocated value: ", _expected); + console2.log("actual allocated value:", _actual); + revert("INVALID_ALLOCATED_VALUE"); + } + } + + function _assertBucketsAllocation(uint256[] memory _expected, uint256[] memory _actual) internal view { + for (uint256 i = 0; i < _expected.length; ++i) { + if (_expected[i] != _actual[i]) { + console2.log("Invalid bucket value after allocation:"); + console2.log("bucket index:", i); + console2.log("expected bucket value:", _expected[i]); + console2.log("actual bucket value:", _actual[i]); + revert("INVALID_ALLOCATED_VALUE"); + } + } + } +} + +contract MinFirstAllocationStrategyTestWrapper { + uint256 public constant MAX_BUCKETS_COUNT = 32; + uint256 public constant MAX_BUCKET_VALUE = 8192; + uint256 public constant MAX_CAPACITY_VALUE = 8192; + uint256 public constant MAX_ALLOCATION_SIZE = 1024; + + struct TestInput { + uint256[] buckets; + uint256[] capacities; + uint256 allocationSize; + } + + struct TestOutput { + uint256[] buckets; + uint256[] capacities; + uint256 allocated; + } + + TestInput internal _input; + TestOutput internal _actual; + TestOutput internal _expected; + + function getInput() + external + view + returns ( + uint256[] memory buckets, + uint256[] memory capacities, + uint256 allocationSize + ) + { + buckets = _input.buckets; + capacities = _input.capacities; + allocationSize = _input.allocationSize; + } + + function getExpectedOutput() + external + view + returns ( + uint256[] memory buckets, + uint256[] memory capacities, + uint256 allocated + ) + { + buckets = _expected.buckets; + capacities = _expected.capacities; + allocated = _expected.allocated; + } + + function getActualOutput() + external + view + returns ( + uint256[] memory buckets, + uint256[] memory capacities, + uint256 allocated + ) + { + buckets = _actual.buckets; + capacities = _actual.capacities; + allocated = _actual.allocated; + } + + function _fillTestInput( + uint256[] memory _fuzzBuckets, + uint256[] memory _fuzzCapacities, + uint256 _fuzzAllocationSize + ) internal { + uint256 bucketsCount = Math256.min(_fuzzBuckets.length, _fuzzCapacities.length) % MAX_BUCKETS_COUNT; + _input.buckets = new uint256[](bucketsCount); + _input.capacities = new uint256[](bucketsCount); + for (uint256 i = 0; i < bucketsCount; ++i) { + _input.buckets[i] = _fuzzBuckets[i] % MAX_BUCKET_VALUE; + _input.capacities[i] = _fuzzCapacities[i] % MAX_CAPACITY_VALUE; + } + _input.allocationSize = _fuzzAllocationSize % MAX_ALLOCATION_SIZE; + } +} + +contract MinFirstAllocationStrategyAllocateTestWrapper is MinFirstAllocationStrategyTestWrapper { + function allocate( + uint256[] memory _fuzzBuckets, + uint256[] memory _fuzzCapacities, + uint256 _fuzzAllocationSize + ) public { + _fillTestInput(_fuzzBuckets, _fuzzCapacities, _fuzzAllocationSize); + + _fillActualAllocateOutput(); + _fillExpectedAllocateOutput(); + } + + function _fillExpectedAllocateOutput() internal { + uint256[] memory buckets = _input.buckets; + uint256[] memory capacities = _input.capacities; + uint256 allocationSize = _input.allocationSize; + + uint256 allocated = NaiveMinFirstAllocationStrategy.allocate(buckets, capacities, allocationSize); + + _expected.allocated = allocated; + _expected.buckets = buckets; + _expected.capacities = capacities; + } + + function _fillActualAllocateOutput() internal { + uint256[] memory buckets = _input.buckets; + uint256[] memory capacities = _input.capacities; + uint256 allocationSize = _input.allocationSize; + + uint256 allocated = MinFirstAllocationStrategy.allocate(buckets, capacities, allocationSize); + + _actual.allocated = allocated; + _actual.buckets = buckets; + _actual.capacities = capacities; + } +} + +library NaiveMinFirstAllocationStrategy { + uint256 private constant MAX_UINT256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; + + function allocate( + uint256[] memory buckets, + uint256[] memory capacities, + uint256 allocationSize + ) internal pure returns (uint256 allocated) { + while (allocated < allocationSize) { + uint256 bestCandidateIndex = MAX_UINT256; + uint256 bestCandidateAllocation = MAX_UINT256; + for (uint256 i = 0; i < buckets.length; ++i) { + if (buckets[i] >= capacities[i]) continue; + if (buckets[i] < bestCandidateAllocation) { + bestCandidateAllocation = buckets[i]; + bestCandidateIndex = i; + } + } + if (bestCandidateIndex == MAX_UINT256) break; + buckets[bestCandidateIndex] += 1; + allocated += 1; + } + } +} From 0050deac96ed8ff416c441efe532b10ab97ad8e7 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Thu, 16 Feb 2023 01:36:58 +0100 Subject: [PATCH 052/199] feat: static totals storage --- .../0.4.24/nos/NodeOperatorsRegistry.sol | 268 +++++++++++++----- .../NodeOperatorsRegistryMock.sol | 16 ++ lib/abi/NodeOperatorsRegistry.json | 2 +- test/helpers/node-operators.js | 8 +- 4 files changed, 216 insertions(+), 78 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index c077181fc..1418f1c4f 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -101,6 +101,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// @notice stores value +1 based, so 0 is means target count is unlimited (i.e. = -1), /// and 1 is means target count = 0 (i.e. all validators should be exited) uint8 internal constant TARGET_VALIDATORS_COUNT_OFFSET = 1; + /// @dev actual operators's number of keys which could be deposited + uint8 internal constant MAX_VALIDATORS_COUNT_OFFSET = 2; // StuckPenaltyStats /// @dev stuck keys count from oracle report @@ -175,12 +177,18 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { Packed64x4.Packed targetValidatorsStats; } + struct NodeOperatorTotals { + Packed64x4.Packed signingKeysStats; + // Packed64x4.Packed targetValidatorsStats; + } + // // STORAGE VARIABLES // /// @dev Mapping of all node operators. Mapping is used to be able to extend the struct. mapping(uint256 => NodeOperator) internal _nodeOperators; + NodeOperatorTotals internal _nodeOperatorTotals; // // METHODS @@ -200,14 +208,19 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 totalOperators = getNodeOperatorsCount(); Packed64x4.Packed memory signingKeysStats; - for (uint256 operatorId; operatorId < totalOperators; ++operatorId) { - signingKeysStats = _loadOperatorSigningKeysStats(operatorId); - uint64 vettedSigningKeysCountBefore = signingKeysStats.get(VETTED_KEYS_COUNT_OFFSET); - uint64 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); - uint64 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); + Packed64x4.Packed memory operatorTargetStats; + Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + uint64 vettedSigningKeysCountBefore; + uint64 totalSigningKeysCount; + uint64 depositedSigningKeysCount; + for (uint256 nodeOperatorId; nodeOperatorId < totalOperators; ++nodeOperatorId) { + signingKeysStats = _loadOperatorSigningKeysStats(nodeOperatorId); + vettedSigningKeysCountBefore = signingKeysStats.get(VETTED_KEYS_COUNT_OFFSET); + totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); + depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); uint64 vettedSigningKeysCountAfter; - if (!_nodeOperators[operatorId].active) { + if (!_nodeOperators[nodeOperatorId].active) { // trim vetted signing keys count when node operator is not active vettedSigningKeysCountAfter = depositedSigningKeysCount; } else { @@ -217,11 +230,33 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { if (vettedSigningKeysCountBefore != vettedSigningKeysCountAfter) { signingKeysStats.set(VETTED_KEYS_COUNT_OFFSET, vettedSigningKeysCountAfter); - _saveOperatorSigningKeysStats(operatorId, signingKeysStats); - emit VettedSigningKeysCountChanged(operatorId, vettedSigningKeysCountAfter); + _saveOperatorSigningKeysStats(nodeOperatorId, signingKeysStats); + + operatorTargetStats = _loadOperatorTargetValidatorsStats(nodeOperatorId); + operatorTargetStats.set(MAX_VALIDATORS_COUNT_OFFSET, vettedSigningKeysCountAfter); + _saveOperatorTargetValidatorsStats(nodeOperatorId, operatorTargetStats); + + emit VettedSigningKeysCountChanged(nodeOperatorId, vettedSigningKeysCountAfter); } + + totalSigningKeysStats.set( + VETTED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET).add(vettedSigningKeysCountAfter) + ); + totalSigningKeysStats.set( + DEPOSITED_KEYS_COUNT_OFFSET, + totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(depositedSigningKeysCount) + ); + totalSigningKeysStats.set( + EXITED_KEYS_COUNT_OFFSET, + totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET).add(signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET)) + ); + totalSigningKeysStats.set( + TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).add(totalSigningKeysCount) + ); } + _saveTotalSigningKeysStats(totalSigningKeysStats); + _increaseValidatorsKeysNonce(); } @@ -310,6 +345,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); emit VettedSigningKeysCountChanged(_nodeOperatorId, depositedSigningKeysCount); + + _updateTotalMaxValidatorsCount(_nodeOperatorId); } _increaseValidatorsKeysNonce(); } @@ -367,6 +404,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); emit VettedSigningKeysCountChanged(_nodeOperatorId, vettedSigningKeysCountAfter); + + _updateTotalMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); } @@ -395,10 +434,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// /// @param _nodeOperatorId Id of the node operator /// @param _exitedValidatorsCount New number of EXITED validators of the node operator - /// @return Total number of exited validators across all node operators. function updateExitedValidatorsCount(uint256 _nodeOperatorId, uint256 _exitedValidatorsCount) external - returns (uint256) { _onlyExistedNodeOperator(_nodeOperatorId); _auth(STAKING_ROUTER_ROLE); @@ -446,18 +483,29 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { internal { Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); - uint64 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); - uint64 exitedValidatorsCount = signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET); + int64 totalExitedValidatorsDelta = + int64(_exitedValidatorsKeysCount) - int64(signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET)); - if (exitedValidatorsCount != _exitedValidatorsKeysCount) { - _requireValidRange(_exitedValidatorsKeysCount <= depositedSigningKeysCount); - if (_exitedValidatorsKeysCount < exitedValidatorsCount && !_allowDecrease) { + if (totalExitedValidatorsDelta != 0) { + _requireValidRange(_exitedValidatorsKeysCount <= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET)); + if (totalExitedValidatorsDelta < 0 && !_allowDecrease) { revert("EXITED_VALIDATORS_COUNT_DECREASED"); } signingKeysStats.set(EXITED_KEYS_COUNT_OFFSET, _exitedValidatorsKeysCount); _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); emit ExitedSigningKeysCountChanged(_nodeOperatorId, _exitedValidatorsKeysCount); + + // upd totals + Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + totalSigningKeysStats.set( + EXITED_KEYS_COUNT_OFFSET, + uint64(int64(totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET)) + totalExitedValidatorsDelta) + ); + _saveTotalSigningKeysStats(totalSigningKeysStats); + + /// @todo optimize: reuse totalSigningKeysStats + _updateTotalMaxValidatorsCount(_nodeOperatorId); } } @@ -475,6 +523,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _saveOperatorTargetValidatorsStats(_nodeOperatorId, operatorTargetStats); emit TargetValidatorsCountChanged(_nodeOperatorId, _targetLimit); + + _updateTotalMaxValidatorsCount(_nodeOperatorId); } /** @@ -493,6 +543,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { } _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); emit StuckValidatorsCountChanged(_nodeOperatorId, _stuckValidatorsCount); + + _updateTotalMaxValidatorsCount(_nodeOperatorId); } function _updateRefundValidatorsKeysCount(uint256 _nodeOperatorId, uint64 _refundedValidatorsCount) internal { @@ -508,6 +560,22 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { } _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); emit RefundedValidatorsCountChanged(_nodeOperatorId, _refundedValidatorsCount); + + _updateTotalMaxValidatorsCount(_nodeOperatorId); + } + + // upd op limits and totals + function _updateTotalMaxValidatorsCount(uint256 _nodeOperatorId) internal returns (int64 maxSigningKeysDelta) { + maxSigningKeysDelta = _applyNodeOperatorLimits(_nodeOperatorId); + if (maxSigningKeysDelta != 0) { + Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + + totalSigningKeysStats.set( + VETTED_KEYS_COUNT_OFFSET, + uint64(int64(totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET)) + maxSigningKeysDelta) + ); + _saveTotalSigningKeysStats(totalSigningKeysStats); + } } /// @notice Invalidates all unused deposit data for all node operators @@ -527,8 +595,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint64 totalTrimmedKeysCount; Packed64x4.Packed memory signingKeysStats; - for (uint256 _nodeOperatorId = _indexFrom; _nodeOperatorId <= _indexTo; ++_nodeOperatorId) { - signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); + for (uint256 nodeOperatorId = _indexFrom; nodeOperatorId <= _indexTo; ++nodeOperatorId) { + signingKeysStats = _loadOperatorSigningKeysStats(nodeOperatorId); uint64 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); trimmedKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET) - depositedSigningKeysCount; @@ -537,11 +605,13 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, depositedSigningKeysCount); signingKeysStats.set(VETTED_KEYS_COUNT_OFFSET, depositedSigningKeysCount); - _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); + _saveOperatorSigningKeysStats(nodeOperatorId, signingKeysStats); - emit TotalSigningKeysCountChanged(_nodeOperatorId, depositedSigningKeysCount); - emit VettedSigningKeysCountChanged(_nodeOperatorId, depositedSigningKeysCount); - emit NodeOperatorTotalKeysTrimmed(_nodeOperatorId, trimmedKeysCount); + _updateTotalMaxValidatorsCount(nodeOperatorId); + + emit TotalSigningKeysCountChanged(nodeOperatorId, depositedSigningKeysCount); + emit VettedSigningKeysCountChanged(nodeOperatorId, depositedSigningKeysCount); + emit NodeOperatorTotalKeysTrimmed(nodeOperatorId, trimmedKeysCount); } if (totalTrimmedKeysCount > 0) { @@ -585,26 +655,45 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { function _getNodeOperatorWithLimitApplied(uint256 _nodeOperatorId) internal view - returns (uint64 vettedSigningKeysCount, uint64 exitedSigningKeysCount, uint64 depositedSigningKeysCount) + returns (uint64 maxSigningKeysCount, uint64 exitedSigningKeysCount, uint64 depositedSigningKeysCount) { Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); + Packed64x4.Packed memory operatorTargetStats = _loadOperatorTargetValidatorsStats(_nodeOperatorId); + exitedSigningKeysCount = signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET); depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); - vettedSigningKeysCount = depositedSigningKeysCount; + maxSigningKeysCount = operatorTargetStats.get(MAX_VALIDATORS_COUNT_OFFSET); + } + + function _applyNodeOperatorLimits(uint256 _nodeOperatorId) internal returns (int64 maxSigningKeysDelta) { + Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); + Packed64x4.Packed memory operatorTargetStats = _loadOperatorTargetValidatorsStats(_nodeOperatorId); + + uint64 exitedSigningKeysCount = signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET); + uint64 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); + uint64 vettedSigningKeysCount = signingKeysStats.get(VETTED_KEYS_COUNT_OFFSET); - if (!isOperatorPenalized(_nodeOperatorId)) { - Packed64x4.Packed memory operatorTargetStats = _loadOperatorTargetValidatorsStats(_nodeOperatorId); + /// @todo check for MAX_VALIDATORS_COUNT_OFFSET < MAX_UINT64 - 1 + uint64 oldMaxSigningKeysCount = operatorTargetStats.get(MAX_VALIDATORS_COUNT_OFFSET); + uint64 newMaxSigningKeysCount = depositedSigningKeysCount; + if (!isOperatorPenalized(_nodeOperatorId, true)) { if (operatorTargetStats.get(IS_TARGET_LIMIT_ACTIVE_OFFSET) == 0) { - vettedSigningKeysCount = signingKeysStats.get(VETTED_KEYS_COUNT_OFFSET); + newMaxSigningKeysCount = vettedSigningKeysCount; } else { - // correct vetted count according to target if target is enabled + // correct max count according to target if target is enabled uint64 targetLimit = exitedSigningKeysCount.add(operatorTargetStats.get(TARGET_VALIDATORS_COUNT_OFFSET)); if (targetLimit > depositedSigningKeysCount) { - vettedSigningKeysCount = Math64.min(signingKeysStats.get(VETTED_KEYS_COUNT_OFFSET), targetLimit); + newMaxSigningKeysCount = Math64.min(vettedSigningKeysCount, targetLimit); } } - } // else vettedSigningKeysCount = depositedSigningKeysCount, so depositable keys count = 0 + } // else newMaxSigningKeysCount = depositedSigningKeysCount, so depositable keys count = 0 + + if (oldMaxSigningKeysCount != newMaxSigningKeysCount) { + operatorTargetStats.set(MAX_VALIDATORS_COUNT_OFFSET, newMaxSigningKeysCount); + _saveOperatorTargetValidatorsStats(_nodeOperatorId, operatorTargetStats); + maxSigningKeysDelta = int64(newMaxSigningKeysCount) - int64(oldMaxSigningKeysCount); + } } function _getSigningKeysAllocationData(uint256 _keysCount) @@ -619,20 +708,22 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 activeNodeOperatorIndex; uint256 nodeOperatorsCount = getNodeOperatorsCount(); - uint256 vettedSigningKeysCount; + uint256 maxSigningKeysCount; uint256 depositedSigningKeysCount; uint256 exitedSigningKeysCount; + /// @todo check for MAX_VALIDATORS_COUNT_OFFSET < MAX_UINT64 - 1 + for (uint256 nodeOperatorId; nodeOperatorId < nodeOperatorsCount; ++nodeOperatorId) { - (vettedSigningKeysCount, exitedSigningKeysCount, depositedSigningKeysCount) = + (maxSigningKeysCount, exitedSigningKeysCount, depositedSigningKeysCount) = _getNodeOperatorWithLimitApplied(nodeOperatorId); // the node operator has no available signing keys - if (depositedSigningKeysCount == vettedSigningKeysCount) continue; + if (depositedSigningKeysCount == maxSigningKeysCount) continue; nodeOperatorIds[activeNodeOperatorIndex] = nodeOperatorId; activeKeyCountsAfterAllocation[activeNodeOperatorIndex] = depositedSigningKeysCount - exitedSigningKeysCount; - activeKeysCapacities[activeNodeOperatorIndex] = vettedSigningKeysCount - exitedSigningKeysCount; + activeKeysCapacities[activeNodeOperatorIndex] = maxSigningKeysCount - exitedSigningKeysCount; ++activeNodeOperatorIndex; } @@ -682,9 +773,16 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit DepositedSigningKeysCountChanged(_nodeOperatorIds[i], depositedSigningKeysCountAfter); signingKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, depositedSigningKeysCountAfter); _saveOperatorSigningKeysStats(_nodeOperatorIds[i], signingKeysStats); + _updateTotalMaxValidatorsCount(_nodeOperatorIds[i]); } assert(loadedKeysCount == _keysCountToLoad); + + Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + totalSigningKeysStats.set( + DEPOSITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(uint64(loadedKeysCount)) + ); + _saveTotalSigningKeysStats(totalSigningKeysStats); } /// @notice Returns the node operator by id @@ -746,7 +844,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { recipients[idx] = _nodeOperators[operatorId].rewardAddress; // prefill shares array with 'key share' for recipient, see below shares[idx] = activeValidatorsCount; - penalized[idx] = isOperatorPenalized(operatorId); + penalized[idx] = isOperatorPenalized(operatorId, false); ++idx; } @@ -802,6 +900,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _requireValidRange(totalSigningKeysCount.add(_keysCount) <= UINT64_MAX); + // totalSigningKeysCount = SIGNING_KEYS_MAPPING_NAME.addKeysSigs(_nodeOperatorId, _keysCount, totalSigningKeysCount, _publicKeys, _signatures); @@ -810,6 +909,13 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, uint64(totalSigningKeysCount)); _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); + // upd totals + Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + totalSigningKeysStats.set( + TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).add(uint64(_keysCount)) + ); + _saveTotalSigningKeysStats(totalSigningKeysStats); + _increaseValidatorsKeysNonce(); } @@ -859,6 +965,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // comapring _toIndex <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than MAX_UINT64 _requireValidRange(_fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) && _toIndex <= totalSigningKeysCount); + /// @todo: move to lib // removing from the last index to the highest one, so we won't get outside the array for (uint256 i = _toIndex; i > _fromIndex; --i) { totalSigningKeysCount = @@ -875,6 +982,15 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { } _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); + // upd totals + Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + totalSigningKeysStats.set( + TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).sub(uint64(_keysCount)) + ); + _saveTotalSigningKeysStats(totalSigningKeysStats); + /// @todo optimize: reuse totalSigningKeysStats + _updateTotalMaxValidatorsCount(_nodeOperatorId); + _increaseValidatorsKeysNonce(); } @@ -941,34 +1057,26 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { return TYPE_POSITION.getStorageBytes32(); } - function getStakingModuleSummary() external view returns ( - uint256 totalExitedValidators, - uint256 totalDepositedValidators, - uint256 depositableValidatorsCount - ) { - uint256 nodeOperatorsCount = getNodeOperatorsCount(); - - uint256 tmpTotalExitedValidators; - uint256 tmpTotalDepositedValidators; - uint256 tmpDepositableValidatorsCount; - for (uint256 i; i < nodeOperatorsCount; ++i) { - (tmpTotalExitedValidators, tmpTotalDepositedValidators, tmpDepositableValidatorsCount) = - _getNodeOperatorValidatorsSummary(i); - totalExitedValidators += tmpTotalExitedValidators; - totalDepositedValidators += tmpTotalDepositedValidators; - depositableValidatorsCount += tmpDepositableValidatorsCount; - } + function getStakingModuleSummary() + external + view + returns (uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount) + { + Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + totalExitedValidators = totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET); + totalDepositedValidators = totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); + depositableValidatorsCount = totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET) - totalDepositedValidators; } function getNodeOperatorSummary(uint256 _nodeOperatorId) external view returns ( - bool isTargetLimitActive, - uint256 targetValidatorsCount, - uint256 stuckValidatorsCount, - uint256 refundedValidatorsCount, - uint256 stuckPenaltyEndTimestamp, - uint256 totalExitedValidators, - uint256 totalDepositedValidators, - uint256 depositableValidatorsCount + bool isTargetLimitActive, + uint256 targetValidatorsCount, + uint256 stuckValidatorsCount, + uint256 refundedValidatorsCount, + uint256 stuckPenaltyEndTimestamp, + uint256 totalExitedValidators, + uint256 totalDepositedValidators, + uint256 depositableValidatorsCount ) { _onlyExistedNodeOperator(_nodeOperatorId); @@ -982,7 +1090,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { stuckPenaltyEndTimestamp = stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET); (totalExitedValidators, totalDepositedValidators, depositableValidatorsCount) = - _getNodeOperatorValidatorsSummary(_nodeOperatorId); + _getNodeOperatorValidatorsSummary(_nodeOperatorId); } function _getNodeOperatorValidatorsSummary(uint256 _nodeOperatorId) internal view returns ( @@ -990,16 +1098,26 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 totalDepositedValidators, uint256 depositableValidatorsCount ) { - uint256 totalVettedValidators; - (totalVettedValidators, totalExitedValidators, totalDepositedValidators) = + uint256 totalMaxValidators; + (totalMaxValidators, totalExitedValidators, totalDepositedValidators) = _getNodeOperatorWithLimitApplied(_nodeOperatorId); - depositableValidatorsCount = totalVettedValidators - totalDepositedValidators; + + depositableValidatorsCount = totalMaxValidators - totalDepositedValidators; } - function isOperatorPenalized(uint256 _nodeOperatorId) public view returns (bool) { + function isOperatorPenalized(uint256 _nodeOperatorId, bool _withClearedPenalty) public view returns (bool) { Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); return stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET) < stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET) - || block.timestamp <= stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET); + || block.timestamp <= stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) + || (_withClearedPenalty && stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) != 0); + } + + function clearNodeOperatorPenalty(uint256 _nodeOperatorId) external returns (bool) { + require(!isOperatorPenalized(_nodeOperatorId, false), "CANT_CLEAR_PANLTY"); + Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); + stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, 0); + _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); + _updateTotalMaxValidatorsCount(_nodeOperatorId); } /// @notice Returns total number of node operators @@ -1022,13 +1140,13 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { external view returns (uint256[] memory nodeOperatorIds) { - uint256 nodeOperatorsCount = getNodeOperatorsCount(); - if (_offset >= nodeOperatorsCount || _limit == 0) return; - nodeOperatorIds = new uint256[](Math256.min(_limit, nodeOperatorsCount - _offset)); - for (uint256 i = 0; i < nodeOperatorIds.length; ++i) { - nodeOperatorIds[i] = _offset + i; - } + uint256 nodeOperatorsCount = getNodeOperatorsCount(); + if (_offset >= nodeOperatorsCount || _limit == 0) return; + nodeOperatorIds = new uint256[](Math256.min(_limit, nodeOperatorsCount - _offset)); + for (uint256 i = 0; i < nodeOperatorIds.length; ++i) { + nodeOperatorIds[i] = _offset + i; } + } /// @notice Returns a counter that MUST change it's value when any of the following happens: /// 1. a node operator's deposit data is added @@ -1110,6 +1228,14 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit NonceChanged(keysOpIndex); } + function _loadTotalSigningKeysStats() internal view returns (Packed64x4.Packed memory) { + return _nodeOperatorTotals.signingKeysStats; + } + + function _saveTotalSigningKeysStats(Packed64x4.Packed memory _val) internal { + _nodeOperatorTotals.signingKeysStats = _val; + } + function _loadOperatorTargetValidatorsStats(uint256 _nodeOperatorId) internal view returns (Packed64x4.Packed memory) { return _nodeOperators[_nodeOperatorId].targetValidatorsStats; } diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index 44a6188a9..71bfc19e2 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -11,6 +11,14 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { Packed64x4.Packed memory signingKeysStats = _nodeOperators[_nodeOperatorId].signingKeysStats; signingKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) + _keysCount); _nodeOperators[_nodeOperatorId].signingKeysStats = signingKeysStats; + + Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + totalSigningKeysStats.set( + DEPOSITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(_keysCount) + ); + _saveTotalSigningKeysStats(totalSigningKeysStats); + + _updateTotalMaxValidatorsCount(_nodeOperatorId); } function testing_markAllKeysDeposited() external { @@ -87,6 +95,13 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { operator.signingKeysStats = signingKeysStats; emit NodeOperatorAdded(id, _name, _rewardAddress, 0); + + Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + totalSigningKeysStats.set(VETTED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET).add(vettedSigningKeysCount)); + totalSigningKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(depositedSigningKeysCount)); + totalSigningKeysStats.set(EXITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET).add(exitedSigningKeysCount)); + totalSigningKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).add(totalSigningKeysCount)); + _saveTotalSigningKeysStats(totalSigningKeysStats); } function testing_setNodeOperatorLimits( @@ -100,6 +115,7 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { stuckPenaltyStats.set(REFUNDED_VALIDATORS_COUNT_OFFSET, refundedValidatorsCount); stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, stuckPenaltyEndAt); _nodeOperators[_nodeOperatorId].stuckPenaltyStats = stuckPenaltyStats; + _updateTotalMaxValidatorsCount(_nodeOperatorId); } function testing_getTotalSigningKeysStats() diff --git a/lib/abi/NodeOperatorsRegistry.json b/lib/abi/NodeOperatorsRegistry.json index a5a7660a1..159cae01e 100644 --- a/lib/abi/NodeOperatorsRegistry.json +++ b/lib/abi/NodeOperatorsRegistry.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"}],"name":"updateExitedValidatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_onlyClearedPenalty","type":"bool"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"}],"name":"updateExitedValidatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file diff --git a/test/helpers/node-operators.js b/test/helpers/node-operators.js index a7c5adc80..d48b56570 100644 --- a/test/helpers/node-operators.js +++ b/test/helpers/node-operators.js @@ -58,16 +58,12 @@ async function addNodeOperator(registry, config, txOptions) { await registry.addSigningKeys(newOperatorId, totalSigningKeysCount, ...validatorKeys.slice(), txOptions) } - if (depositedSigningKeysCount > 0) { - await registry.increaseNodeOperatorDepositedSigningKeysCount(newOperatorId, depositedSigningKeysCount, txOptions) - } - if (vettedSigningKeysCount > 0) { await registry.setNodeOperatorStakingLimit(newOperatorId, vettedSigningKeysCount, txOptions) } - if (exitedSigningKeysCount > 0) { - await registry.updateExitedValidatorsCount(newOperatorId, exitedSigningKeysCount, txOptions) + if (depositedSigningKeysCount > 0) { + await registry.increaseNodeOperatorDepositedSigningKeysCount(newOperatorId, depositedSigningKeysCount, txOptions) } if (exitedSigningKeysCount > 0) { From 330345198d8534387447eb65213c367d7afa4d2d Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Thu, 16 Feb 2023 12:15:06 +0400 Subject: [PATCH 053/199] Move all MemUtils tests to Foundry --- .../common/test_helpers/MemUtilsTest.sol | 535 ------------------ test/common/lib/mem-utils.test.js | 115 ---- test/common/lib/mem-utils.test.sol | 510 ++++++++++++++++- 3 files changed, 500 insertions(+), 660 deletions(-) delete mode 100644 contracts/common/test_helpers/MemUtilsTest.sol delete mode 100644 test/common/lib/mem-utils.test.js diff --git a/contracts/common/test_helpers/MemUtilsTest.sol b/contracts/common/test_helpers/MemUtilsTest.sol deleted file mode 100644 index ff977b755..000000000 --- a/contracts/common/test_helpers/MemUtilsTest.sol +++ /dev/null @@ -1,535 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Lido -// SPDX-License-Identifier: GPL-3.0 - -/* See contracts/COMPILERS.md */ -pragma solidity 0.8.9; - - -import { MemUtils } from "../lib/MemUtils.sol"; - -import "./Assertions.sol"; - - -contract MemUtilsTest { - function getDataPtr(bytes memory arr) internal pure returns (uint256 dataPtr) { - assembly { - dataPtr := add(arr, 32) - } - } - - function fill(bytes memory arr, bytes1 value) internal pure returns (bytes memory) { - for (uint256 i = 0; i < arr.length; ++i) { - arr[i] = value; - } - return arr; - } - - /// - /// unsafeAllocateBytes - /// - - function unsafeAlloc_allocates_empty_byte_array() external pure { - // disable all compiler optimizations by including an assembly block not marked as mem-safe - assembly { - mstore(0x00, 0x1) - } - - uint256 preAllocFreeMemPtr = getFreeMemPtr(); - - // assert free mem pointer is 32-byte aligned initially - Assert.isTrue(preAllocFreeMemPtr % 32 == 0); - - bytes memory arr = MemUtils.unsafeAllocateBytes(0); - Assert.empty(arr); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - - uint256 freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32); - } - - function unsafeAlloc_allocates_memory_and_advances_free_mem_pointer() external pure { - // disable all compiler optimizations by including an assembly block not marked as mem-safe - assembly { - mstore(0x00, 0x1) - } - - uint256 initialFreeMemPtr = getFreeMemPtr(); - uint256 preAllocFreeMemPtr = initialFreeMemPtr; - - // assert free mem pointer is 32-byte aligned initially - Assert.isTrue(preAllocFreeMemPtr % 32 == 0); - - bytes memory arr = MemUtils.unsafeAllocateBytes(32); - Assert.length(arr, 32); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - fill(arr, 0x11); - - uint256 freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32); - preAllocFreeMemPtr = freeMemPtr; - - arr = MemUtils.unsafeAllocateBytes(64); - Assert.length(arr, 64); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - fill(arr, 0x22); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 64); - preAllocFreeMemPtr = freeMemPtr; - - arr = MemUtils.unsafeAllocateBytes(32 * 10); - Assert.length(arr, 32 * 10); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - fill(arr, 0x33); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32 * 10); - preAllocFreeMemPtr = freeMemPtr; - - arr = MemUtils.unsafeAllocateBytes(32 * 100); - Assert.length(arr, 32 * 100); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - fill(arr, 0x44); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32 * 100); - - Assert.mem(initialFreeMemPtr, freeMemPtr, abi.encodePacked( - // array 1: length - uint256(32), - // array 1: data - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - // array 2: length - uint256(64), - // array 2: data - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), - // array 3: length - uint256(32 * 10), - // array 3: data - fill(new bytes(32 * 10), 0x33), - // array 3: length - uint256(32 * 100), - // array 3: data - fill(new bytes(32 * 100), 0x44) - )); - } - - function unsafeAlloc_pads_free_mem_pointer_to_32_bytes() external pure { - // disable all compiler optimizations by including an assembly block not marked as mem-safe - assembly { - mstore(0x00, 0x1) - } - - uint256 preAllocFreeMemPtr = getFreeMemPtr(); - - // assert free mem pointer is 32-byte aligned initially - Assert.isTrue(preAllocFreeMemPtr % 32 == 0); - - bytes memory arr = MemUtils.unsafeAllocateBytes(1); - Assert.length(arr, 1); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - - uint256 freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32); - preAllocFreeMemPtr = freeMemPtr; - - arr = MemUtils.unsafeAllocateBytes(20); - Assert.length(arr, 20); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32); - preAllocFreeMemPtr = freeMemPtr; - - arr = MemUtils.unsafeAllocateBytes(60); - Assert.length(arr, 60); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 64); - preAllocFreeMemPtr = freeMemPtr; - - arr = MemUtils.unsafeAllocateBytes(32 * 10 + 1); - Assert.length(arr, 32 * 10 + 1); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32 * 11); - preAllocFreeMemPtr = freeMemPtr; - - arr = MemUtils.unsafeAllocateBytes(32 * 100 + 15); - Assert.length(arr, 32 * 100 + 15); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32 * 101); - } - - function unsafeAlloc_handles_misaligned_free_mem_pointer_and_pads_to_32_bytes() external pure { - uint256 freeMemPtr = getFreeMemPtr(); - - // assert free mem pointer is 32-byte aligned initially - Assert.isTrue(freeMemPtr % 32 == 0); - - // misalign the free mem pointer - uint256 preAllocFreeMemPtr = incrementFreeMemPtr(3); - - bytes memory arr = MemUtils.unsafeAllocateBytes(32); - Assert.length(arr, 32); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, (preAllocFreeMemPtr + 32 - 3) + 32 + 32); - - // misalign the free mem pointer - preAllocFreeMemPtr = incrementFreeMemPtr(1); - - arr = MemUtils.unsafeAllocateBytes(120); - Assert.length(arr, 120); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, (preAllocFreeMemPtr - 1) + 32 + 128); - - // misalign the free mem pointer - preAllocFreeMemPtr = incrementFreeMemPtr(32 - 12); - - arr = MemUtils.unsafeAllocateBytes(128 + 12); - Assert.length(arr, 128 + 12); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 128 + 12); - - // misalign the free mem pointer - preAllocFreeMemPtr = incrementFreeMemPtr(5); - - arr = MemUtils.unsafeAllocateBytes(0); - Assert.empty(arr); - Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); - - freeMemPtr = getFreeMemPtr(); - Assert.equal(freeMemPtr, preAllocFreeMemPtr + (32 - 5) + 32); - } - - /// - /// memcpy - /// - - function memcpy_copies_mem_chunks_that_are_multiples_of_32_bytes() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), - bytes32(0x4444444444444444444444444444444444444444444444444444444444444444), - bytes32(0x5555555555555555555555555555555555555555555555555555555555555555) - ); - - MemUtils.memcpy(getDataPtr(src), getDataPtr(dst), 64); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), - bytes32(0x5555555555555555555555555555555555555555555555555555555555555555) - )); - } - - function memcpy_copies_mem_chunks_that_are_multiples_of_32_bytes_from_a_non_32b_offset() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), - bytes32(0x3333333333333333333333333333333333333333333333333333333333333333) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x4444444444444444444444444444444444444444444444444444444444444444), - bytes32(0x5555555555555555555555555555555555555555555555555555555555555555), - bytes32(0x6666666666666666666666666666666666666666666666666666666666666666) - ); - - MemUtils.memcpy(getDataPtr(src) + 4, getDataPtr(dst), 64); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111122222222), - bytes32(0x2222222222222222222222222222222222222222222222222222222233333333), - bytes32(0x6666666666666666666666666666666666666666666666666666666666666666) - )); - } - - function memcpy_copies_mem_chunks_that_are_multiples_of_32b_to_a_non_32b_offset() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), - bytes32(0x4444444444444444444444444444444444444444444444444444444444444444), - bytes32(0x5555555555555555555555555555555555555555555555555555555555555555) - ); - - MemUtils.memcpy(getDataPtr(src), getDataPtr(dst) + 4, 64); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x3333333311111111111111111111111111111111111111111111111111111111), - bytes32(0x1111111122222222222222222222222222222222222222222222222222222222), - bytes32(0x2222222255555555555555555555555555555555555555555555555555555555) - )); - } - - function memcpy_copies_mem_chunks_that_are_multiples_of_32_bytes_from_and_to_a_non_32b_offset() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), - bytes32(0x3333333333333333333333333333333333333333333333333333333333333333) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x4444444444444444444444444444444444444444444444444444444444444444), - bytes32(0x5555555555555555555555555555555555555555555555555555555555555555), - bytes32(0x6666666666666666666666666666666666666666666666666666666666666666) - ); - - MemUtils.memcpy(getDataPtr(src) + 4, getDataPtr(dst) + 3, 64); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x4444441111111111111111111111111111111111111111111111111111111122), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222233), - bytes32(0x3333336666666666666666666666666666666666666666666666666666666666) - )); - } - - function memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), - bytes32(0x4444444444444444444444444444444444444444444444444444444444444444) - ); - - MemUtils.memcpy(getDataPtr(src), getDataPtr(dst), 42); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222244444444444444444444444444444444444444444444) - )); - } - - function memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes_from_a_non_32b_offset() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), - bytes32(0x4444444444444444444444444444444444444444444444444444444444444444) - ); - - MemUtils.memcpy(getDataPtr(src) + 3, getDataPtr(dst), 42); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111222222), - bytes32(0x2222222222222222222244444444444444444444444444444444444444444444) - )); - } - - function memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes_to_a_non_32b_offset() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), - bytes32(0x4444444444444444444444444444444444444444444444444444444444444444) - ); - - MemUtils.memcpy(getDataPtr(src), getDataPtr(dst) + 3, 42); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x3333331111111111111111111111111111111111111111111111111111111111), - bytes32(0x1111112222222222222222222244444444444444444444444444444444444444) - )); - } - - function memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes_from_and_to_a_non_32b_offset() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), - bytes32(0x4444444444444444444444444444444444444444444444444444444444444444) - ); - - MemUtils.memcpy(getDataPtr(src) + 3, getDataPtr(dst) + 4, 42); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x3333333311111111111111111111111111111111111111111111111111111111), - bytes32(0x1122222222222222222222222222444444444444444444444444444444444444) - )); - } - - function memcpy_copies_mem_chunks_shorter_than_32_bytes() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - MemUtils.memcpy(getDataPtr(src), getDataPtr(dst), 5); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x1111111111222222222222222222222222222222222222222222222222222222) - )); - } - - function memcpy_copies_mem_chunks_shorter_than_32_bytes_from_a_non_32b_offset() external pure { - bytes memory src = abi.encodePacked( - bytes32(0xcccccccccccccccccccccccccccccccccc8badf00d1234eeeeeeeeeeeeeeeeee) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - MemUtils.memcpy(getDataPtr(src) + 17, getDataPtr(dst), 4); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x8badf00d22222222222222222222222222222222222222222222222222222222) - )); - } - - function memcpy_copies_mem_chunks_shorter_than_32_bytes_to_a_non_32b_offset() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - MemUtils.memcpy(getDataPtr(src), getDataPtr(dst) + 5, 5); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x2222222222111111111122222222222222222222222222222222222222222222) - )); - } - - function memcpy_copies_mem_chunks_shorter_than_32_bytes_from_and_to_a_non_32b_offset() external pure { - bytes memory src = abi.encodePacked( - bytes32(0xcccccccccccccccccccccccccccccccccc8badf00d1234eeeeeeeeeeeeeeeeee) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - MemUtils.memcpy(getDataPtr(src) + 17, getDataPtr(dst) + 3, 4); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x2222228badf00d22222222222222222222222222222222222222222222222222) - )); - } - - function memcpy_zero_length_is_handled_correctly() external pure { - bytes memory src = abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111) - ); - - bytes memory dst = abi.encodePacked( - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - ); - - MemUtils.memcpy(getDataPtr(src) + 11, getDataPtr(dst) + 13, 0); - - Assert.equal(dst, abi.encodePacked( - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) - )); - } - - /// - /// keccakUint256Array - /// - - function keccakUint256Array_calcs_keccak_over_a_uint_array() external pure { - uint256[] memory array = new uint256[](5); - array[0] = uint256(0x1111111111111111111111111111111111111111111111111111111111111111); - array[1] = uint256(0x2222222222222222222222222222222222222222222222222222222222222222); - array[2] = uint256(0x3333333333333333333333333333333333333333333333333333333333333333); - array[3] = uint256(0x4444444444444444444444444444444444444444444444444444444444444444); - array[4] = uint256(0x5555555555555555555555555555555555555555555555555555555555555555); - - bytes32 expected = keccak256(abi.encodePacked(array)); - bytes32 actual = MemUtils.keccakUint256Array(array); - - Assert.equal(actual, expected); - } - - function keccakUint256Array_calcs_keccak_over_an_empty_array() external pure { - uint256[] memory array = new uint256[](0); - - bytes32 expected = keccak256(abi.encodePacked(array)); - bytes32 actual = MemUtils.keccakUint256Array(array); - - Assert.equal(actual, expected); - } - - /// - /// trimUint256Array - /// - - function trimUint256Array_decreases_length_of_a_uint_array() external pure { - uint256[] memory array = new uint256[](5); - array[0] = uint256(0x1111111111111111111111111111111111111111111111111111111111111111); - array[1] = uint256(0x2222222222222222222222222222222222222222222222222222222222222222); - array[2] = uint256(0x3333333333333333333333333333333333333333333333333333333333333333); - array[3] = uint256(0x4444444444444444444444444444444444444444444444444444444444444444); - array[4] = uint256(0x5555555555555555555555555555555555555555555555555555555555555555); - - MemUtils.trimUint256Array(array, 2); - - Assert.equal(array.length, 3); - Assert.equal(array[0], uint256(0x1111111111111111111111111111111111111111111111111111111111111111)); - Assert.equal(array[1], uint256(0x2222222222222222222222222222222222222222222222222222222222222222)); - Assert.equal(array[2], uint256(0x3333333333333333333333333333333333333333333333333333333333333333)); - - Assert.equal(abi.encodePacked(array), abi.encodePacked( - bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), - bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), - bytes32(0x3333333333333333333333333333333333333333333333333333333333333333) - )); - } - - function trimUint256Array_allows_trimming_to_zero_length() external pure { - uint256[] memory array = new uint256[](3); - array[0] = uint256(0x1111111111111111111111111111111111111111111111111111111111111111); - array[1] = uint256(0x2222222222222222222222222222222222222222222222222222222222222222); - array[2] = uint256(0x3333333333333333333333333333333333333333333333333333333333333333); - - MemUtils.trimUint256Array(array, 3); - - Assert.empty(array); - } - - function trimUint256Array_reverts_on_trying_to_trim_by_more_than_length() external pure { - uint256[] memory array = new uint256[](3); - array[0] = uint256(0x1111111111111111111111111111111111111111111111111111111111111111); - array[1] = uint256(0x2222222222222222222222222222222222222222222222222222222222222222); - array[2] = uint256(0x3333333333333333333333333333333333333333333333333333333333333333); - - MemUtils.trimUint256Array(array, 4); - revert Assert.RevertExpected(); - } -} diff --git a/test/common/lib/mem-utils.test.js b/test/common/lib/mem-utils.test.js deleted file mode 100644 index 2faf066ff..000000000 --- a/test/common/lib/mem-utils.test.js +++ /dev/null @@ -1,115 +0,0 @@ -const { assert } = require('../../helpers/assert') -const { printEvents } = require('../../helpers/utils') - -const MemUtilsTest = artifacts.require('MemUtilsTest') - - -contract('MemUtils', () => { - let test - - before(async () => { - test = await MemUtilsTest.new() - }) - - context('unsafeAllocateBytes', () => { - - it('allocates empty byte array', async () => { - await test.unsafeAlloc_allocates_empty_byte_array() - }) - - it('allocates memory and advances free mem pointer', async () => { - await test.unsafeAlloc_allocates_memory_and_advances_free_mem_pointer() - }) - - it('pads free mem pointer to 32 bytes', async () => { - await test.unsafeAlloc_pads_free_mem_pointer_to_32_bytes() - }) - - it('handles misaligned free mem pointer and pads it to 32 bytes', async () => { - await test.unsafeAlloc_handles_misaligned_free_mem_pointer_and_pads_to_32_bytes() - }) - }) - - context('memcpy', () => { - - it('copies mem chunks that are multiples of 32 bytes', async () => { - await test.memcpy_copies_mem_chunks_that_are_multiples_of_32_bytes() - }) - - it('copies mem chunks that are multiples of 32 bytes from a non-32 byte offset', async () => { - await test.memcpy_copies_mem_chunks_that_are_multiples_of_32_bytes_from_a_non_32b_offset() - }) - - it('copies mem chunks that are multiples of 32 bytes to a non-32 byte offset', async () => { - await test.memcpy_copies_mem_chunks_that_are_multiples_of_32b_to_a_non_32b_offset() - }) - - it('copies mem chunks that are multiples of 32 bytes from and to a non-32 byte offset', async () => { - await test.memcpy_copies_mem_chunks_that_are_multiples_of_32_bytes_from_and_to_a_non_32b_offset() - }) - - it('copies mem chunks that are not multiples of 32 bytes', async () => { - await test.memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes() - }) - - it('copies mem chunks that are not multiples of 32 bytes from a non-32 byte offset', async () => { - await test.memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes_from_a_non_32b_offset() - }) - - it('copies mem chunks that are not multiples of 32 bytes to a non-32 byte offset', async () => { - await test.memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes_to_a_non_32b_offset() - }) - - it('copies mem chunks that are not multiples of 32 bytes from and to a non-32 byte offset', async () => { - await test.memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes_from_and_to_a_non_32b_offset() - }) - - it('copies mem chunks shorter than 32 bytes', async () => { - await test.memcpy_copies_mem_chunks_shorter_than_32_bytes() - }) - - it('copies mem chunks shorter than 32 bytes from a non-32 byte offset', async () => { - await test.memcpy_copies_mem_chunks_shorter_than_32_bytes_from_a_non_32b_offset() - }) - - it('copies mem chunks shorter than 32 bytes to a non-32 byte offset', async () => { - await test.memcpy_copies_mem_chunks_shorter_than_32_bytes_to_a_non_32b_offset() - }) - - it('copies mem chunks shorter than 32 bytes from and to a non-32 byte offset', async () => { - await test.memcpy_copies_mem_chunks_shorter_than_32_bytes_from_and_to_a_non_32b_offset() - }) - - it('zero length is handled correctly', async () => { - await test.memcpy_zero_length_is_handled_correctly() - }) - }) - - context('keccakUint256Array', () => { - - it('calculates a keccak256 over a uint256 array', async () => { - await test.keccakUint256Array_calcs_keccak_over_a_uint_array() - }) - - it('calculates a keccak256 over an empty uint256 array', async () => { - await test.keccakUint256Array_calcs_keccak_over_an_empty_array() - }) - }) - - context('trimUint256Array', () => { - - it('decreases length of a uint256 array', async () => { - await test.trimUint256Array_decreases_length_of_a_uint_array() - }) - - it('allows trimming to a zero length', async () => { - await test.trimUint256Array_allows_trimming_to_zero_length() - }) - - it('reverts on trying to trim by more than the array length', async () => { - await assert.reverts( - test.trimUint256Array_reverts_on_trying_to_trim_by_more_than_length() - ) - }) - }) -}) diff --git a/test/common/lib/mem-utils.test.sol b/test/common/lib/mem-utils.test.sol index 8bc94713d..cb4e462f4 100644 --- a/test/common/lib/mem-utils.test.sol +++ b/test/common/lib/mem-utils.test.sol @@ -4,14 +4,30 @@ pragma solidity 0.8.9; import "forge-std/Test.sol"; + import { MemUtils } from "contracts/common/lib/MemUtils.sol"; +import "contracts/common/test_helpers/Assertions.sol"; + + +contract MemUtilsTest is Test { + function getDataPtr(bytes memory arr) internal pure returns (uint256 dataPtr) { + assembly { + dataPtr := add(arr, 32) + } + } + + function fill(bytes memory arr, bytes1 value) internal pure returns (bytes memory) { + for (uint256 i = 0; i < arr.length; ++i) { + arr[i] = value; + } + return arr; + } -contract MemUtilsTestFoundry is Test { /// /// unsafeAllocateBytes /// - function test_unsafeAlloc_allocates_empty_byte_array() external { + function test_unsafeAlloc_allocates_empty_byte_array() external pure { // disable all compiler optimizations by including an assembly block not marked as mem-safe assembly { mstore(0x00, 0x1) @@ -20,25 +36,499 @@ contract MemUtilsTestFoundry is Test { uint256 preAllocFreeMemPtr = getFreeMemPtr(); // assert free mem pointer is 32-byte aligned initially - assertTrue(preAllocFreeMemPtr % 32 == 0); + Assert.isTrue(preAllocFreeMemPtr % 32 == 0); bytes memory arr = MemUtils.unsafeAllocateBytes(0); - assert(arr.length == 0); - assertEq(getMemPtr(arr), preAllocFreeMemPtr); + Assert.empty(arr); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); uint256 freeMemPtr = getFreeMemPtr(); - assertEq(freeMemPtr, preAllocFreeMemPtr + 32); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32); } - function getFreeMemPtr() internal pure returns (uint256 result) { + function test_unsafeAlloc_allocates_memory_and_advances_free_mem_pointer() external pure { + // disable all compiler optimizations by including an assembly block not marked as mem-safe assembly { - result := mload(0x40) + mstore(0x00, 0x1) } + + uint256 initialFreeMemPtr = getFreeMemPtr(); + uint256 preAllocFreeMemPtr = initialFreeMemPtr; + + // assert free mem pointer is 32-byte aligned initially + Assert.isTrue(preAllocFreeMemPtr % 32 == 0); + + bytes memory arr = MemUtils.unsafeAllocateBytes(32); + Assert.length(arr, 32); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + fill(arr, 0x11); + + uint256 freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32); + preAllocFreeMemPtr = freeMemPtr; + + arr = MemUtils.unsafeAllocateBytes(64); + Assert.length(arr, 64); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + fill(arr, 0x22); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 64); + preAllocFreeMemPtr = freeMemPtr; + + arr = MemUtils.unsafeAllocateBytes(32 * 10); + Assert.length(arr, 32 * 10); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + fill(arr, 0x33); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32 * 10); + preAllocFreeMemPtr = freeMemPtr; + + arr = MemUtils.unsafeAllocateBytes(32 * 100); + Assert.length(arr, 32 * 100); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + fill(arr, 0x44); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32 * 100); + + Assert.mem(initialFreeMemPtr, freeMemPtr, abi.encodePacked( + // array 1: length + uint256(32), + // array 1: data + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + // array 2: length + uint256(64), + // array 2: data + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), + // array 3: length + uint256(32 * 10), + // array 3: data + fill(new bytes(32 * 10), 0x33), + // array 3: length + uint256(32 * 100), + // array 3: data + fill(new bytes(32 * 100), 0x44) + )); } - function getMemPtr(bytes memory arr) internal pure returns (uint256 result) { + function test_unsafeAlloc_pads_free_mem_pointer_to_32_bytes() external pure { + // disable all compiler optimizations by including an assembly block not marked as mem-safe assembly { - result := arr + mstore(0x00, 0x1) } + + uint256 preAllocFreeMemPtr = getFreeMemPtr(); + + // assert free mem pointer is 32-byte aligned initially + Assert.isTrue(preAllocFreeMemPtr % 32 == 0); + + bytes memory arr = MemUtils.unsafeAllocateBytes(1); + Assert.length(arr, 1); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + + uint256 freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32); + preAllocFreeMemPtr = freeMemPtr; + + arr = MemUtils.unsafeAllocateBytes(20); + Assert.length(arr, 20); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32); + preAllocFreeMemPtr = freeMemPtr; + + arr = MemUtils.unsafeAllocateBytes(60); + Assert.length(arr, 60); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 64); + preAllocFreeMemPtr = freeMemPtr; + + arr = MemUtils.unsafeAllocateBytes(32 * 10 + 1); + Assert.length(arr, 32 * 10 + 1); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32 * 11); + preAllocFreeMemPtr = freeMemPtr; + + arr = MemUtils.unsafeAllocateBytes(32 * 100 + 15); + Assert.length(arr, 32 * 100 + 15); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 32 * 101); + } + + function test_unsafeAlloc_handles_misaligned_free_mem_pointer_and_pads_to_32_bytes() external pure { + uint256 freeMemPtr = getFreeMemPtr(); + + // assert free mem pointer is 32-byte aligned initially + Assert.isTrue(freeMemPtr % 32 == 0); + + // misalign the free mem pointer + uint256 preAllocFreeMemPtr = incrementFreeMemPtr(3); + + bytes memory arr = MemUtils.unsafeAllocateBytes(32); + Assert.length(arr, 32); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, (preAllocFreeMemPtr + 32 - 3) + 32 + 32); + + // misalign the free mem pointer + preAllocFreeMemPtr = incrementFreeMemPtr(1); + + arr = MemUtils.unsafeAllocateBytes(120); + Assert.length(arr, 120); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, (preAllocFreeMemPtr - 1) + 32 + 128); + + // misalign the free mem pointer + preAllocFreeMemPtr = incrementFreeMemPtr(32 - 12); + + arr = MemUtils.unsafeAllocateBytes(128 + 12); + Assert.length(arr, 128 + 12); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + 32 + 128 + 12); + + // misalign the free mem pointer + preAllocFreeMemPtr = incrementFreeMemPtr(5); + + arr = MemUtils.unsafeAllocateBytes(0); + Assert.empty(arr); + Assert.equal(getMemPtr(arr), preAllocFreeMemPtr); + + freeMemPtr = getFreeMemPtr(); + Assert.equal(freeMemPtr, preAllocFreeMemPtr + (32 - 5) + 32); + } + + /// + /// memcpy + /// + + function test_memcpy_copies_mem_chunks_that_are_multiples_of_32_bytes() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), + bytes32(0x4444444444444444444444444444444444444444444444444444444444444444), + bytes32(0x5555555555555555555555555555555555555555555555555555555555555555) + ); + + MemUtils.memcpy(getDataPtr(src), getDataPtr(dst), 64); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), + bytes32(0x5555555555555555555555555555555555555555555555555555555555555555) + )); + } + + function test_memcpy_copies_mem_chunks_that_are_multiples_of_32_bytes_from_a_non_32b_offset() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), + bytes32(0x3333333333333333333333333333333333333333333333333333333333333333) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x4444444444444444444444444444444444444444444444444444444444444444), + bytes32(0x5555555555555555555555555555555555555555555555555555555555555555), + bytes32(0x6666666666666666666666666666666666666666666666666666666666666666) + ); + + MemUtils.memcpy(getDataPtr(src) + 4, getDataPtr(dst), 64); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111122222222), + bytes32(0x2222222222222222222222222222222222222222222222222222222233333333), + bytes32(0x6666666666666666666666666666666666666666666666666666666666666666) + )); + } + + function test_memcpy_copies_mem_chunks_that_are_multiples_of_32b_to_a_non_32b_offset() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), + bytes32(0x4444444444444444444444444444444444444444444444444444444444444444), + bytes32(0x5555555555555555555555555555555555555555555555555555555555555555) + ); + + MemUtils.memcpy(getDataPtr(src), getDataPtr(dst) + 4, 64); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x3333333311111111111111111111111111111111111111111111111111111111), + bytes32(0x1111111122222222222222222222222222222222222222222222222222222222), + bytes32(0x2222222255555555555555555555555555555555555555555555555555555555) + )); + } + + function test_memcpy_copies_mem_chunks_that_are_multiples_of_32_bytes_from_and_to_a_non_32b_offset() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), + bytes32(0x3333333333333333333333333333333333333333333333333333333333333333) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x4444444444444444444444444444444444444444444444444444444444444444), + bytes32(0x5555555555555555555555555555555555555555555555555555555555555555), + bytes32(0x6666666666666666666666666666666666666666666666666666666666666666) + ); + + MemUtils.memcpy(getDataPtr(src) + 4, getDataPtr(dst) + 3, 64); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x4444441111111111111111111111111111111111111111111111111111111122), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222233), + bytes32(0x3333336666666666666666666666666666666666666666666666666666666666) + )); + } + + function test_memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), + bytes32(0x4444444444444444444444444444444444444444444444444444444444444444) + ); + + MemUtils.memcpy(getDataPtr(src), getDataPtr(dst), 42); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222244444444444444444444444444444444444444444444) + )); + } + + function test_memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes_from_a_non_32b_offset() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), + bytes32(0x4444444444444444444444444444444444444444444444444444444444444444) + ); + + MemUtils.memcpy(getDataPtr(src) + 3, getDataPtr(dst), 42); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111222222), + bytes32(0x2222222222222222222244444444444444444444444444444444444444444444) + )); + } + + function test_memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes_to_a_non_32b_offset() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), + bytes32(0x4444444444444444444444444444444444444444444444444444444444444444) + ); + + MemUtils.memcpy(getDataPtr(src), getDataPtr(dst) + 3, 42); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x3333331111111111111111111111111111111111111111111111111111111111), + bytes32(0x1111112222222222222222222244444444444444444444444444444444444444) + )); + } + + function test_memcpy_copies_mem_chunks_that_are_not_multiples_of_32_bytes_from_and_to_a_non_32b_offset() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x3333333333333333333333333333333333333333333333333333333333333333), + bytes32(0x4444444444444444444444444444444444444444444444444444444444444444) + ); + + MemUtils.memcpy(getDataPtr(src) + 3, getDataPtr(dst) + 4, 42); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x3333333311111111111111111111111111111111111111111111111111111111), + bytes32(0x1122222222222222222222222222444444444444444444444444444444444444) + )); + } + + function test_memcpy_copies_mem_chunks_shorter_than_32_bytes() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + MemUtils.memcpy(getDataPtr(src), getDataPtr(dst), 5); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x1111111111222222222222222222222222222222222222222222222222222222) + )); + } + + function test_memcpy_copies_mem_chunks_shorter_than_32_bytes_from_a_non_32b_offset() external pure { + bytes memory src = abi.encodePacked( + bytes32(0xcccccccccccccccccccccccccccccccccc8badf00d1234eeeeeeeeeeeeeeeeee) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + MemUtils.memcpy(getDataPtr(src) + 17, getDataPtr(dst), 4); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x8badf00d22222222222222222222222222222222222222222222222222222222) + )); + } + + function test_memcpy_copies_mem_chunks_shorter_than_32_bytes_to_a_non_32b_offset() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + MemUtils.memcpy(getDataPtr(src), getDataPtr(dst) + 5, 5); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x2222222222111111111122222222222222222222222222222222222222222222) + )); + } + + function test_memcpy_copies_mem_chunks_shorter_than_32_bytes_from_and_to_a_non_32b_offset() external pure { + bytes memory src = abi.encodePacked( + bytes32(0xcccccccccccccccccccccccccccccccccc8badf00d1234eeeeeeeeeeeeeeeeee) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + MemUtils.memcpy(getDataPtr(src) + 17, getDataPtr(dst) + 3, 4); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x2222228badf00d22222222222222222222222222222222222222222222222222) + )); + } + + function test_memcpy_zero_length_is_handled_correctly() external pure { + bytes memory src = abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111) + ); + + bytes memory dst = abi.encodePacked( + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + ); + + MemUtils.memcpy(getDataPtr(src) + 11, getDataPtr(dst) + 13, 0); + + Assert.equal(dst, abi.encodePacked( + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222) + )); + } + + /// + /// keccakUint256Array + /// + + function test_keccakUint256Array_calcs_keccak_over_a_uint_array() external pure { + uint256[] memory array = new uint256[](5); + array[0] = uint256(0x1111111111111111111111111111111111111111111111111111111111111111); + array[1] = uint256(0x2222222222222222222222222222222222222222222222222222222222222222); + array[2] = uint256(0x3333333333333333333333333333333333333333333333333333333333333333); + array[3] = uint256(0x4444444444444444444444444444444444444444444444444444444444444444); + array[4] = uint256(0x5555555555555555555555555555555555555555555555555555555555555555); + + bytes32 expected = keccak256(abi.encodePacked(array)); + bytes32 actual = MemUtils.keccakUint256Array(array); + + Assert.equal(actual, expected); + } + + function test_keccakUint256Array_calcs_keccak_over_an_empty_array() external pure { + uint256[] memory array = new uint256[](0); + + bytes32 expected = keccak256(abi.encodePacked(array)); + bytes32 actual = MemUtils.keccakUint256Array(array); + + Assert.equal(actual, expected); + } + + /// + /// trimUint256Array + /// + + function test_trimUint256Array_decreases_length_of_a_uint_array() external pure { + uint256[] memory array = new uint256[](5); + array[0] = uint256(0x1111111111111111111111111111111111111111111111111111111111111111); + array[1] = uint256(0x2222222222222222222222222222222222222222222222222222222222222222); + array[2] = uint256(0x3333333333333333333333333333333333333333333333333333333333333333); + array[3] = uint256(0x4444444444444444444444444444444444444444444444444444444444444444); + array[4] = uint256(0x5555555555555555555555555555555555555555555555555555555555555555); + + MemUtils.trimUint256Array(array, 2); + + Assert.equal(array.length, 3); + Assert.equal(array[0], uint256(0x1111111111111111111111111111111111111111111111111111111111111111)); + Assert.equal(array[1], uint256(0x2222222222222222222222222222222222222222222222222222222222222222)); + Assert.equal(array[2], uint256(0x3333333333333333333333333333333333333333333333333333333333333333)); + + Assert.equal(abi.encodePacked(array), abi.encodePacked( + bytes32(0x1111111111111111111111111111111111111111111111111111111111111111), + bytes32(0x2222222222222222222222222222222222222222222222222222222222222222), + bytes32(0x3333333333333333333333333333333333333333333333333333333333333333) + )); + } + + function test_trimUint256Array_allows_trimming_to_zero_length() external pure { + uint256[] memory array = new uint256[](3); + array[0] = uint256(0x1111111111111111111111111111111111111111111111111111111111111111); + array[1] = uint256(0x2222222222222222222222222222222222222222222222222222222222222222); + array[2] = uint256(0x3333333333333333333333333333333333333333333333333333333333333333); + + MemUtils.trimUint256Array(array, 3); + + Assert.empty(array); + } + + function test_trimUint256Array_reverts_on_trying_to_trim_by_more_than_length() external { + uint256[] memory array = new uint256[](3); + array[0] = uint256(0x1111111111111111111111111111111111111111111111111111111111111111); + array[1] = uint256(0x2222222222222222222222222222222222222222222222222222222222222222); + array[2] = uint256(0x3333333333333333333333333333333333333333333333333333333333333333); + + vm.expectRevert(); + MemUtils.trimUint256Array(array, 4); } } From 868c2c6a9f6f480a589e9da2ea241da62dfc3884 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Thu, 16 Feb 2023 16:47:05 +0700 Subject: [PATCH 054/199] test: AccountingOracle.submitReportExtraDataList checks items count --- ...ounting-oracle-submit-report-extra-data.test.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 3a7c49b55..e30089bd1 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -194,6 +194,20 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) }) + context('checks items count', () => { + it('reverts with UnexpectedExtraDataItemsCount if there was wrong amount of items', async () => { + const wrongItemsCount = 1 + const reportFields = { + extraDataItemsCount: wrongItemsCount + } + const { extraDataList, extraDataItems } = await prepareNextReportInNextFrame({ reportFields }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `UnexpectedExtraDataItemsCount(${reportFields.extraDataItemsCount}, ${extraDataItems.length})` + ) + }) + }) + context('enforces module ids sorting order', () => { beforeEach(deploy) From 276540433a9301f3f1bb0f005f6e53a866ec95bd Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Thu, 16 Feb 2023 17:14:40 +0700 Subject: [PATCH 055/199] test: AccountingOracle initial values zero-checking --- .../oracle/accounting-oracle-deploy.test.js | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-deploy.test.js b/test/0.8.9/oracle/accounting-oracle-deploy.test.js index bb4b2a56b..f5aff0a6d 100644 --- a/test/0.8.9/oracle/accounting-oracle-deploy.test.js +++ b/test/0.8.9/oracle/accounting-oracle-deploy.test.js @@ -1,3 +1,4 @@ +const { ZERO_ADDRESS } = require('@aragon/contract-helpers-test') const { assert } = require('../../helpers/assert') const { hex } = require('../../helpers/utils') const { @@ -39,6 +40,7 @@ const MockLegacyOracle = artifacts.require('MockLegacyOracle') const V1_ORACLE_LAST_COMPLETED_EPOCH = 2 * EPOCHS_PER_FRAME const V1_ORACLE_LAST_REPORT_SLOT = V1_ORACLE_LAST_COMPLETED_EPOCH * SLOTS_PER_EPOCH +const EXTRA_DATA_FORMAT_EMPTY = 0 const EXTRA_DATA_FORMAT_LIST = 1 const EXTRA_DATA_TYPE_STUCK_VALIDATORS = 1 @@ -138,6 +140,7 @@ module.exports = { CONSENSUS_VERSION, V1_ORACLE_LAST_COMPLETED_EPOCH, V1_ORACLE_LAST_REPORT_SLOT, + EXTRA_DATA_FORMAT_EMPTY, EXTRA_DATA_FORMAT_LIST, EXTRA_DATA_TYPE_STUCK_VALIDATORS, EXTRA_DATA_TYPE_EXITED_VALIDATORS, @@ -181,7 +184,9 @@ async function deployAccountingOracleSetup( secondsPerSlot = SECONDS_PER_SLOT, genesisTime = GENESIS_TIME, getLidoAndStakingRouter = deployMockLidoAndStakingRouter, - getLegacyOracle = deployMockLegacyOracle + getLegacyOracle = deployMockLegacyOracle, + lidoLocatorAddr: lidoLocatorAddrArg, + legacyOracleAddr: legacyOracleAddrArg } = {} ) { const locatorAddr = (await deployLocatorWithDummyAddressesImplementation(admin)).address @@ -202,9 +207,9 @@ async function deployAccountingOracleSetup( } const oracle = await AccountingOracle.new( - locatorAddr, + lidoLocatorAddrArg || locatorAddr, lido.address, - legacyOracle.address, + legacyOracleAddrArg || legacyOracle.address, secondsPerSlot, genesisTime, { from: admin } @@ -241,6 +246,7 @@ async function initAccountingOracle({ await oracle.grantRole(await oracle.SUBMIT_DATA_ROLE(), dataSubmitter, { from: admin }) } + assert.equal(+(await oracle.EXTRA_DATA_FORMAT_EMPTY()), EXTRA_DATA_FORMAT_EMPTY) assert.equal(+(await oracle.EXTRA_DATA_FORMAT_LIST()), EXTRA_DATA_FORMAT_LIST) assert.equal(+(await oracle.EXTRA_DATA_TYPE_STUCK_VALIDATORS()), EXTRA_DATA_TYPE_STUCK_VALIDATORS) assert.equal(+(await oracle.EXTRA_DATA_TYPE_EXITED_VALIDATORS()), EXTRA_DATA_TYPE_EXITED_VALIDATORS) @@ -350,5 +356,36 @@ contract('AccountingOracle', ([admin, member1]) => { assert.equal(await oracle.LIDO(), mockLido.address) assert.equal(+(await oracle.SECONDS_PER_SLOT()), SECONDS_PER_SLOT) }) + + it('reverts if lido locator address is zero', async () => { + await assert.reverts( + deployAccountingOracleSetup(admin, { lidoLocatorAddr: ZERO_ADDRESS }), + 'LidoLocatorCannotBeZero()' + ) + }) + + it('reverts if legacy oracle address is zero', async () => { + await assert.reverts( + deployAccountingOracleSetup(admin, { legacyOracleAddr: ZERO_ADDRESS }), + 'LegacyOracleCannotBeZero()' + ) + }) + + it('initialize reverts if admin address is zero', async () => { + const { consensus } = await deployAccountingOracleSetup(admin) + await assert.reverts( + oracle.initialize(ZERO_ADDRESS, consensus.address, CONSENSUS_VERSION, { from: admin }), + 'AdminCannotBeZero()' + ) + }) + + it('initializeWithoutMigration reverts if admin address is zero', async () => { + const { consensus } = await deployAccountingOracleSetup(admin) + const { refSlot } = await consensus.getCurrentFrame() + await assert.reverts( + oracle.initializeWithoutMigration(ZERO_ADDRESS, consensus.address, CONSENSUS_VERSION, refSlot, { from: admin }), + 'AdminCannotBeZero()' + ) + }) }) }) From af7d39c17d00eb9375c1976ad3308fe829500639 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 16 Feb 2023 17:44:50 +0700 Subject: [PATCH 056/199] feat: add more submitReportExtraDataList tests --- ...ng-oracle-submit-report-extra-data.test.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 3a7c49b55..2ed8e578d 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -522,6 +522,29 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) }) + it('reverts if extraData has already been already processed', async () => { + const { extraDataItems, extraDataList } = await prepareNextReportInNextFrame() + await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + const state = await oracle.getExtraDataProcessingState() + assert.equals(+state.itemsCount, extraDataItems.length) + assert.equals(+state.itemsCount, state.itemsProcessed) + await assert.revertsWithCustomError( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `ExtraDataAlreadyProcessed()` + ) + }) + + it('reverts if main data has not been processed yet', async () => { + await consensus.advanceTimeToNextFrameStart() + const { refSlot } = await consensus.getCurrentFrame() + const { reportFields, reportHash, extraDataList } = getReportData({ reportFields: { refSlot } }) + await consensus.submitReport(reportFields.refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) + await assert.revertsWithCustomError( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + 'CannotSubmitExtraDataBeforeMainData()' + ) + }) + it('updates extra data processing state', async () => { const { extraDataItems, extraDataHash, reportFields, extraDataList } = await prepareNextReportInNextFrame() From b768886ec3d4ef4d768bc8449b66e910383b96df Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 16 Feb 2023 19:20:30 +0700 Subject: [PATCH 057/199] feat: add extraDataFormat tests for submitReport --- .../oracle/accounting-oracle-deploy.test.js | 13 ++- ...counting-oracle-submit-report-data.test.js | 96 +++++++++++++++---- 2 files changed, 91 insertions(+), 18 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-deploy.test.js b/test/0.8.9/oracle/accounting-oracle-deploy.test.js index bb4b2a56b..54fa91db2 100644 --- a/test/0.8.9/oracle/accounting-oracle-deploy.test.js +++ b/test/0.8.9/oracle/accounting-oracle-deploy.test.js @@ -40,6 +40,7 @@ const V1_ORACLE_LAST_COMPLETED_EPOCH = 2 * EPOCHS_PER_FRAME const V1_ORACLE_LAST_REPORT_SLOT = V1_ORACLE_LAST_COMPLETED_EPOCH * SLOTS_PER_EPOCH const EXTRA_DATA_FORMAT_LIST = 1 +const EXTRA_DATA_FORMAT_EMPTY = 0 const EXTRA_DATA_TYPE_STUCK_VALIDATORS = 1 const EXTRA_DATA_TYPE_EXITED_VALIDATORS = 2 @@ -139,6 +140,7 @@ module.exports = { V1_ORACLE_LAST_COMPLETED_EPOCH, V1_ORACLE_LAST_REPORT_SLOT, EXTRA_DATA_FORMAT_LIST, + EXTRA_DATA_FORMAT_EMPTY, EXTRA_DATA_TYPE_STUCK_VALIDATORS, EXTRA_DATA_TYPE_EXITED_VALIDATORS, deployAndConfigureAccountingOracle, @@ -222,7 +224,16 @@ async function deployAccountingOracleSetup( // pretend we're at the first slot of the initial frame's epoch await consensus.setTime(genesisTime + initialEpoch * slotsPerEpoch * secondsPerSlot) - return { lido, stakingRouter, withdrawalQueue, locatorAddr, legacyOracle, oracle, consensus, oracleReportSanityChecker } + return { + lido, + stakingRouter, + withdrawalQueue, + locatorAddr, + legacyOracle, + oracle, + consensus, + oracleReportSanityChecker + } } async function initAccountingOracle({ diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js index 8446c4196..e4680fa30 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js @@ -10,6 +10,7 @@ const { calcExtraDataListHash, calcReportDataHash, EXTRA_DATA_FORMAT_LIST, + EXTRA_DATA_FORMAT_EMPTY, SLOTS_PER_FRAME, SECONDS_PER_SLOT, GENESIS_TIME, @@ -33,6 +34,23 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra let mockLegacyOracle = null let mockWithdrawalQueue = null + const getReportFields = (override = {}) => ({ + consensusVersion: CONSENSUS_VERSION, + numValidators: 10, + clBalanceGwei: e9(320), + stakingModuleIdsWithNewlyExitedValidators: [1], + numExitedValidatorsByStakingModule: [3], + withdrawalVaultBalance: e18(1), + elRewardsVaultBalance: e18(2), + lastWithdrawalRequestIdToFinalize: 1, + finalizationShareRate: e27(1), + isBunkerMode: true, + extraDataFormat: EXTRA_DATA_FORMAT_LIST, + extraDataHash: extraDataHash, + extraDataItemsCount: extraDataItems.length, + ...override + }) + const deploy = async (options = undefined) => { const deployed = await deployAndConfigureAccountingOracle(admin) const { refSlot } = await deployed.consensus.getCurrentFrame() @@ -52,22 +70,9 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra extraDataItems = encodeExtraDataItems(extraData) extraDataList = packExtraDataList(extraDataItems) extraDataHash = calcExtraDataListHash(extraDataList) - reportFields = { - consensusVersion: CONSENSUS_VERSION, - refSlot: +refSlot, - numValidators: 10, - clBalanceGwei: e9(320), - stakingModuleIdsWithNewlyExitedValidators: [1], - numExitedValidatorsByStakingModule: [3], - withdrawalVaultBalance: e18(1), - elRewardsVaultBalance: e18(2), - lastWithdrawalRequestIdToFinalize: 1, - finalizationShareRate: e27(1), - isBunkerMode: true, - extraDataFormat: EXTRA_DATA_FORMAT_LIST, - extraDataHash: extraDataHash, - extraDataItemsCount: extraDataItems.length - } + reportFields = getReportFields({ + refSlot: +refSlot + }) reportItems = getReportDataItems(reportFields) const reportHash = calcReportDataHash(reportItems) await deployed.consensus.addMember(member1, 1, { from: admin }) @@ -211,7 +216,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra ) }) - it('should should allow calling if correct consensus version', async () => { + it('should allow calling if correct consensus version', async () => { await consensus.setTime(deadline) const { refSlot } = await consensus.getCurrentFrame() @@ -491,6 +496,63 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra `UnsupportedExtraDataFormat(${EXTRA_DATA_FORMAT_LIST + 1})` ) }) + + it('should revert on non-empty format but zero length', async () => { + await consensus.setTime(deadline) + const { refSlot } = await consensus.getCurrentFrame() + const reportFields = getReportFields({ + refSlot: +refSlot, + extraDataItemsCount: 0 + }) + const reportItems = getReportDataItems(reportFields) + const reportHash = calcReportDataHash(reportItems) + await consensus.submitReport(refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) + await assert.revertsWithCustomError( + oracle.submitReportData(reportItems, oracleVersion, { from: member1 }), + `ExtraDataItemsCountCannotBeZeroForNonEmptyData()` + ) + }) + }) + + context('enforces zero extraData fields for the empty format', () => { + it('should revert for non empty ExtraDataHash', async () => { + await consensus.setTime(deadline) + const { refSlot } = await consensus.getCurrentFrame() + const nonZeroHash = web3.utils.keccak256('nonZeroHash') + const reportFields = getReportFields({ + refSlot: +refSlot, + isBunkerMode: false, + extraDataFormat: EXTRA_DATA_FORMAT_EMPTY, + extraDataHash: nonZeroHash, + extraDataItemsCount: 0 + }) + const reportItems = getReportDataItems(reportFields) + const reportHash = calcReportDataHash(reportItems) + await consensus.submitReport(refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) + await assert.revertsWithCustomError( + oracle.submitReportData(reportItems, oracleVersion, { from: member1 }), + `UnexpectedExtraDataHash("${ZERO_HASH}", "${nonZeroHash}")` + ) + }) + + it('should revert for non zero ExtraDataLength', async () => { + await consensus.setTime(deadline) + const { refSlot } = await consensus.getCurrentFrame() + const reportFields = getReportFields({ + refSlot: +refSlot, + isBunkerMode: false, + extraDataFormat: EXTRA_DATA_FORMAT_EMPTY, + extraDataHash: ZERO_HASH, + extraDataItemsCount: 10 + }) + const reportItems = getReportDataItems(reportFields) + const reportHash = calcReportDataHash(reportItems) + await consensus.submitReport(refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) + await assert.revertsWithCustomError( + oracle.submitReportData(reportItems, oracleVersion, { from: member1 }), + `UnexpectedExtraDataItemsCount(0, 10)` + ) + }) }) context('ExtraDataProcessingState', () => { From 39c4fe1b572713172db112ced8252bd810135e65 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Thu, 16 Feb 2023 19:36:56 +0700 Subject: [PATCH 058/199] fix: switch reverts position in AccountOracle._submitReportExtraDataList --- contracts/0.8.9/oracle/AccountingOracle.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/0.8.9/oracle/AccountingOracle.sol b/contracts/0.8.9/oracle/AccountingOracle.sol index 0359c94a3..12a95d121 100644 --- a/contracts/0.8.9/oracle/AccountingOracle.sol +++ b/contracts/0.8.9/oracle/AccountingOracle.sol @@ -671,6 +671,10 @@ contract AccountingOracle is BaseOracle { revert CannotSubmitExtraDataBeforeMainData(); } + if (procState.dataFormat != EXTRA_DATA_FORMAT_LIST) { + revert UnexpectedExtraDataFormat(procState.dataFormat, EXTRA_DATA_FORMAT_LIST); + } + if (procState.itemsProcessed == procState.itemsCount) { revert ExtraDataAlreadyProcessed(); } @@ -679,10 +683,6 @@ contract AccountingOracle is BaseOracle { revert ExtraDataListOnlySupportsSingleTx(); } - if (procState.dataFormat != EXTRA_DATA_FORMAT_LIST) { - revert UnexpectedExtraDataFormat(procState.dataFormat, EXTRA_DATA_FORMAT_LIST); - } - bytes32 dataHash = keccak256(items); if (dataHash != procState.dataHash) { revert UnexpectedExtraDataHash(procState.dataHash, dataHash); From 8f14b1493f7aef78ba93efe7884527ca99004a8a Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Thu, 16 Feb 2023 19:38:16 +0700 Subject: [PATCH 059/199] fix: replace check for maxNodeOperatorsPerItem to assert in AccountingOracle._processExtraDataItems --- contracts/0.8.9/oracle/AccountingOracle.sol | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/contracts/0.8.9/oracle/AccountingOracle.sol b/contracts/0.8.9/oracle/AccountingOracle.sol index 12a95d121..144d15a45 100644 --- a/contracts/0.8.9/oracle/AccountingOracle.sol +++ b/contracts/0.8.9/oracle/AccountingOracle.sol @@ -759,10 +759,9 @@ contract AccountingOracle is BaseOracle { dataOffset = iter.dataOffset; } - if (maxNodeOperatorsPerItem > 0) { - IOracleReportSanityChecker(LOCATOR.oracleReportSanityChecker()) - .checkNodeOperatorsPerExtraDataItemCount(maxNodeOperatorItemIndex, maxNodeOperatorsPerItem); - } + assert(maxNodeOperatorsPerItem > 0); + IOracleReportSanityChecker(LOCATOR.oracleReportSanityChecker()) + .checkNodeOperatorsPerExtraDataItemCount(maxNodeOperatorItemIndex, maxNodeOperatorsPerItem); } function _processExtraDataItem(bytes calldata data, ExtraDataIterState memory iter) internal returns (uint256) { From 3990e5506b5667bd12bf2992ab68fb0e2f4dbc0d Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Thu, 16 Feb 2023 19:40:57 +0700 Subject: [PATCH 060/199] test: AccountingOracle.submitReportExtraDataList enforces data format --- ...ting-oracle-submit-report-extra-data.test.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index a5da71d05..40741e184 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -10,6 +10,8 @@ const { packExtraDataList, calcExtraDataListHash, calcReportDataHash, + ZERO_HASH, + EXTRA_DATA_FORMAT_EMPTY, EXTRA_DATA_FORMAT_LIST, EXTRA_DATA_TYPE_STUCK_VALIDATORS } = require('./accounting-oracle-deploy.test') @@ -208,6 +210,21 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) }) + context('enforces data format', () => { + it('reverts with UnexpectedExtraDataFormat if there was empty format submitted on first phase', async () => { + const reportFields = { + extraDataHash: ZERO_HASH, + extraDataFormat: EXTRA_DATA_FORMAT_EMPTY, + extraDataItemsCount: 0 + } + const { extraDataList } = await prepareNextReportInNextFrame({ reportFields }) + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + `UnexpectedExtraDataFormat(${EXTRA_DATA_FORMAT_EMPTY}, ${EXTRA_DATA_FORMAT_LIST})` + ) + }) + }) + context('enforces module ids sorting order', () => { beforeEach(deploy) From c7c46c34b12dd19587b4b1e6f7470de9084aee34 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Thu, 16 Feb 2023 19:58:35 +0700 Subject: [PATCH 061/199] test: fix doubled constant --- test/0.8.9/oracle/accounting-oracle-deploy.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-deploy.test.js b/test/0.8.9/oracle/accounting-oracle-deploy.test.js index af31beab9..9295e4baf 100644 --- a/test/0.8.9/oracle/accounting-oracle-deploy.test.js +++ b/test/0.8.9/oracle/accounting-oracle-deploy.test.js @@ -40,7 +40,6 @@ const MockLegacyOracle = artifacts.require('MockLegacyOracle') const V1_ORACLE_LAST_COMPLETED_EPOCH = 2 * EPOCHS_PER_FRAME const V1_ORACLE_LAST_REPORT_SLOT = V1_ORACLE_LAST_COMPLETED_EPOCH * SLOTS_PER_EPOCH -const EXTRA_DATA_FORMAT_EMPTY = 0 const EXTRA_DATA_FORMAT_LIST = 1 const EXTRA_DATA_FORMAT_EMPTY = 0 @@ -143,7 +142,6 @@ module.exports = { V1_ORACLE_LAST_REPORT_SLOT, EXTRA_DATA_FORMAT_EMPTY, EXTRA_DATA_FORMAT_LIST, - EXTRA_DATA_FORMAT_EMPTY, EXTRA_DATA_TYPE_STUCK_VALIDATORS, EXTRA_DATA_TYPE_EXITED_VALIDATORS, deployAndConfigureAccountingOracle, From 3c14ab0a03f6744e30362f6312f6a16c5af22960 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 16 Feb 2023 20:09:18 +0700 Subject: [PATCH 062/199] feat: add extra check for extraData format --- contracts/0.8.9/oracle/AccountingOracle.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/0.8.9/oracle/AccountingOracle.sol b/contracts/0.8.9/oracle/AccountingOracle.sol index 144d15a45..09c533d38 100644 --- a/contracts/0.8.9/oracle/AccountingOracle.sol +++ b/contracts/0.8.9/oracle/AccountingOracle.sol @@ -101,6 +101,7 @@ contract AccountingOracle is BaseOracle { error UnexpectedExtraDataHash(bytes32 consensusHash, bytes32 receivedHash); error UnexpectedExtraDataFormat(uint256 expectedFormat, uint256 receivedFormat); error ExtraDataItemsCountCannotBeZeroForNonEmptyData(); + error ExtraDataHashCannotBeZeroForNonEmptyData(); error UnexpectedExtraDataItemsCount(uint256 expectedCount, uint256 receivedCount); error UnexpectedExtraDataIndex(uint256 expectedIndex, uint256 receivedIndex); error InvalidExtraDataItem(uint256 itemIndex); @@ -553,6 +554,9 @@ contract AccountingOracle is BaseOracle { if (data.extraDataItemsCount == 0) { revert ExtraDataItemsCountCannotBeZeroForNonEmptyData(); } + if (data.extraDataHash == bytes32(0)) { + revert ExtraDataHashCannotBeZeroForNonEmptyData(); + } } IOracleReportSanityChecker(LOCATOR.oracleReportSanityChecker()) From 25153b9120f5df9951105cb31b11ed7c2081e00b Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 16 Feb 2023 20:10:35 +0700 Subject: [PATCH 063/199] feat: test for zeroHash non empty data --- .../oracle/accounting-oracle-deploy.test.js | 1 - .../accounting-oracle-submit-report-data.test.js | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/test/0.8.9/oracle/accounting-oracle-deploy.test.js b/test/0.8.9/oracle/accounting-oracle-deploy.test.js index af31beab9..8ae6dd597 100644 --- a/test/0.8.9/oracle/accounting-oracle-deploy.test.js +++ b/test/0.8.9/oracle/accounting-oracle-deploy.test.js @@ -42,7 +42,6 @@ const V1_ORACLE_LAST_REPORT_SLOT = V1_ORACLE_LAST_COMPLETED_EPOCH * SLOTS_PER_EP const EXTRA_DATA_FORMAT_EMPTY = 0 const EXTRA_DATA_FORMAT_LIST = 1 -const EXTRA_DATA_FORMAT_EMPTY = 0 const EXTRA_DATA_TYPE_STUCK_VALIDATORS = 1 const EXTRA_DATA_TYPE_EXITED_VALIDATORS = 2 diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js index e4680fa30..a580ddca9 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js @@ -512,6 +512,22 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra `ExtraDataItemsCountCannotBeZeroForNonEmptyData()` ) }) + + it('should revert on non-empty format but zero hash', async () => { + await consensus.setTime(deadline) + const { refSlot } = await consensus.getCurrentFrame() + const reportFields = getReportFields({ + refSlot: +refSlot, + extraDataHash: ZERO_HASH + }) + const reportItems = getReportDataItems(reportFields) + const reportHash = calcReportDataHash(reportItems) + await consensus.submitReport(refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) + await assert.revertsWithCustomError( + oracle.submitReportData(reportItems, oracleVersion, { from: member1 }), + `ExtraDataHashCannotBeZeroForNonEmptyData()` + ) + }) }) context('enforces zero extraData fields for the empty format', () => { From 2b10209db006c7fa4959989877457499710af26f Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 16 Feb 2023 20:11:16 +0700 Subject: [PATCH 064/199] chore: abi --- lib/abi/AccountingOracle.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/abi/AccountingOracle.json b/lib/abi/AccountingOracle.json index 13f5f9002..37abb6eff 100644 --- a/lib/abi/AccountingOracle.json +++ b/lib/abi/AccountingOracle.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"lidoLocator","type":"address"},{"internalType":"address","name":"lido","type":"address"},{"internalType":"address","name":"legacyOracle","type":"address"},{"internalType":"uint256","name":"secondsPerSlot","type":"uint256"},{"internalType":"uint256","name":"genesisTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressCannotBeSame","type":"error"},{"inputs":[],"name":"AddressCannotBeZero","type":"error"},{"inputs":[],"name":"AdminCannotBeZero","type":"error"},{"inputs":[],"name":"CannotSubmitExtraDataBeforeMainData","type":"error"},{"inputs":[],"name":"ExtraDataAlreadyProcessed","type":"error"},{"inputs":[],"name":"ExtraDataListOnlySupportsSingleTx","type":"error"},{"inputs":[{"internalType":"uint256","name":"code","type":"uint256"}],"name":"IncorrectOracleMigration","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidExitedValidatorsData","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"name":"InvalidExtraDataItem","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"name":"InvalidExtraDataSortOrder","type":"error"},{"inputs":[],"name":"LegacyOracleCannotBeZero","type":"error"},{"inputs":[],"name":"LidoLocatorCannotBeZero","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NumExitedValidatorsCannotDecrease","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ProcessingDeadlineMissed","type":"error"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"SenderNotAllowed","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":"expectedFormat","type":"uint256"},{"internalType":"uint256","name":"receivedFormat","type":"uint256"}],"name":"UnexpectedExtraDataFormat","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedIndex","type":"uint256"},{"internalType":"uint256","name":"receivedIndex","type":"uint256"}],"name":"UnexpectedExtraDataIndex","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedCount","type":"uint256"},{"internalType":"uint256","name":"receivedCount","type":"uint256"}],"name":"UnexpectedExtraDataItemsCount","type":"error"},{"inputs":[{"internalType":"uint256","name":"consensusRefSlot","type":"uint256"},{"internalType":"uint256","name":"dataRefSlot","type":"uint256"}],"name":"UnexpectedRefSlot","type":"error"},{"inputs":[{"internalType":"uint256","name":"format","type":"uint256"}],"name":"UnsupportedExtraDataFormat","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"},{"internalType":"uint256","name":"dataType","type":"uint256"}],"name":"UnsupportedExtraDataType","type":"error"},{"inputs":[],"name":"VersionCannotBeSame","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":true,"internalType":"uint256","name":"refSlot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsProcessed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsCount","type":"uint256"}],"name":"ExtraDataSubmitted","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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"refSlot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"processedItemsCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsCount","type":"uint256"}],"name":"WarnExtraDataIncompleteProcessing","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refSlot","type":"uint256"}],"name":"WarnProcessingMissed","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_FORMAT_LIST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_TYPE_EXITED_VALIDATORS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_TYPE_STUCK_VALIDATORS","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":"LEGACY_ORACLE","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":"LOCATOR","outputs":[{"internalType":"contract ILidoLocator","name":"","type":"address"}],"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":"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":"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":[],"name":"getLastProcessingRefSlot","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":"mainDataHash","type":"bytes32"},{"internalType":"bool","name":"mainDataSubmitted","type":"bool"},{"internalType":"bytes32","name":"extraDataHash","type":"bytes32"},{"internalType":"uint256","name":"extraDataFormat","type":"uint256"},{"internalType":"uint256","name":"extraDataItemsCount","type":"uint256"},{"internalType":"uint256","name":"extraDataItemsSubmitted","type":"uint256"}],"internalType":"struct AccountingOracle.ProcessingState","name":"result","type":"tuple"}],"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":"admin","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","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"}],"name":"initializeWithoutMigration","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":[{"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":"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":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"numValidators","type":"uint256"},{"internalType":"uint256","name":"clBalanceGwei","type":"uint256"},{"internalType":"uint256[]","name":"stakingModuleIdsWithNewlyExitedValidators","type":"uint256[]"},{"internalType":"uint256[]","name":"numExitedValidatorsByStakingModule","type":"uint256[]"},{"internalType":"uint256","name":"withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"lastFinalizableWithdrawalRequestId","type":"uint256"},{"internalType":"uint256","name":"simulatedShareRate","type":"uint256"},{"internalType":"bool","name":"isBunkerMode","type":"bool"},{"internalType":"uint256","name":"extraDataFormat","type":"uint256"},{"internalType":"bytes32","name":"extraDataHash","type":"bytes32"},{"internalType":"uint256","name":"extraDataItemsCount","type":"uint256"}],"internalType":"struct AccountingOracle.ReportData","name":"data","type":"tuple"},{"internalType":"uint256","name":"contractVersion","type":"uint256"}],"name":"submitReportData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"items","type":"bytes"}],"name":"submitReportExtraDataList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"lidoLocator","type":"address"},{"internalType":"address","name":"lido","type":"address"},{"internalType":"address","name":"legacyOracle","type":"address"},{"internalType":"uint256","name":"secondsPerSlot","type":"uint256"},{"internalType":"uint256","name":"genesisTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressCannotBeSame","type":"error"},{"inputs":[],"name":"AddressCannotBeZero","type":"error"},{"inputs":[],"name":"AdminCannotBeZero","type":"error"},{"inputs":[],"name":"CannotSubmitExtraDataBeforeMainData","type":"error"},{"inputs":[],"name":"ExtraDataAlreadyProcessed","type":"error"},{"inputs":[],"name":"ExtraDataHashCannotBeZeroForNonEmptyData","type":"error"},{"inputs":[],"name":"ExtraDataItemsCountCannotBeZeroForNonEmptyData","type":"error"},{"inputs":[],"name":"ExtraDataListOnlySupportsSingleTx","type":"error"},{"inputs":[{"internalType":"uint256","name":"code","type":"uint256"}],"name":"IncorrectOracleMigration","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidExitedValidatorsData","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"name":"InvalidExtraDataItem","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"name":"InvalidExtraDataSortOrder","type":"error"},{"inputs":[],"name":"LegacyOracleCannotBeZero","type":"error"},{"inputs":[],"name":"LidoLocatorCannotBeZero","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NumExitedValidatorsCannotDecrease","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ProcessingDeadlineMissed","type":"error"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"SenderNotAllowed","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":"expectedFormat","type":"uint256"},{"internalType":"uint256","name":"receivedFormat","type":"uint256"}],"name":"UnexpectedExtraDataFormat","type":"error"},{"inputs":[{"internalType":"bytes32","name":"consensusHash","type":"bytes32"},{"internalType":"bytes32","name":"receivedHash","type":"bytes32"}],"name":"UnexpectedExtraDataHash","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedIndex","type":"uint256"},{"internalType":"uint256","name":"receivedIndex","type":"uint256"}],"name":"UnexpectedExtraDataIndex","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedCount","type":"uint256"},{"internalType":"uint256","name":"receivedCount","type":"uint256"}],"name":"UnexpectedExtraDataItemsCount","type":"error"},{"inputs":[{"internalType":"uint256","name":"consensusRefSlot","type":"uint256"},{"internalType":"uint256","name":"dataRefSlot","type":"uint256"}],"name":"UnexpectedRefSlot","type":"error"},{"inputs":[{"internalType":"uint256","name":"format","type":"uint256"}],"name":"UnsupportedExtraDataFormat","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"},{"internalType":"uint256","name":"dataType","type":"uint256"}],"name":"UnsupportedExtraDataType","type":"error"},{"inputs":[],"name":"VersionCannotBeSame","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":true,"internalType":"uint256","name":"refSlot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsProcessed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsCount","type":"uint256"}],"name":"ExtraDataSubmitted","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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"refSlot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"processedItemsCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsCount","type":"uint256"}],"name":"WarnExtraDataIncompleteProcessing","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refSlot","type":"uint256"}],"name":"WarnProcessingMissed","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_FORMAT_EMPTY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_FORMAT_LIST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_TYPE_EXITED_VALIDATORS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_TYPE_STUCK_VALIDATORS","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":"LEGACY_ORACLE","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":"LOCATOR","outputs":[{"internalType":"contract ILidoLocator","name":"","type":"address"}],"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":"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":"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":[],"name":"getLastProcessingRefSlot","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":"mainDataHash","type":"bytes32"},{"internalType":"bool","name":"mainDataSubmitted","type":"bool"},{"internalType":"bytes32","name":"extraDataHash","type":"bytes32"},{"internalType":"uint256","name":"extraDataFormat","type":"uint256"},{"internalType":"uint256","name":"extraDataItemsCount","type":"uint256"},{"internalType":"uint256","name":"extraDataItemsSubmitted","type":"uint256"}],"internalType":"struct AccountingOracle.ProcessingState","name":"result","type":"tuple"}],"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":"admin","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","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"}],"name":"initializeWithoutMigration","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":[{"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":"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":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"numValidators","type":"uint256"},{"internalType":"uint256","name":"clBalanceGwei","type":"uint256"},{"internalType":"uint256[]","name":"stakingModuleIdsWithNewlyExitedValidators","type":"uint256[]"},{"internalType":"uint256[]","name":"numExitedValidatorsByStakingModule","type":"uint256[]"},{"internalType":"uint256","name":"withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"lastFinalizableWithdrawalRequestId","type":"uint256"},{"internalType":"uint256","name":"simulatedShareRate","type":"uint256"},{"internalType":"bool","name":"isBunkerMode","type":"bool"},{"internalType":"uint256","name":"extraDataFormat","type":"uint256"},{"internalType":"bytes32","name":"extraDataHash","type":"bytes32"},{"internalType":"uint256","name":"extraDataItemsCount","type":"uint256"}],"internalType":"struct AccountingOracle.ReportData","name":"data","type":"tuple"},{"internalType":"uint256","name":"contractVersion","type":"uint256"}],"name":"submitReportData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"items","type":"bytes"}],"name":"submitReportExtraDataList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file From 08980f02dee1d50b7d363ba78805d06696da0375 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Thu, 16 Feb 2023 20:12:35 +0700 Subject: [PATCH 065/199] fix: missing export --- test/0.8.9/oracle/accounting-oracle-deploy.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/0.8.9/oracle/accounting-oracle-deploy.test.js b/test/0.8.9/oracle/accounting-oracle-deploy.test.js index 3be48f907..0a6c5cf9f 100644 --- a/test/0.8.9/oracle/accounting-oracle-deploy.test.js +++ b/test/0.8.9/oracle/accounting-oracle-deploy.test.js @@ -40,8 +40,10 @@ const MockLegacyOracle = artifacts.require('MockLegacyOracle') const V1_ORACLE_LAST_COMPLETED_EPOCH = 2 * EPOCHS_PER_FRAME const V1_ORACLE_LAST_REPORT_SLOT = V1_ORACLE_LAST_COMPLETED_EPOCH * SLOTS_PER_EPOCH +const EXTRA_DATA_FORMAT_EMPTY = 0 const EXTRA_DATA_FORMAT_LIST = 1 + const EXTRA_DATA_TYPE_STUCK_VALIDATORS = 1 const EXTRA_DATA_TYPE_EXITED_VALIDATORS = 2 function getReportDataItems(r) { From 86e51c30be7d27df2ae3f071c210df308209cbd6 Mon Sep 17 00:00:00 2001 From: Artyom Veremeenko Date: Thu, 16 Feb 2023 17:40:20 +0400 Subject: [PATCH 066/199] PausableUntil: add tests and getResumeSinceTimestamp() view --- .../PausableUntilPrivateExposed.sol | 27 +++++ contracts/0.8.9/utils/PausableUntil.sol | 10 +- lib/abi/ValidatorsExitBusOracle.json | 2 +- lib/abi/WithdrawalQueue.json | 2 +- lib/abi/WithdrawalRequestNFT.json | 2 +- test/0.4.24/lido.test.js | 14 +-- .../node-operators-registry-penalty.test.js | 5 +- .../oracle-report-sanity-checker.test.js | 10 +- test/0.8.9/pausable-until.test.js | 105 ++++++++++++++++++ test/helpers/blockchain.js | 16 ++- 10 files changed, 170 insertions(+), 23 deletions(-) create mode 100644 contracts/0.8.9/test_helpers/PausableUntilPrivateExposed.sol create mode 100644 test/0.8.9/pausable-until.test.js diff --git a/contracts/0.8.9/test_helpers/PausableUntilPrivateExposed.sol b/contracts/0.8.9/test_helpers/PausableUntilPrivateExposed.sol new file mode 100644 index 000000000..acf1d7973 --- /dev/null +++ b/contracts/0.8.9/test_helpers/PausableUntilPrivateExposed.sol @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2023 Lido +// SPDX-License-Identifier: GPL-3.0 + +/* See contracts/COMPILERS.md */ +pragma solidity 0.8.9; + +import {PausableUntil} from "../utils/PausableUntil.sol"; + +contract PausableUntilPrivateExposed is PausableUntil { + + function stubUnderModifierWhenPaused() external view whenPaused returns (uint256) { + return 42; + } + + function stubUnderModifierWhenResumed() external view whenResumed returns (uint256) { + return 42; + } + + function resume() external { + _resume(); + } + + function pause(uint256 _duration) external { + _pause(_duration); + } + +} diff --git a/contracts/0.8.9/utils/PausableUntil.sol b/contracts/0.8.9/utils/PausableUntil.sol index 3bbd1b570..9d1e03cf1 100644 --- a/contracts/0.8.9/utils/PausableUntil.sol +++ b/contracts/0.8.9/utils/PausableUntil.sol @@ -43,7 +43,15 @@ contract PausableUntil { return block.timestamp < RESUME_SINCE_TIMESTAMP_POSITION.getStorageUint256(); } - function _resume() internal { + /// @notice Returns one of: + /// - PAUSE_INFINITELY if paused infinitely returns + /// - first second when get contract get resumed if paused for specific duration + /// - some timestamp in pase if not paused + function getResumeSinceTimestamp() external view returns (uint256) { + return RESUME_SINCE_TIMESTAMP_POSITION.getStorageUint256(); + } + + function _resume() internal whenPaused { RESUME_SINCE_TIMESTAMP_POSITION.setStorageUint256(block.timestamp); emit Resumed(); diff --git a/lib/abi/ValidatorsExitBusOracle.json b/lib/abi/ValidatorsExitBusOracle.json index 7ac4b56fb..ea5c3c016 100644 --- a/lib/abi/ValidatorsExitBusOracle.json +++ b/lib/abi/ValidatorsExitBusOracle.json @@ -1 +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":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidRequestsData","type":"error"},{"inputs":[],"name":"InvalidRequestsDataLength","type":"error"},{"inputs":[],"name":"InvalidRequestsDataSortOrder","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ProcessingDeadlineMissed","type":"error"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"ResumedExpected","type":"error"},{"inputs":[],"name":"SenderNotAllowed","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":[],"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":"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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"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":"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":[],"name":"getLastProcessingRefSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256[]","name":"nodeOpIds","type":"uint256[]"}],"name":"getLastRequestedValidatorIndices","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"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":[{"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":"pauser","type":"address"},{"internalType":"address","name":"resumer","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"lastProcessingRefSlot","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":"pause","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":"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":"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"}] \ No newline at end of file +[{"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":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidRequestsData","type":"error"},{"inputs":[],"name":"InvalidRequestsDataLength","type":"error"},{"inputs":[],"name":"InvalidRequestsDataSortOrder","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ProcessingDeadlineMissed","type":"error"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"ResumedExpected","type":"error"},{"inputs":[],"name":"SenderNotAllowed","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":[],"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":"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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"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":"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":[],"name":"getLastProcessingRefSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256[]","name":"nodeOpIds","type":"uint256[]"}],"name":"getLastRequestedValidatorIndices","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"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":"pauser","type":"address"},{"internalType":"address","name":"resumer","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"lastProcessingRefSlot","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":"pause","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":"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":"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"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueue.json b/lib/abi/WithdrawalQueue.json index e81ab351d..31a89cc07 100644 --- a/lib/abi/WithdrawalQueue.json +++ b/lib/abi/WithdrawalQueue.json @@ -1 +1 @@ -[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalRequestNFT.json b/lib/abi/WithdrawalRequestNFT.json index 0ccb54190..89d976ef8 100644 --- a/lib/abi/WithdrawalRequestNFT.json +++ b/lib/abi/WithdrawalRequestNFT.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/test/0.4.24/lido.test.js b/test/0.4.24/lido.test.js index f5a951102..deed45f39 100644 --- a/test/0.4.24/lido.test.js +++ b/test/0.4.24/lido.test.js @@ -9,7 +9,7 @@ const { assertBn, assertEvent } = require('@aragon/contract-helpers-test/src/ass const { assertRevert } = require('../helpers/assertThrow') const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') const { formatEther } = require('ethers/lib/utils') -const { waitBlocks, EvmSnapshot } = require('../helpers/blockchain') +const { waitBlocks, EvmSnapshot, advanceChainTime, getCurrentBlockTimestamp } = require('../helpers/blockchain') const { getEthBalance, formatStEth, @@ -54,11 +54,6 @@ const MAX_DEPOSITS = 150 const CURATED_MODULE_ID = 1 const CALLDATA = '0x0' -async function getTimestamp() { - const blockNum = await ethers.provider.getBlockNumber(); - const block = await ethers.provider.getBlock(blockNum); - return block.timestamp; -} contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody, depositor, treasury]) => { let app, oracle, depositContract, operators @@ -134,8 +129,7 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody const pushReport = async (clValidators, clBalance) => { const elRewards = await web3.eth.getBalance(elRewardsVault.address) await pushOracleReport(consensus, oracle, clValidators, clBalance, elRewards) - await ethers.provider.send('evm_increaseTime', [SECONDS_PER_FRAME + 1000]) - await ethers.provider.send('evm_mine') + await advanceChainTime(SECONDS_PER_FRAME + 1000) } const checkStat = async ({ depositedValidators, beaconValidators, beaconBalance }) => { @@ -1023,14 +1017,14 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody await checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) await assertRevert( - app.handleOracleReport(await getTimestamp(), 1, ETH(30), 0, 0, 0, 0, 0, { from: appManager }), + app.handleOracleReport(await getCurrentBlockTimestamp(), 1, ETH(30), 0, 0, 0, 0, 0, { from: appManager }), 'APP_AUTH_FAILED' ) await pushReport(1, ETH(30)) await checkStat({ depositedValidators: 1, beaconValidators: 1, beaconBalance: ETH(30) }) - await assertRevert(app.handleOracleReport(await getTimestamp(), 1, ETH(29), 0, 0, 0, 0, 0, { from: nobody }), 'APP_AUTH_FAILED') + await assertRevert(app.handleOracleReport(await getCurrentBlockTimestamp(), 1, ETH(29), 0, 0, 0, 0, 0, { from: nobody }), 'APP_AUTH_FAILED') await pushReport(1, ETH(100)) // stale data await checkStat({ depositedValidators: 1, beaconValidators: 1, beaconBalance: ETH(100) }) diff --git a/test/0.4.24/node-operators-registry-penalty.test.js b/test/0.4.24/node-operators-registry-penalty.test.js index cfb05752b..4f2837006 100644 --- a/test/0.4.24/node-operators-registry-penalty.test.js +++ b/test/0.4.24/node-operators-registry-penalty.test.js @@ -4,7 +4,7 @@ const { assertRevert } = require('../helpers/assertThrow') const { toBN, padRight, printEvents } = require('../helpers/utils') const { BN } = require('bn.js') const { AragonDAO } = require('./helpers/dao') -const { EvmSnapshot } = require('../helpers/blockchain') +const { EvmSnapshot, advanceChainTime } = require('../helpers/blockchain') const { ZERO_ADDRESS, getEventAt, bn } = require('@aragon/contract-helpers-test') const nodeOperators = require('../helpers/node-operators') const signingKeys = require('../helpers/signing-keys') @@ -351,8 +351,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use await app.updateRefundedValidatorsCount(firstNodeOperator, 1, { from: voting }) assert.isTrue(await app.testing_isNodeOperatorPenalized(firstNodeOperator)) - await hre.network.provider.send('evm_increaseTime', [2 * 24 * 60 * 60 + 10]) - await hre.network.provider.send('evm_mine') + await advanceChainTime(2 * 24 * 60 * 60 + 10) assert.isFalse(await app.testing_isNodeOperatorPenalized(firstNodeOperator)) diff --git a/test/0.8.9/oracle-report-sanity-checker.test.js b/test/0.8.9/oracle-report-sanity-checker.test.js index aec6dab7d..460bc9691 100644 --- a/test/0.8.9/oracle-report-sanity-checker.test.js +++ b/test/0.8.9/oracle-report-sanity-checker.test.js @@ -1,6 +1,7 @@ const hre = require('hardhat') const { ETH } = require('../helpers/utils') const { assert } = require('../helpers/assert') +const { getCurrentBlockTimestamp } = require('../helpers/blockchain') const mocksFilePath = 'contracts/0.8.9/test_helpers/OracleReportSanityCheckerMocks.sol' const LidoStub = hre.artifacts.require(`${mocksFilePath}:LidoStub`) @@ -192,13 +193,12 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa } before(async () => { - const currentBlockNumber = await hre.ethers.provider.getBlockNumber() - const currentBlock = await hre.ethers.provider.getBlock(currentBlockNumber) - correctWithdrawalQueueOracleReport.refReportTimestamp = currentBlock.timestamp - oldRequestCreationTimestamp = currentBlock.timestamp - defaultLimitsList.requestTimestampMargin + const currentBlockTimestamp = await getCurrentBlockTimestamp() + correctWithdrawalQueueOracleReport.refReportTimestamp = currentBlockTimestamp + oldRequestCreationTimestamp = currentBlockTimestamp - defaultLimitsList.requestTimestampMargin correctWithdrawalQueueOracleReport.requestIdToFinalizeUpTo = oldRequestCreationTimestamp await withdrawalQueueMock.setRequestBlockNumber(oldRequestId, oldRequestCreationTimestamp) - newRequestCreationTimestamp = currentBlock.timestamp - Math.floor(defaultLimitsList.requestTimestampMargin / 2) + newRequestCreationTimestamp = currentBlockTimestamp - Math.floor(defaultLimitsList.requestTimestampMargin / 2) await withdrawalQueueMock.setRequestBlockNumber(newRequestId, newRequestCreationTimestamp) }) diff --git a/test/0.8.9/pausable-until.test.js b/test/0.8.9/pausable-until.test.js new file mode 100644 index 000000000..4f56f1f1e --- /dev/null +++ b/test/0.8.9/pausable-until.test.js @@ -0,0 +1,105 @@ +const hre = require('hardhat') + +const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') +const { EvmSnapshot, advanceChainTime, getCurrentBlockTimestamp } = require('../helpers/blockchain') +const { ETH, StETH } = require('../helpers/utils') +const { assert } = require('../helpers/assert') + +const PausableUntil = artifacts.require('PausableUntilPrivateExposed') + + + + +contract('PausableUntil', ([deployer, _, anotherAccount]) => { + let pausable + let PAUSE_INFINITELY + + before('deploy lido with dao', async () => { + pausable = await PausableUntil.new( { from: deployer }) + PAUSE_INFINITELY = await pausable.PAUSE_INFINITELY() + + snapshot = new EvmSnapshot(hre.ethers.provider) + await snapshot.make() + }) + + afterEach(async () => { + await snapshot.rollback() + }) + + /// Check views, modifiers and capability to pause/resume + async function assertPausedState(resumeSinceTimestamp = undefined) { + assert.isTrue(await pausable.isPaused()) + assert.isTrue(await pausable.getResumeSinceTimestamp() > await getCurrentBlockTimestamp()) + assert.equals(await pausable.stubUnderModifierWhenPaused(), bn(42)) + if (resumeSinceTimestamp !== undefined) { + assert.equals(await pausable.getResumeSinceTimestamp(), resumeSinceTimestamp) + } + + await assert.revertsWithCustomError(pausable.pause(12345), `ResumedExpected()`) + await assert.revertsWithCustomError(pausable.stubUnderModifierWhenResumed(), `ResumedExpected()`) + } + + /// Check views, modifiers and capability to pause/resume + async function assertResumedState() { + assert.isFalse(await pausable.isPaused()) + assert.isTrue(await pausable.getResumeSinceTimestamp() <= await getCurrentBlockTimestamp()) + assert.equals(await pausable.stubUnderModifierWhenResumed(), bn(42)) + await assert.revertsWithCustomError(pausable.stubUnderModifierWhenPaused(), `PausedExpected()`) + await assert.revertsWithCustomError(pausable.resume(), `PausedExpected()`) + } + + describe('Logic', () => { + it(`state after deployment`, async () => { + await assertResumedState() + assert.equals(await pausable.getResumeSinceTimestamp(), bn(0)) + }) + + it(`revert if pause for zero duration`, async () => { + await assert.revertsWithCustomError(pausable.pause(0), `ZeroPauseDuration()`) + }) + + it(`pause infinitely`, async () => { + await assertResumedState() + const MONTH_IN_SECS = 30 * 24 * 60 * 60 + + await pausable.pause(PAUSE_INFINITELY) + await assertPausedState(PAUSE_INFINITELY) + + await advanceChainTime(MONTH_IN_SECS) + await assertPausedState(PAUSE_INFINITELY) + + await advanceChainTime(12 * MONTH_IN_SECS) + await assertPausedState(PAUSE_INFINITELY) + }) + + it(`pause on specific pauseDuration`, async () => { + assert.isFalse(await pausable.isPaused()) + const pauseDuration = 3 * 60 + + await pausable.pause(pauseDuration) + const resumeSinceTimestamp = await getCurrentBlockTimestamp() + pauseDuration + await assertPausedState(resumeSinceTimestamp) + + await advanceChainTime(Math.floor(pauseDuration / 2)) + assert.isTrue(await pausable.isPaused()) + await advanceChainTime(resumeSinceTimestamp - 1 - (await getCurrentBlockTimestamp())) + assert.equals(await getCurrentBlockTimestamp(), resumeSinceTimestamp - 1) + // Check only view here because with revert transactions chain can pass more than 1 seconds + assert.isTrue(await pausable.isPaused()) + + await advanceChainTime(1) + assert.equals(await getCurrentBlockTimestamp(), resumeSinceTimestamp) + await assertResumedState() + }) + + it(`resume`, async () => { + await pausable.pause(PAUSE_INFINITELY) + await pausable.resume() + await assertResumedState() + + await pausable.pause(123) + await pausable.resume() + await assertResumedState() + }) + }) +}) diff --git a/test/helpers/blockchain.js b/test/helpers/blockchain.js index baf5ae570..7d7f8bb32 100644 --- a/test/helpers/blockchain.js +++ b/test/helpers/blockchain.js @@ -7,6 +7,17 @@ async function waitBlocks(numBlocksToMine) { return block } +async function advanceChainTime(seconds) { + await hre.network.provider.send('evm_increaseTime', [seconds]) + await hre.network.provider.send('evm_mine') +} + +async function getCurrentBlockTimestamp() { + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + return block.timestamp; +} + /** * Allows to make snapshot of the blockchain and revert to the previous state */ @@ -38,8 +49,11 @@ function impersonate(provider, address) { return provider.send('hardhat_impersonateAccount', [address]) } + module.exports = { EvmSnapshot, waitBlocks, - impersonate + advanceChainTime, + getCurrentBlockTimestamp, + impersonate, } From 8b8a97f0588c7d73a08a4a2f321704fa1f64ddfb Mon Sep 17 00:00:00 2001 From: Artyom Veremeenko Date: Thu, 16 Feb 2023 19:45:44 +0400 Subject: [PATCH 067/199] fix: typos in comments --- contracts/0.8.9/WithdrawalVault.sol | 2 +- contracts/0.8.9/utils/PausableUntil.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/0.8.9/WithdrawalVault.sol b/contracts/0.8.9/WithdrawalVault.sol index 75d6902c9..c5485b785 100644 --- a/contracts/0.8.9/WithdrawalVault.sol +++ b/contracts/0.8.9/WithdrawalVault.sol @@ -65,7 +65,7 @@ contract WithdrawalVault is Versioned { } /** - * @notice Intialize the contract explicitly. + * @notice Initialize the contract explicitly. * Sets the contract version to '1'. */ function initialize() external { diff --git a/contracts/0.8.9/utils/PausableUntil.sol b/contracts/0.8.9/utils/PausableUntil.sol index 9d1e03cf1..0fe8a8356 100644 --- a/contracts/0.8.9/utils/PausableUntil.sol +++ b/contracts/0.8.9/utils/PausableUntil.sol @@ -46,7 +46,7 @@ contract PausableUntil { /// @notice Returns one of: /// - PAUSE_INFINITELY if paused infinitely returns /// - first second when get contract get resumed if paused for specific duration - /// - some timestamp in pase if not paused + /// - some timestamp in past if not paused function getResumeSinceTimestamp() external view returns (uint256) { return RESUME_SINCE_TIMESTAMP_POSITION.getStorageUint256(); } From 1351b163bdf1c0d8e69c2102a0e7182b2d335cb5 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Thu, 16 Feb 2023 17:30:08 +0100 Subject: [PATCH 068/199] fix: move updates from SR to NOR --- .../0.4.24/nos/NodeOperatorsRegistry.sol | 67 ++++++++++++--- contracts/0.8.9/StakingRouter.sol | 43 +--------- contracts/0.8.9/interfaces/IStakingModule.sol | 16 ++-- contracts/0.8.9/test_helpers/ModuleSolo.sol | 9 +- .../0.8.9/test_helpers/StakingModuleMock.sol | 9 +- lib/abi/NodeOperatorsRegistry.json | 2 +- test/0.4.24/node-operators-registry.test.js | 86 +++++++++++++------ test/helpers/node-operators.js | 5 +- 8 files changed, 145 insertions(+), 92 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 1418f1c4f..161c6bdd2 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -420,27 +420,70 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// @notice Called by StakingRouter to update the number of the validators of the given node /// operator that were requested to exit but failed to do so in the max allowed time /// - /// @param _nodeOperatorId Id of the node operator - /// @param _stuckValidatorsCount New number of stuck validators of the node operator - function updateStuckValidatorsCount(uint256 _nodeOperatorId, uint256 _stuckValidatorsCount) external { - _onlyExistedNodeOperator(_nodeOperatorId); + /// @param _nodeOperatorIds bytes packed array of the node operators id + /// @param _stuckValidatorsCounts bytes packed array of the new number of stuck validators for the node operators + function updateStuckValidatorsCount( + bytes _nodeOperatorIds, + bytes _stuckValidatorsCounts + ) + external + { _auth(STAKING_ROUTER_ROLE); + _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _stuckValidatorsCounts.length % 16 == 0); - _updateStuckValidatorsCount(_nodeOperatorId, uint64(_stuckValidatorsCount)); + uint256 nodeOperatorsCount = _nodeOperatorIds.length / 8; + _requireValidReportData(_stuckValidatorsCounts.length / 16 == nodeOperatorsCount); + uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); + + uint256 nodeOperatorId; + uint64 validatorsCount; + for (uint256 i; i < nodeOperatorsCount; ) { + /// @solidity memory-safe-assembly + assembly { + let _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) + let _stuckValidatorsCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot) + nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) + validatorsCount := shr(128, calldataload(add(_stuckValidatorsCountsOffset, mul(i, 16)))) + i := add(i, 1) + } + _requireValidRange(nodeOperatorId < totalNodeOperatorsCount); + _updateStuckValidatorsCount(nodeOperatorId, validatorsCount); + } } /// @notice Called by StakingRouter to update the number of the validators in the EXITED state /// for node operator with given id /// - /// @param _nodeOperatorId Id of the node operator - /// @param _exitedValidatorsCount New number of EXITED validators of the node operator - function updateExitedValidatorsCount(uint256 _nodeOperatorId, uint256 _exitedValidatorsCount) + /// @param _nodeOperatorIds bytes packed array of the node operators id + /// @param _stuckValidatorsCounts bytes packed array of the new number of EXITED validators for the node operators + function updateExitedValidatorsCount( + bytes _nodeOperatorIds, + bytes _stuckValidatorsCounts + ) external { - _onlyExistedNodeOperator(_nodeOperatorId); _auth(STAKING_ROUTER_ROLE); + _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _stuckValidatorsCounts.length % 16 == 0); + + uint256 nodeOperatorsCount = _nodeOperatorIds.length / 8; + _requireValidReportData(_stuckValidatorsCounts.length / 16 == nodeOperatorsCount); + uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); - _updateExitedValidatorsCount(_nodeOperatorId, uint64(_exitedValidatorsCount), false); + uint256 nodeOperatorId; + uint64 validatorsCount; + + for (uint256 i; i < nodeOperatorsCount; ) { + /// @solidity memory-safe-assembly + assembly { + let _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) + let _stuckValidatorsCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot) + nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) + validatorsCount := shr(128, calldataload(add(_stuckValidatorsCountsOffset, mul(i, 16)))) + i := add(i, 1) + } + _requireValidRange(nodeOperatorId < totalNodeOperatorsCount); + _updateExitedValidatorsCount(nodeOperatorId, validatorsCount, false); + } } /// @notice Updates the number of the refunded validators for node operator with the given id @@ -1272,6 +1315,10 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { require(_pass, "OUT_OF_RANGE"); } + function _requireValidReportData(bool _pass) internal pure { + require(_pass, "INVALID_REPORT_DATA"); + } + function _onlyCorrectNodeOperatorState(bool _pass) internal pure { require(_pass, "WRONG_OPERATOR_ACTIVE_STATE"); } diff --git a/contracts/0.8.9/StakingRouter.sol b/contracts/0.8.9/StakingRouter.sol index c68854a32..d09b1faf8 100644 --- a/contracts/0.8.9/StakingRouter.sol +++ b/contracts/0.8.9/StakingRouter.sol @@ -303,15 +303,6 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version external onlyRole(REPORT_EXITED_VALIDATORS_ROLE) { - if (_nodeOperatorIds.length % 8 != 0 || _exitedValidatorsCounts.length % 16 != 0) { - revert InvalidReportData(); - } - - uint256 totalNodeOps = _nodeOperatorIds.length / 8; - if (_exitedValidatorsCounts.length / 16 != totalNodeOps) { - revert InvalidReportData(); - } - StakingModule storage stakingModule = _getStakingModuleById(_stakingModuleId); IStakingModule moduleContract = IStakingModule(stakingModule.stakingModuleAddress); ( @@ -320,17 +311,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version /* uint256 depositableValidatorsCount */ ) = moduleContract.getStakingModuleSummary(); - for (uint256 i = 0; i < totalNodeOps; ) { - uint256 nodeOpId; - uint256 validatorsCount; - /// @solidity memory-safe-assembly - assembly { - nodeOpId := shr(192, calldataload(add(_nodeOperatorIds.offset, mul(i, 8)))) - validatorsCount := shr(128, calldataload(add(_exitedValidatorsCounts.offset, mul(i, 16)))) - i := add(i, 1) - } - moduleContract.updateExitedValidatorsCount(nodeOpId, validatorsCount); - } + moduleContract.updateExitedValidatorsCount(_nodeOperatorIds, _exitedValidatorsCounts); uint256 prevReportedExitedValidatorsCount = stakingModule.exitedValidatorsCount; ( @@ -444,28 +425,8 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version external onlyRole(REPORT_EXITED_VALIDATORS_ROLE) { - if (_nodeOperatorIds.length % 8 != 0 || _stuckValidatorsCounts.length % 16 != 0) { - revert InvalidReportData(); - } - - uint256 totalNodeOps = _nodeOperatorIds.length / 8; - if (_stuckValidatorsCounts.length / 16 != totalNodeOps) { - revert InvalidReportData(); - } - address moduleAddr = _getStakingModuleById(_stakingModuleId).stakingModuleAddress; - - for (uint256 i = 0; i < totalNodeOps; ) { - uint256 nodeOpId; - uint256 validatorsCount; - /// @solidity memory-safe-assembly - assembly { - nodeOpId := shr(192, calldataload(add(_nodeOperatorIds.offset, mul(i, 8)))) - validatorsCount := shr(128, calldataload(add(_stuckValidatorsCounts.offset, mul(i, 16)))) - i := add(i, 1) - } - IStakingModule(moduleAddr).updateStuckValidatorsCount(nodeOpId, validatorsCount); - } + IStakingModule(moduleAddr).updateStuckValidatorsCount(_nodeOperatorIds, _stuckValidatorsCounts); } function getExitedValidatorsCountAcrossAllModules() external view returns (uint256) { diff --git a/contracts/0.8.9/interfaces/IStakingModule.sol b/contracts/0.8.9/interfaces/IStakingModule.sol index 5ef430076..5cd343932 100644 --- a/contracts/0.8.9/interfaces/IStakingModule.sol +++ b/contracts/0.8.9/interfaces/IStakingModule.sol @@ -83,19 +83,19 @@ interface IStakingModule { /// @notice Updates the number of the validators of the given node operator that were requested /// to exit but failed to do so in the max allowed time - /// @param _nodeOperatorId Id of the node operator - /// @param _stuckValidatorsCount New number of stuck validators of the node operator + /// @param _nodeOperatorIds bytes packed array of the node operators id + /// @param _stuckValidatorsCounts bytes packed array of the new number of STUCK validators for the node operators function updateStuckValidatorsCount( - uint256 _nodeOperatorId, - uint256 _stuckValidatorsCount + bytes calldata _nodeOperatorIds, + bytes calldata _stuckValidatorsCounts ) external; /// @notice Updates the number of the validators in the EXITED state for node operator with given id - /// @param _nodeOperatorId Id of the node operator - /// @param _exitedValidatorsCount New number of EXITED validators of the node operator + /// @param _nodeOperatorIds bytes packed array of the node operators id + /// @param _stuckValidatorsCounts bytes packed array of the new number of EXITED validators for the node operators function updateExitedValidatorsCount( - uint256 _nodeOperatorId, - uint256 _exitedValidatorsCount + bytes calldata _nodeOperatorIds, + bytes calldata _stuckValidatorsCounts ) external; /// @notice Updates the number of the refunded validators for node operator with the given id diff --git a/contracts/0.8.9/test_helpers/ModuleSolo.sol b/contracts/0.8.9/test_helpers/ModuleSolo.sol index 1bf96fbeb..078ae8095 100644 --- a/contracts/0.8.9/test_helpers/ModuleSolo.sol +++ b/contracts/0.8.9/test_helpers/ModuleSolo.sol @@ -79,11 +79,14 @@ contract ModuleSolo is IStakingModule { function handleRewardsMinted(uint256 _totalShares) external {} function updateStuckValidatorsCount( - uint256 _nodeOperatorId, - uint256 _stuckValidatorKeysCount + bytes calldata _nodeOperatorIds, + bytes calldata _stuckValidatorsCounts ) external {} - function updateExitedValidatorsCount(uint256, uint256) external {} + function updateExitedValidatorsCount( + bytes calldata _nodeOperatorIds, + bytes calldata _stuckValidatorsCounts + ) external {} function updateRefundedValidatorsCount(uint256 _nodeOperatorId, uint256 _refundedValidatorsCount) external {} diff --git a/contracts/0.8.9/test_helpers/StakingModuleMock.sol b/contracts/0.8.9/test_helpers/StakingModuleMock.sol index 7e4c07c2e..af42a5b2b 100644 --- a/contracts/0.8.9/test_helpers/StakingModuleMock.sol +++ b/contracts/0.8.9/test_helpers/StakingModuleMock.sol @@ -64,11 +64,14 @@ contract StakingModuleMock is IStakingModule { function handleRewardsMinted(uint256 _totalShares) external {} function updateStuckValidatorsCount( - uint256 _nodeOperatorId, - uint256 _stuckValidatorKeysCount + bytes calldata _nodeOperatorIds, + bytes calldata _stuckValidatorsCounts ) external {} - function updateExitedValidatorsCount(uint256, uint256) external {} + function updateExitedValidatorsCount( + bytes calldata _nodeOperatorIds, + bytes calldata _stuckValidatorsCounts + ) external {} function updateRefundedValidatorsCount(uint256 _nodeOperatorId, uint256 _refundedValidatorsCount) external {} diff --git a/lib/abi/NodeOperatorsRegistry.json b/lib/abi/NodeOperatorsRegistry.json index 159cae01e..d5ae3cc15 100644 --- a/lib/abi/NodeOperatorsRegistry.json +++ b/lib/abi/NodeOperatorsRegistry.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_onlyClearedPenalty","type":"bool"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"}],"name":"updateExitedValidatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_withClearedPenalty","type":"bool"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index 3b5f4ab3f..1491a5268 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -7,6 +7,7 @@ const { EvmSnapshot } = require('../helpers/blockchain') const { ZERO_ADDRESS, getEventAt } = require('@aragon/contract-helpers-test') const nodeOperators = require('../helpers/node-operators') const signingKeys = require('../helpers/signing-keys') +const { hex } = require('../helpers/utils') const { web3, artifacts } = require('hardhat') const { getRandomLocatorConfig } = require('../helpers/locator') const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') @@ -78,6 +79,15 @@ const hexConcat = (first, ...rest) => { const ETH = (value) => web3.utils.toWei(value + '', 'ether') const StETH = artifacts.require('StETHMock') +function prepIdsCountsPayload(ids, counts) { + if (!Array.isArray(ids)) ids = [ids] + if (!Array.isArray(counts)) counts = [counts] + return { + operatorIds: '0x' + ids.map((id) => hex(id, 8)).join(''), + keysCounts: '0x' + counts.map((count) => hex(count, 16)).join('') + } +} + contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nobody]) => { let appBase, app, locator, steth, dao const snapshot = new EvmSnapshot(hre.ethers.provider) @@ -1064,25 +1074,29 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('reverts with "OUT_OF_RANGE" error when called on non existent validator', async () => { const hasPermission = await dao.hasPermission(voting, app, 'STAKING_ROUTER_ROLE') assert.isTrue(hasPermission) - await assert.reverts(app.updateExitedValidatorsCount(notExistedNodeOperatorId, 40, { from: voting }), 'OUT_OF_RANGE') + const { operatorIds, keysCounts } = prepIdsCountsPayload(notExistedNodeOperatorId, 40) + await assert.reverts(app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }), 'OUT_OF_RANGE') }) it('reverts with "APP_AUTH_FAILED" error when called by sender without STAKING_ROUTER_ROLE', async () => { const hasPermission = await dao.hasPermission(nobody, app, 'STAKING_ROUTER_ROLE') assert.isFalse(hasPermission) - await assert.reverts(app.updateExitedValidatorsCount(firstNodeOperatorId, 40, { from: nobody }), 'APP_AUTH_FAILED') + const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, 40) + await assert.reverts(app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: nobody }), 'APP_AUTH_FAILED') }) it("doesn't change the state when new value is equal to the previous one", async () => { const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator(firstNodeOperatorId, false) - await app.updateExitedValidatorsCount(firstNodeOperatorId, exitedValidatorsKeysCountBefore, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, exitedValidatorsKeysCountBefore) + await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(firstNodeOperatorId, false) assert.equals(exitedValidatorsKeysCountBefore, exitedValidatorsKeysCountAfter) }) it("doesn't emit ExitedSigningKeysCountChanged event when new value is equal to the previous one", async () => { const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator(firstNodeOperatorId, false) - const receipt = await app.updateExitedValidatorsCount(firstNodeOperatorId, exitedValidatorsKeysCountBefore, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, exitedValidatorsKeysCountBefore) + const receipt = await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) assert.notEmits(receipt, 'ExitedSigningKeysCountChanged') }) @@ -1090,18 +1104,17 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const newExitedValidatorsCount = 1000 const nodeOperator = await app.getNodeOperator(firstNodeOperatorId, false) assert(newExitedValidatorsCount > nodeOperator.usedSigningKeys.toNumber()) - await assert.reverts( - app.updateExitedValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, { from: voting }), - 'OUT_OF_RANGE' - ) + const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, newExitedValidatorsCount) + await assert.reverts(app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }), 'OUT_OF_RANGE') }) it('reverts with "EXITED_VALIDATORS_COUNT_DECREASED" error when new exitedValidatorsKeysCount less then current one', async () => { const nodeOperator = await app.getNodeOperator(firstNodeOperatorId, false) assert(nodeOperator.stoppedValidators.toNumber() > 0, 'invariant failed: no exited validators') const newExitedValidatorsKeysCount = nodeOperator.stoppedValidators.toNumber() - 1 + const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, newExitedValidatorsKeysCount) await assert.reverts( - app.updateExitedValidatorsCount(firstNodeOperatorId, newExitedValidatorsKeysCount, { from: voting }), + app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }), 'EXITED_VALIDATORS_COUNT_DECREASED' ) }) @@ -1113,16 +1126,23 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob false ) assert.notEquals(exitedValidatorsKeysCountBefore, newExitedValidatorsCount) - await app.updateExitedValidatorsCount(secondNodeOperatorId, newExitedValidatorsCount, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(secondNodeOperatorId, newExitedValidatorsCount) + await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(secondNodeOperatorId, false) assert.equals(exitedValidatorsKeysCountAfter, newExitedValidatorsCount) }) it('increases the total exited signing keys count', async () => { const newExitedValidatorsCount = 4 - const [{ stoppedValidators: exitedValidatorsKeysCountBefore }, { exitedSigningKeysCount: exitedSigningKeysCountBefore }] = - await Promise.all([await app.getNodeOperator(firstNodeOperatorId, false), app.testing_getTotalSigningKeysStats()]) - await app.updateExitedValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, { from: voting }) + const [ + { stoppedValidators: exitedValidatorsKeysCountBefore }, + { exitedSigningKeysCount: exitedSigningKeysCountBefore } + ] = await Promise.all([ + await app.getNodeOperator(firstNodeOperatorId, false), + app.testing_getTotalSigningKeysStats() + ]) + const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, newExitedValidatorsCount) + await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) const exitedSigningKeysCountIncrement = newExitedValidatorsCount - exitedValidatorsKeysCountBefore.toNumber() const { exitedSigningKeysCount: exitedSigningKeysCountAfter } = await app.testing_getTotalSigningKeysStats() assert.equals( @@ -1133,7 +1153,8 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits ExitedSigningKeysCountChanged event with correct params', async () => { const newExitedValidatorsCount = 4 - const receipt = await app.updateExitedValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, newExitedValidatorsCount) + const receipt = await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) assert.emits(receipt, 'ExitedSigningKeysCountChanged', { nodeOperatorId: firstNodeOperatorId, exitedValidatorsCount: newExitedValidatorsCount @@ -1143,7 +1164,8 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it("doesn't change the exited signing keys count of other node operators", async () => { const newExitedValidatorsCount = 4 const { stakingLimit: secondNodeOperatorStakingLimitBefore } = await app.getNodeOperator(firstNodeOperatorId, true) - await app.updateExitedValidatorsCount(secondNodeOperatorId, newExitedValidatorsCount, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(secondNodeOperatorId, newExitedValidatorsCount) + await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) const { stakingLimit: secondNodeOperatorStakingLimitAfter } = await app.getNodeOperator(firstNodeOperatorId, true) assert.equals(secondNodeOperatorStakingLimitAfter, secondNodeOperatorStakingLimitBefore) }) @@ -1969,13 +1991,25 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits DepositedSigningKeysCountChanged when keys were loaded', async () => { let keysToAllocate = 2 let receipt = await app.testing_obtainDepositData(keysToAllocate) - assert.emits(receipt, 'DepositedSigningKeysCountChanged', { nodeOperatorId: firstNodeOperatorId, depositedValidatorsCount: 6 }) - assert.emits(receipt, 'DepositedSigningKeysCountChanged', { nodeOperatorId: secondNodeOperatorId, depositedValidatorsCount: 8 }) + assert.emits(receipt, 'DepositedSigningKeysCountChanged', { + nodeOperatorId: firstNodeOperatorId, + depositedValidatorsCount: 6 + }) + assert.emits(receipt, 'DepositedSigningKeysCountChanged', { + nodeOperatorId: secondNodeOperatorId, + depositedValidatorsCount: 8 + }) keysToAllocate = 10 receipt = await app.testing_obtainDepositData(keysToAllocate) - assert.notEmits(receipt, 'DepositedSigningKeysCountChanged', { nodeOperatorId: firstNodeOperatorId, depositedSigningKeysCount: 6 }) - assert.emits(receipt, 'DepositedSigningKeysCountChanged', { nodeOperatorId: secondNodeOperatorId, depositedValidatorsCount: 10 }) + assert.notEmits(receipt, 'DepositedSigningKeysCountChanged', { + nodeOperatorId: firstNodeOperatorId, + depositedSigningKeysCount: 6 + }) + assert.emits(receipt, 'DepositedSigningKeysCountChanged', { + nodeOperatorId: secondNodeOperatorId, + depositedValidatorsCount: 10 + }) }) }) @@ -2043,12 +2077,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('returns zero shares when all validators are exited', async () => { - await app.updateExitedValidatorsCount(firstNodeOperatorId, NODE_OPERATORS[firstNodeOperatorId].depositedSigningKeysCount, { - from: voting - }) - await app.updateExitedValidatorsCount(secondNodeOperatorId, NODE_OPERATORS[secondNodeOperatorId].depositedSigningKeysCount, { - from: voting - }) + const { operatorIds, keysCounts } = prepIdsCountsPayload( + [firstNodeOperatorId, secondNodeOperatorId], + [ + NODE_OPERATORS[firstNodeOperatorId].depositedSigningKeysCount, + NODE_OPERATORS[secondNodeOperatorId].depositedSigningKeysCount + ] + ) + await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) const activeNodeOperators = await nodeOperators.filterNodeOperators(app, (nodeOperator) => nodeOperator.active) const totalRewardsShare = web3.utils.toWei('10') const { recipients, shares } = await app.getRewardsDistribution(totalRewardsShare) diff --git a/test/helpers/node-operators.js b/test/helpers/node-operators.js index d48b56570..a54c10f59 100644 --- a/test/helpers/node-operators.js +++ b/test/helpers/node-operators.js @@ -2,6 +2,7 @@ const hre = require('hardhat') const { assert } = require('chai') const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') const { FakeValidatorKeys } = require('./signing-keys') +const { hex } = require('./utils') /*** * Adds new Node Operator to the registry and configures it @@ -67,7 +68,9 @@ async function addNodeOperator(registry, config, txOptions) { } if (exitedSigningKeysCount > 0) { - await registry.updateExitedValidatorsCount(newOperatorId, exitedSigningKeysCount, txOptions) + const operatorIdsPayload = '0x' + [newOperatorId].map((id) => hex(id, 8)).join('') + const keysCountsPayload = '0x' + [exitedSigningKeysCount].map((count) => hex(count, 16)).join('') + await registry.updateExitedValidatorsCount(operatorIdsPayload, keysCountsPayload, txOptions) } if (!isActive) { From 82862dd8f595f525631c0f56bcb5c63d448947ea Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Thu, 16 Feb 2023 23:59:59 +0700 Subject: [PATCH 069/199] test: more initil tests for AccountingOracle --- test/0.8.9/oracle/accounting-oracle-deploy.test.js | 6 ++++++ test/0.8.9/oracle/base-oracle-access-control.test.js | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/test/0.8.9/oracle/accounting-oracle-deploy.test.js b/test/0.8.9/oracle/accounting-oracle-deploy.test.js index 0a6c5cf9f..c249cf936 100644 --- a/test/0.8.9/oracle/accounting-oracle-deploy.test.js +++ b/test/0.8.9/oracle/accounting-oracle-deploy.test.js @@ -397,5 +397,11 @@ contract('AccountingOracle', ([admin, member1]) => { 'AdminCannotBeZero()' ) }) + + it('initializeWithoutMigration succeeds', async () => { + const deployed = await deployAccountingOracleSetup(admin) + const { refSlot } = await deployed.consensus.getCurrentFrame() + await deployed.oracle.initializeWithoutMigration(admin, deployed.consensus.address, CONSENSUS_VERSION, refSlot, { from: admin }) + }) }) }) diff --git a/test/0.8.9/oracle/base-oracle-access-control.test.js b/test/0.8.9/oracle/base-oracle-access-control.test.js index 640093f26..2df45f632 100644 --- a/test/0.8.9/oracle/base-oracle-access-control.test.js +++ b/test/0.8.9/oracle/base-oracle-access-control.test.js @@ -16,6 +16,7 @@ const { const MockConsensusContract = artifacts.require('MockConsensusContract') contract('BaseOracle', ([admin, account1, account2, member1, member2]) => { + let initTx let oracle = null let consensus = null const manageConsensusContractRoleKeccak156 = web3.utils.keccak256('MANAGE_CONSENSUS_CONTRACT_ROLE') @@ -23,6 +24,7 @@ contract('BaseOracle', ([admin, account1, account2, member1, member2]) => { const deploy = async (options = undefined) => { const deployed = await deployBaseOracle(admin, options) + initTx = deployed.initTx oracle = deployed.oracle consensus = deployed.consensusContract } @@ -34,6 +36,11 @@ contract('BaseOracle', ([admin, account1, account2, member1, member2]) => { assert.isNotNull(oracle) assert.isNotNull(consensus) }) + + it('gives default roles', async () => { + const DEFAULT_ADMIN_ROLE = await oracle.DEFAULT_ADMIN_ROLE + await assert.emits(initTx, 'RoleGranted', { role: DEFAULT_ADMIN_ROLE, account: admin, sender: admin }) + }) }) context('MANAGE_CONSENSUS_CONTRACT_ROLE', () => { From 934e0fd0a3d154771512521e1f6917905d2b0b5b Mon Sep 17 00:00:00 2001 From: Artyom Veremeenko Date: Thu, 16 Feb 2023 21:17:53 +0400 Subject: [PATCH 070/199] refactor: rename a few shortened names --- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 2 +- contracts/0.8.9/oracle/AccountingOracle.sol | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index c077181fc..b51728aa5 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -856,7 +856,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); uint256 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); uint256 _toIndex = _fromIndex.add(_keysCount); - // comapring _toIndex <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than MAX_UINT64 + // comparing _toIndex <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than MAX_UINT64 _requireValidRange(_fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) && _toIndex <= totalSigningKeysCount); // removing from the last index to the highest one, so we won't get outside the array diff --git a/contracts/0.8.9/oracle/AccountingOracle.sol b/contracts/0.8.9/oracle/AccountingOracle.sol index c9bf7b61c..eb7d5bd62 100644 --- a/contracts/0.8.9/oracle/AccountingOracle.sol +++ b/contracts/0.8.9/oracle/AccountingOracle.sol @@ -456,7 +456,7 @@ contract AccountingOracle is BaseOracle { /// /// 0. last reference slot of legacy oracle /// 1. last legacy oracle's consensus report arrives - /// 2. new oracle is deployed and enabled, legacy oracle is disabled and upgraded to compat code + /// 2. new oracle is deployed and enabled, legacy oracle is disabled and upgraded to compatibility code /// 3. first reference slot of the new oracle /// 4. first new oracle's consensus report arrives /// @@ -474,7 +474,7 @@ contract AccountingOracle is BaseOracle { uint256 genesisTime) = IConsensusContract(consensusContract).getChainConfig(); { - // check chain spec to match the prev. one (a block is used to reduce stack alloc) + // check chain spec to match the prev. one (a block is used to reduce stack allocation) (uint256 legacyEpochsPerFrame, uint256 legacySlotsPerEpoch, uint256 legacySecondsPerSlot, @@ -743,7 +743,7 @@ contract AccountingOracle is BaseOracle { uint256 nodeOpsCount; uint256 firstNodeOpId; bytes calldata nodeOpIds; - bytes calldata valsCounts; + bytes calldata valuesCounts; if (dataOffset + 35 > data.length) { // has to fit at least moduleId (3 bytes), nodeOpsCount (8 bytes), @@ -762,9 +762,9 @@ contract AccountingOracle is BaseOracle { nodeOpIds.offset := add(data.offset, add(dataOffset, 11)) nodeOpIds.length := mul(nodeOpsCount, 8) firstNodeOpId := shr(192, calldataload(nodeOpIds.offset)) - valsCounts.offset := add(nodeOpIds.offset, nodeOpIds.length) - valsCounts.length := mul(nodeOpsCount, 16) - dataOffset := sub(add(valsCounts.offset, valsCounts.length), data.offset) + valuesCounts.offset := add(nodeOpIds.offset, nodeOpIds.length) + valuesCounts.length := mul(nodeOpsCount, 16) + dataOffset := sub(add(valuesCounts.offset, valuesCounts.length), data.offset) } if (moduleId == 0) { @@ -787,10 +787,10 @@ contract AccountingOracle is BaseOracle { if (iter.itemType == EXTRA_DATA_TYPE_STUCK_VALIDATORS) { IStakingRouter(iter.stakingRouter) - .reportStakingModuleStuckValidatorsCountByNodeOperator(moduleId, nodeOpIds, valsCounts); + .reportStakingModuleStuckValidatorsCountByNodeOperator(moduleId, nodeOpIds, valuesCounts); } else { IStakingRouter(iter.stakingRouter) - .reportStakingModuleExitedValidatorsCountByNodeOperator(moduleId, nodeOpIds, valsCounts); + .reportStakingModuleExitedValidatorsCountByNodeOperator(moduleId, nodeOpIds, valuesCounts); } iter.dataOffset = dataOffset; From f89e443cb962be0029fd885a1711f19bd7bb8bcc Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Fri, 17 Feb 2023 06:19:18 +0400 Subject: [PATCH 071/199] Calculate deposits count in Lido contract --- contracts/0.4.24/Lido.sol | 69 ++++++---------- .../0.4.24/nos/NodeOperatorsRegistry.sol | 47 +++++------ .../NodeOperatorsRegistryMock.sol | 6 +- contracts/0.8.9/StakingRouter.sol | 78 ++++++++---------- contracts/0.8.9/interfaces/IStakingModule.sol | 16 ++-- contracts/0.8.9/test_helpers/ModuleSolo.sol | 3 +- .../0.8.9/test_helpers/StakingModuleMock.sol | 1 - lib/abi/Lido.json | 2 +- lib/abi/NodeOperatorsRegistry.json | 2 +- lib/abi/StakingRouter.json | 2 +- test/0.4.24/node-operators-registry.test.js | 80 +++++++++---------- test/0.8.9/staking-router.test.js | 3 +- 12 files changed, 132 insertions(+), 177 deletions(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index b15c723ae..fc38ef81a 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -81,7 +81,7 @@ interface IStakingRouter { uint256 _maxDepositsCount, uint256 _stakingModuleId, bytes _depositCalldata - ) external payable returns (uint256); + ) external payable; function getStakingRewardsDistribution() external @@ -101,6 +101,11 @@ interface IStakingRouter { function getTotalFeeE4Precision() external view returns (uint16 totalFee); function getStakingFeeAggregateDistributionE4Precision() external view returns (uint16 modulesFee, uint16 treasuryFee); + + function getStakingModuleMaxDepositsCount(uint256 _stakingModuleId, uint256 _depositableEther) + external + view + returns (uint256); } interface IWithdrawalQueue { @@ -244,9 +249,6 @@ contract Lido is Versioned, StETHPermit, AragonApp { // The `amount` of ether was sent to the deposit_contract.deposit function event Unbuffered(uint256 amount); - // The amount of ETH sent from StakingRouter contract to Lido contract when deposit called - event StakingRouterDepositRemainderReceived(uint256 amount); - /** * @dev As AragonApp, Lido contract must be initialized with following variables: * NB: by default, staking and the whole Lido pool are in paused state @@ -472,17 +474,6 @@ contract Lido is Versioned, StETHPermit, AragonApp { emit WithdrawalsReceived(msg.value); } - /** - * @notice A payable function for staking router deposits remainder. Can be called only by `StakingRouter` - * @dev We need a dedicated function because funds received by the default payable function - * are treated as a user deposit - */ - function receiveStakingRouterDepositRemainder() external payable { - require(msg.sender == getLidoLocator().stakingRouter()); - - emit StakingRouterDepositRemainderReceived(msg.value); - } - /** * @notice Stop pool routine operations */ @@ -677,14 +668,11 @@ contract Lido is Versioned, StETHPermit, AragonApp { * @dev Returns depositable ether amount. * Takes into account unfinalized stETH required by WithdrawalQueue */ - function getDepositableEther() public view returns (uint256 depositableEth) { - uint256 bufferedEth = _getBufferedEther(); + function getDepositableEther() public view returns (uint256 depositableEther) { + uint256 bufferedEther = _getBufferedEther(); uint256 withdrawalReserve = IWithdrawalQueue(getLidoLocator().withdrawalQueue()).unfinalizedStETH(); - if (bufferedEth > withdrawalReserve) { - bufferedEth -= withdrawalReserve; - depositableEth = bufferedEth.div(DEPOSIT_SIZE).mul(DEPOSIT_SIZE); - } + depositableEther = bufferedEther > withdrawalReserve ? bufferedEther - withdrawalReserve : 0; } /** @@ -700,33 +688,24 @@ contract Lido is Versioned, StETHPermit, AragonApp { require(_stakingModuleId <= uint24(-1), "STAKING_MODULE_ID_TOO_LARGE"); require(canDeposit(), "CAN_NOT_DEPOSIT"); - uint256 depositableEth = getDepositableEther(); - - if (depositableEth > 0) { - /// available ether amount for deposits (multiple of 32eth) - depositableEth = Math256.min(depositableEth, _maxDepositsCount.mul(DEPOSIT_SIZE)); - - uint256 unaccountedEth = _getUnaccountedEther(); - /// @dev transfer ether to SR and make deposit at the same time - /// @notice allow zero value of depositableEth, in this case SR will simply transfer the unaccounted ether to Lido contract - uint256 depositsCount = IStakingRouter(locator.stakingRouter()).deposit.value(depositableEth)( - _maxDepositsCount, - _stakingModuleId, - _depositCalldata - ); + IStakingRouter stakingRouter = IStakingRouter(locator.stakingRouter()); + uint256 depositsCount = Math256.min( + _maxDepositsCount, + stakingRouter.getStakingModuleMaxDepositsCount(_stakingModuleId, getDepositableEther()) + ); - uint256 depositedAmount = depositsCount.mul(DEPOSIT_SIZE); - assert(depositedAmount <= depositableEth); + if (depositsCount == 0) return; - if (depositsCount > 0) { - uint256 newDepositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256().add(depositsCount); - DEPOSITED_VALIDATORS_POSITION.setStorageUint256(newDepositedValidators); - emit DepositedValidatorsChanged(newDepositedValidators); + uint256 unaccountedEth = _getUnaccountedEther(); + uint256 depositsValue = depositsCount.mul(DEPOSIT_SIZE); + _markAsUnbuffered(depositsValue); + /// @dev transfer ether to SR and make deposit at the same time + stakingRouter.deposit.value(depositsValue)(depositsCount, _stakingModuleId, _depositCalldata); + assert(_getUnaccountedEther() == unaccountedEth); - _markAsUnbuffered(depositedAmount); - assert(_getUnaccountedEther() == unaccountedEth); - } - } + uint256 newDepositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256().add(depositsCount); + DEPOSITED_VALIDATORS_POSITION.setStorageUint256(newDepositedValidators); + emit DepositedValidatorsChanged(newDepositedValidators); } /// DEPRECATED PUBLIC METHODS diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index c077181fc..9084a411d 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -549,36 +549,29 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { } } - /// @notice Obtains up to _depositsCount deposit data to be used by StakingRouter - /// to deposit to the Ethereum Deposit contract - /// @dev the second param is optional staking module calldata - /// (not used for NodeOperatorsRegistry) - /// @param _depositsCount Desireable number of deposits to be done - /// @return depositsCount Actual deposits count might be done with returned data + /// @notice Obtains deposit data to be used by StakingRouter to deposit to the Ethereum Deposit + /// contract + /// @param _depositsCount Number of deposits to be done /// @return publicKeys Batch of the concatenated public validators keys /// @return signatures Batch of the concatenated deposit signatures for returned public keys - function obtainDepositData(uint256 _depositsCount, bytes /* _depositCalldata */) - external - returns ( - uint256 depositsCount, - bytes memory publicKeys, - bytes memory signatures - ) - { + function obtainDepositData( + uint256 _depositsCount, + bytes /* _depositCalldata */ + ) external returns (bytes memory publicKeys, bytes memory signatures) { _auth(STAKING_ROUTER_ROLE); - - uint256[] memory nodeOperatorIds; - uint256[] memory activeKeysCountAfterAllocation; - - (depositsCount, nodeOperatorIds, activeKeysCountAfterAllocation) = - _getSigningKeysAllocationData(_depositsCount); - - if (depositsCount == 0) { - return (0, new bytes(0), new bytes(0)); - } - - (publicKeys, signatures) = - _loadAllocatedSigningKeys(depositsCount, nodeOperatorIds, activeKeysCountAfterAllocation); + ( + uint256 allocatedKeysCount, + uint256[] memory nodeOperatorIds, + uint256[] memory activeKeysCountAfterAllocation + ) = _getSigningKeysAllocationData(_depositsCount); + + require(allocatedKeysCount == _depositsCount, "INSUFFICIENT_KEYS_COUNT"); + + (publicKeys, signatures) = _loadAllocatedSigningKeys( + allocatedKeysCount, + nodeOperatorIds, + activeKeysCountAfterAllocation + ); _increaseValidatorsKeysNonce(); } diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index 44a6188a9..4291a0b1e 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -155,8 +155,8 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { external returns (uint256 loadedValidatorsKeysCount, bytes memory publicKeys, bytes memory signatures) { - (loadedValidatorsKeysCount, publicKeys, signatures) = this.obtainDepositData(_keysToAllocate, new bytes(0)); - emit ValidatorsKeysLoaded(loadedValidatorsKeysCount, publicKeys, signatures); + (publicKeys, signatures) = this.obtainDepositData(_keysToAllocate, new bytes(0)); + emit ValidatorsKeysLoaded(publicKeys, signatures); } function testing_isNodeOperatorPenalized(uint256 operatorId) external view returns (bool) { @@ -176,7 +176,7 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { return _getNodeOperatorWithLimitApplied(operatorId); } - event ValidatorsKeysLoaded(uint256 count, bytes publicKeys, bytes signatures); + event ValidatorsKeysLoaded(bytes publicKeys, bytes signatures); function testing__distributeRewards() external returns (uint256) { return _distributeRewards(); diff --git a/contracts/0.8.9/StakingRouter.sol b/contracts/0.8.9/StakingRouter.sol index 9686ee7a6..788882ef4 100644 --- a/contracts/0.8.9/StakingRouter.sol +++ b/contracts/0.8.9/StakingRouter.sol @@ -15,11 +15,6 @@ import {MinFirstAllocationStrategy} from "../common/lib/MinFirstAllocationStrate import {BeaconChainDepositor} from "./BeaconChainDepositor.sol"; import {Versioned} from "./utils/Versioned.sol"; -interface ILido { - function getDepositableEther() external view returns (uint256); - function receiveStakingRouterDepositRemainder() external payable; -} - contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Versioned { using UnstructuredStorage for bytes32; @@ -54,6 +49,8 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version uint256 currentNodeOpExitedValidatorsCount, uint256 currentNodeOpStuckValidatorsCount ); + error InvalidDepositsValue(uint256 etherValue); + error DepositsCountMismatch(uint256 desiredDepositsCount, uint256 actualDepositsCount); enum StakingModuleStatus { Active, // deposits and rewards allowed @@ -157,8 +154,8 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version /** * @notice Return the Lido contract address */ - function getLido() public view returns (ILido) { - return ILido(LIDO_POSITION.getStorageAddress()); + function getLido() public view returns (address) { + return LIDO_POSITION.getStorageAddress(); } /** @@ -834,14 +831,13 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version * @param _stakingModuleId id of the staking module to be deposited * @return max number of deposits might be done using given staking module */ - function getStakingModuleMaxDepositsCount(uint256 _stakingModuleId) public view + function getStakingModuleMaxDepositsCount(uint256 _stakingModuleId, uint256 _depositableEther) public view validStakingModuleId(_stakingModuleId) returns (uint256) { uint256 stakingModuleIndex = _getStakingModuleIndexById(_stakingModuleId); - uint256 depositsToAllocate = getLido().getDepositableEther() / DEPOSIT_SIZE; (, uint256[] memory newDepositsAllocation, StakingModuleCache[] memory stakingModulesCache) - = _getDepositsAllocation(depositsToAllocate); + = _getDepositsAllocation(_depositableEther / DEPOSIT_SIZE); return newDepositsAllocation[stakingModuleIndex] - stakingModulesCache[stakingModuleIndex].activeValidatorsCount; } @@ -981,59 +977,49 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version /** * @dev Invokes a deposit call to the official Deposit contract - * @param _maxDepositsCount max deposits count + * @param _depositsCount number of deposits to make * @param _stakingModuleId id of the staking module to be deposited * @param _depositCalldata staking module calldata */ function deposit( - uint256 _maxDepositsCount, + uint256 _depositsCount, uint256 _stakingModuleId, bytes calldata _depositCalldata - ) external payable validStakingModuleId(_stakingModuleId) returns (uint256 depositsCount) { + ) external payable validStakingModuleId(_stakingModuleId) { if (msg.sender != LIDO_POSITION.getStorageAddress()) revert AppAuthLidoFailed(); - uint256 depositableEth = msg.value; - if (depositableEth == 0) { - _transferBalanceEthToLido(); - return 0; + uint256 depositsValue = msg.value; + if (depositsValue == 0 || depositsValue != _depositsCount * DEPOSIT_SIZE) { + revert InvalidDepositsValue(depositsValue); } bytes32 withdrawalCredentials = getWithdrawalCredentials(); if (withdrawalCredentials == 0) revert EmptyWithdrawalsCredentials(); - uint256 stakingModuleIndex = _getStakingModuleIndexById(_stakingModuleId); - StakingModule storage stakingModule = _getStakingModuleByIndex(stakingModuleIndex); - if (StakingModuleStatus(stakingModule.status) != StakingModuleStatus.Active) revert StakingModuleNotActive(); - - uint256 maxDepositsCount = Math256.min( - _maxDepositsCount, - getStakingModuleMaxDepositsCount(_stakingModuleId) - ); - - if (maxDepositsCount > 0) { - bytes memory publicKeysBatch; - bytes memory signaturesBatch; - (depositsCount, publicKeysBatch, signaturesBatch) = IStakingModule(stakingModule.stakingModuleAddress) - .obtainDepositData(maxDepositsCount, _depositCalldata); + StakingModule storage stakingModule = _getStakingModuleById(_stakingModuleId); + if (StakingModuleStatus(stakingModule.status) != StakingModuleStatus.Active) { + revert StakingModuleNotActive(); + } - if (depositsCount > 0) { - _makeBeaconChainDeposits32ETH(depositsCount, abi.encodePacked(withdrawalCredentials), publicKeysBatch, signaturesBatch); + (bytes memory publicKeysBatch, bytes memory signaturesBatch) = + IStakingModule(stakingModule.stakingModuleAddress) + .obtainDepositData(_depositsCount, _depositCalldata); - stakingModule.lastDepositAt = uint64(block.timestamp); - stakingModule.lastDepositBlock = block.number; + uint256 etherBalanceBeforeDeposits = address(this).balance; + _makeBeaconChainDeposits32ETH( + _depositsCount, + abi.encodePacked(withdrawalCredentials), + publicKeysBatch, + signaturesBatch + ); + uint256 etherBalanceAfterDeposits = address(this).balance; - emit StakingRouterETHDeposited(_stakingModuleId, depositsCount * DEPOSIT_SIZE); - } - } - _transferBalanceEthToLido(); - } + /// @dev make sure that deposited correct amount of ETH + assert(etherBalanceBeforeDeposits - etherBalanceAfterDeposits == depositsValue); - /// @dev transfer all remaining balance to Lido contract - function _transferBalanceEthToLido() internal { - uint256 balance = address(this).balance; - if (balance > 0) { - getLido().receiveStakingRouterDepositRemainder{value: balance}(); - } + stakingModule.lastDepositAt = uint64(block.timestamp); + stakingModule.lastDepositBlock = block.number; + emit StakingRouterETHDeposited(_stakingModuleId, depositsValue); } /** diff --git a/contracts/0.8.9/interfaces/IStakingModule.sol b/contracts/0.8.9/interfaces/IStakingModule.sol index 5ef430076..06b543b90 100644 --- a/contracts/0.8.9/interfaces/IStakingModule.sol +++ b/contracts/0.8.9/interfaces/IStakingModule.sol @@ -114,18 +114,16 @@ interface IStakingModule { uint256 _stuckValidatorsCount ) external; - /// @notice Obtains up to _depositsCount deposit data to be used by StakingRouter - /// to deposit to the Ethereum Deposit contract - /// @param _depositsCount Desireable number of deposits to be done + /// @notice Obtains deposit data to be used by StakingRouter to deposit to the Ethereum Deposit + /// contract + /// @dev The method MUST revert when the staking module has not enough deposit data items + /// @param _depositsCount Number of deposits to be done /// @param _calldata Staking module defined data encoded as bytes - /// @return depositsCount Actual deposits count might be done with returned data /// @return publicKeys Batch of the concatenated public validators keys /// @return signatures Batch of the concatenated deposit signatures for returned public keys - function obtainDepositData(uint256 _depositsCount, bytes calldata _calldata) external returns ( - uint256 depositsCount, - bytes memory publicKeys, - bytes memory signatures - ); + function obtainDepositData(uint256 _depositsCount, bytes calldata _calldata) + external + returns (bytes memory publicKeys, bytes memory signatures); /// @notice Called by StakingRouter after oracle finishes updating validators counters for all node operators function onAllValidatorCountersUpdated() external; diff --git a/contracts/0.8.9/test_helpers/ModuleSolo.sol b/contracts/0.8.9/test_helpers/ModuleSolo.sol index 1bf96fbeb..4b090e147 100644 --- a/contracts/0.8.9/test_helpers/ModuleSolo.sol +++ b/contracts/0.8.9/test_helpers/ModuleSolo.sol @@ -128,7 +128,6 @@ contract ModuleSolo is IStakingModule { external pure returns ( - uint256 depositsCount, bytes memory publicKeys, bytes memory signatures ) @@ -139,6 +138,6 @@ contract ModuleSolo is IStakingModule { MemUtils.copyBytes(_calldata, publicKeys, 0, 0, _depositsCount * PUBKEY_LENGTH); MemUtils.copyBytes(_calldata, signatures, _depositsCount * PUBKEY_LENGTH, 0, _depositsCount * PUBKEY_LENGTH); - return (_depositsCount, publicKeys, signatures); + return (publicKeys, signatures); } } diff --git a/contracts/0.8.9/test_helpers/StakingModuleMock.sol b/contracts/0.8.9/test_helpers/StakingModuleMock.sol index 7e4c07c2e..44bdf8e49 100644 --- a/contracts/0.8.9/test_helpers/StakingModuleMock.sol +++ b/contracts/0.8.9/test_helpers/StakingModuleMock.sol @@ -87,7 +87,6 @@ contract StakingModuleMock is IStakingModule { function obtainDepositData(uint256 _depositsCount, bytes calldata _calldata) external returns ( - uint256 depositsCount, bytes memory publicKeys, bytes memory signatures ) diff --git a/lib/abi/Lido.json b/lib/abi/Lido.json index 7d0de5b65..1ba98cad5 100644 --- a/lib/abi/Lido.json +++ b/lib/abi/Lido.json @@ -1 +1 @@ -[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_clValidators","type":"uint256"},{"name":"_clBalance","type":"uint256"},{"name":"_withdrawalVaultBalance","type":"uint256"},{"name":"_elRewardsVaultBalance","type":"uint256"},{"name":"_lastFinalizableRequestId","type":"uint256"},{"name":"_simulatedShareRate","type":"uint256"}],"name":"handleOracleReport","outputs":[{"name":"postTotalPooledEther","type":"uint256"},{"name":"postTotalShares","type":"uint256"},{"name":"withdrawals","type":"uint256"},{"name":"elRewards","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"receiveStakingRouterDepositRemainder","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"totalFee","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getDepositableEther","outputs":[{"name":"depositableEth","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"StakingRouterDepositRemainderReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}] \ No newline at end of file +[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_clValidators","type":"uint256"},{"name":"_clBalance","type":"uint256"},{"name":"_withdrawalVaultBalance","type":"uint256"},{"name":"_elRewardsVaultBalance","type":"uint256"},{"name":"_lastFinalizableRequestId","type":"uint256"},{"name":"_simulatedShareRate","type":"uint256"}],"name":"handleOracleReport","outputs":[{"name":"postTotalPooledEther","type":"uint256"},{"name":"postTotalShares","type":"uint256"},{"name":"withdrawals","type":"uint256"},{"name":"elRewards","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"totalFee","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getDepositableEther","outputs":[{"name":"depositableEther","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}] \ No newline at end of file diff --git a/lib/abi/NodeOperatorsRegistry.json b/lib/abi/NodeOperatorsRegistry.json index a5a7660a1..23c47b76b 100644 --- a/lib/abi/NodeOperatorsRegistry.json +++ b/lib/abi/NodeOperatorsRegistry.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"}],"name":"updateExitedValidatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"}],"name":"updateExitedValidatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file diff --git a/lib/abi/StakingRouter.json b/lib/abi/StakingRouter.json index eadd0ae03..14024d252 100644 --- a/lib/abi/StakingRouter.json +++ b/lib/abi/StakingRouter.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"EmptyWithdrawalsCredentials","type":"error"},{"inputs":[],"name":"ExitedValidatorsCountCannotDecrease","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidReportData","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotExpectedBalance","type":"error"},{"inputs":[],"name":"StakingModuleIdTooLarge","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","type":"error"},{"inputs":[],"name":"StakingModuleNotPaused","type":"error"},{"inputs":[],"name":"StakingModuleStatusTheSame","type":"error"},{"inputs":[],"name":"StakingModuleUnregistered","type":"error"},{"inputs":[],"name":"StakingModuleWrongName","type":"error"},{"inputs":[],"name":"StakingModulesLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpStuckValidatorsCount","type":"uint256"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ValueOver100Percent","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","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":false,"internalType":"address","name":"stakingModule","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"createdBy","type":"address"}],"name":"StakingModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unreportedExitedValidatorsCount","type":"uint256"}],"name":"StakingModuleExitedValidatorsIncompleteReporting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingModuleFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"enum StakingRouter.StakingModuleStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleTargetShareSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingRouterETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalCredentials","type":"bytes32"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"WithdrawalCredentialsSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PRECISION_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_WITHDRAWAL_CREDENTIALS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_REWARDS_MINTED_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_MANAGE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_SET_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_stakingModuleAddress","type":"address"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxDepositsCount","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"depositsCount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getAllNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"}],"name":"getDepositsAllocation","outputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLido","outputs":[{"internalType":"contract ILido","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256[]","name":"_nodeOperatorIds","type":"uint256[]"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"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":"getStakingFeeAggregateDistribution","outputs":[{"internalType":"uint96","name":"modulesFee","type":"uint96"},{"internalType":"uint96","name":"treasuryFee","type":"uint96"},{"internalType":"uint256","name":"basePrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingFeeAggregateDistributionE4Precision","outputs":[{"internalType":"uint16","name":"modulesFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModule","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleActiveValidatorsCount","outputs":[{"internalType":"uint256","name":"activeValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"}],"name":"getStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleIds","outputs":[{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleLastDepositBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleMaxDepositsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleStatus","outputs":[{"internalType":"enum StakingRouter.StakingModuleStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleSummary","outputs":[{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModules","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule[]","name":"res","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingRewardsDistribution","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"},{"internalType":"uint96[]","name":"stakingModuleFees","type":"uint96[]"},{"internalType":"uint96","name":"totalFee","type":"uint96"},{"internalType":"uint256","name":"precisionPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFeeE4Precision","outputs":[{"internalType":"uint16","name":"totalFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalCredentials","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"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"pauseStakingModule","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":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_totalShares","type":"uint256[]"}],"name":"reportRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"resumeStakingModule","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":"_stakingModuleId","type":"uint256"},{"internalType":"enum StakingRouter.StakingModuleStatus","name":"_status","type":"uint8"}],"name":"setStakingModuleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","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":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"_triggerUpdateFinish","type":"bool"},{"components":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorStuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorStuckValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.ValidatorsCountCorrection","name":"_correction","type":"tuple"}],"name":"unsafeSetExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"desiredDepositsCount","type":"uint256"},{"internalType":"uint256","name":"actualDepositsCount","type":"uint256"}],"name":"DepositsCountMismatch","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"EmptyWithdrawalsCredentials","type":"error"},{"inputs":[],"name":"ExitedValidatorsCountCannotDecrease","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"etherValue","type":"uint256"}],"name":"InvalidDepositsValue","type":"error"},{"inputs":[],"name":"InvalidReportData","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotExpectedBalance","type":"error"},{"inputs":[],"name":"StakingModuleIdTooLarge","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","type":"error"},{"inputs":[],"name":"StakingModuleNotPaused","type":"error"},{"inputs":[],"name":"StakingModuleStatusTheSame","type":"error"},{"inputs":[],"name":"StakingModuleUnregistered","type":"error"},{"inputs":[],"name":"StakingModuleWrongName","type":"error"},{"inputs":[],"name":"StakingModulesLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpStuckValidatorsCount","type":"uint256"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ValueOver100Percent","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","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":false,"internalType":"address","name":"stakingModule","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"createdBy","type":"address"}],"name":"StakingModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unreportedExitedValidatorsCount","type":"uint256"}],"name":"StakingModuleExitedValidatorsIncompleteReporting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingModuleFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"enum StakingRouter.StakingModuleStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleTargetShareSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingRouterETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalCredentials","type":"bytes32"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"WithdrawalCredentialsSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PRECISION_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_WITHDRAWAL_CREDENTIALS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_REWARDS_MINTED_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_MANAGE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_SET_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_stakingModuleAddress","type":"address"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getAllNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"}],"name":"getDepositsAllocation","outputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256[]","name":"_nodeOperatorIds","type":"uint256[]"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"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":"getStakingFeeAggregateDistribution","outputs":[{"internalType":"uint96","name":"modulesFee","type":"uint96"},{"internalType":"uint96","name":"treasuryFee","type":"uint96"},{"internalType":"uint256","name":"basePrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingFeeAggregateDistributionE4Precision","outputs":[{"internalType":"uint16","name":"modulesFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModule","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleActiveValidatorsCount","outputs":[{"internalType":"uint256","name":"activeValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"}],"name":"getStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleIds","outputs":[{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleLastDepositBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_depositableEther","type":"uint256"}],"name":"getStakingModuleMaxDepositsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleStatus","outputs":[{"internalType":"enum StakingRouter.StakingModuleStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleSummary","outputs":[{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModules","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule[]","name":"res","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingRewardsDistribution","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"},{"internalType":"uint96[]","name":"stakingModuleFees","type":"uint96[]"},{"internalType":"uint96","name":"totalFee","type":"uint96"},{"internalType":"uint256","name":"precisionPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFeeE4Precision","outputs":[{"internalType":"uint16","name":"totalFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalCredentials","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"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"pauseStakingModule","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":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_totalShares","type":"uint256[]"}],"name":"reportRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"resumeStakingModule","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":"_stakingModuleId","type":"uint256"},{"internalType":"enum StakingRouter.StakingModuleStatus","name":"_status","type":"uint8"}],"name":"setStakingModuleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","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":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"_triggerUpdateFinish","type":"bool"},{"components":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorStuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorStuckValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.ValidatorsCountCorrection","name":"_correction","type":"tuple"}],"name":"unsafeSetExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index ba8ae291a..443f613e7 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -1834,46 +1834,34 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await assert.reverts(app.obtainDepositData(10, '0x', { from: nobody }), 'APP_AUTH_FAILED') }) - it('returns empty result when no validators to deposit to', async () => { - // clear the registry to remove all unused keys with node operators + it('reverts with error "INSUFFICIENT_KEYS_COUNT" when no validators to deposit to', async () => { await app.testing_resetRegistry() const nodeOperatorsCount = await app.getNodeOperatorsCount() assert.equals(nodeOperatorsCount, 0) const keysToAllocate = 10 - const receipt = await app.testing_obtainDepositData(keysToAllocate) - const keysLoadedEvent = getEventAt(receipt, 'ValidatorsKeysLoaded').args - assert.equals(keysLoadedEvent.count, 0) - assert.isNull(keysLoadedEvent.publicKeys) - assert.isNull(keysLoadedEvent.signatures) + await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INSUFFICIENT_KEYS_COUNT') }) - it("doesn't change validators keys nonce when no available keys for deposit", async () => { - // deactivate node operators before testing to remove available keys - await app.deactivateNodeOperator(firstNodeOperatorId, { from: voting }) - await app.deactivateNodeOperator(secondNodeOperatorId, { from: voting }) - const activeNodeOperatorsCount = await app.getActiveNodeOperatorsCount() - assert.equals(activeNodeOperatorsCount, 0) + it('reverts with error "INSUFFICIENT_KEYS_COUNT" when module has not enough keys', async () => { + await app.testing_resetRegistry() - const nonceBefore = await app.getNonce() - const keysToAllocate = 10 - await app.testing_obtainDepositData(keysToAllocate) - const nonceAfter = await app.getNonce() - assert.equals(nonceBefore, nonceAfter) - }) + await app.addNodeOperator('fo o', ADDRESS_1, { from: voting }) + await app.addNodeOperator(' bar', ADDRESS_2, { from: voting }) - it("doesn't emits DepositedSigningKeysCountChanged when no available keys for deposit", async () => { - // remove unused keys - await app.onWithdrawalCredentialsChanged({ from: voting }) - const [firstNodeOperator, secondNodeOperator] = await Promise.all([ - app.getNodeOperator(firstNodeOperatorId, false), - app.getNodeOperator(secondNodeOperatorId, false) - ]) - assert.equals(firstNodeOperator.totalSigningKeys, firstNodeOperator.usedSigningKeys) - assert.equals(secondNodeOperator.totalSigningKeys, secondNodeOperator.usedSigningKeys) + const firstOperatorKeys = new signingKeys.FakeValidatorKeys(3) + const secondOperatorKeys = new signingKeys.FakeValidatorKeys(3) - const keysToAllocate = 10 - const receipt = await app.testing_obtainDepositData(keysToAllocate) - assert.notEmits(receipt, 'DepositedSigningKeysCountChanged') + await app.addSigningKeys(0, 3, ...firstOperatorKeys.slice(), { from: voting }) + await app.addSigningKeys(1, 3, ...secondOperatorKeys.slice(), { from: voting }) + + await app.setNodeOperatorStakingLimit(0, 10, { from: voting }) + await app.setNodeOperatorStakingLimit(1, 10, { from: voting }) + + const stakingModuleSummary = await app.getStakingModuleSummary() + assert.equals(stakingModuleSummary.depositableValidatorsCount, 6) + + const keysToAllocate = 7 + await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INSUFFICIENT_KEYS_COUNT') }) it('loads correct signing keys', async () => { @@ -1892,6 +1880,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await app.setNodeOperatorStakingLimit(0, 10, { from: voting }) await app.setNodeOperatorStakingLimit(1, 10, { from: voting }) + let stakingModuleSummary = await app.getStakingModuleSummary() + assert.equals(stakingModuleSummary.depositableValidatorsCount, 6) + let keysToAllocate = 1 let receipt = await app.testing_obtainDepositData(keysToAllocate) let keysLoadedEvent = getEventAt(receipt, 'ValidatorsKeysLoaded').args @@ -1899,6 +1890,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equal(keysLoadedEvent.publicKeys, firstOperatorKeys.get(0)[0], 'assignment 1: pubkeys') assert.equal(keysLoadedEvent.signatures, firstOperatorKeys.get(0)[1], 'assignment 1: signatures') + stakingModuleSummary = await app.getStakingModuleSummary() + assert.equals(stakingModuleSummary.depositableValidatorsCount, 5) + keysToAllocate = 2 receipt = await app.testing_obtainDepositData(keysToAllocate) keysLoadedEvent = getEventAt(receipt, 'ValidatorsKeysLoaded').args @@ -1915,7 +1909,13 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob 'assignment 2: signatures' ) + stakingModuleSummary = await app.getStakingModuleSummary() + assert.equals(stakingModuleSummary.depositableValidatorsCount, 3) + keysToAllocate = 10 + await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INSUFFICIENT_KEYS_COUNT') + + keysToAllocate = 3 receipt = await app.testing_obtainDepositData(keysToAllocate) keysLoadedEvent = getEventAt(receipt, 'ValidatorsKeysLoaded').args @@ -1930,17 +1930,16 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob 'assignment 2: signatures' ) - keysToAllocate = 10 - receipt = await app.testing_obtainDepositData(keysToAllocate) - keysLoadedEvent = getEventAt(receipt, 'ValidatorsKeysLoaded').args + stakingModuleSummary = await app.getStakingModuleSummary() + assert.equals(stakingModuleSummary.depositableValidatorsCount, 0) - assert.equal(keysLoadedEvent.publicKeys, null, 'no singing keys left: publicKeys') - assert.equal(keysLoadedEvent.signatures, null, 'no singing keys left: signatures') + keysToAllocate = 1 + await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INSUFFICIENT_KEYS_COUNT') }) it('increases keysOpIndex & changes nonce', async () => { const [keysOpIndexBefore, nonceBefore] = await Promise.all([app.getKeysOpIndex(), app.getNonce()]) - const keysToAllocate = 10 + const { depositableValidatorsCount: keysToAllocate } = await app.getStakingModuleSummary() await app.testing_obtainDepositData(keysToAllocate) const [keysOpIndexAfter, nonceAfter] = await Promise.all([app.getKeysOpIndex(), app.getNonce()]) assert.equals(keysOpIndexAfter, keysOpIndexBefore.toNumber() + 1) @@ -1948,7 +1947,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('increases global deposited signing keys counter', async () => { - const keysToAllocate = 10 + const { depositableValidatorsCount: keysToAllocate } = await app.getStakingModuleSummary() const keyIndex = NODE_OPERATORS[secondNodeOperatorId].depositedSigningKeysCount + 1 assert.isTrue(keyIndex <= NODE_OPERATORS[secondNodeOperatorId].totalSigningKeysCount) const { depositedSigningKeysCount: depositedSigningKeysCountBefore } = await app.testing_getTotalSigningKeysStats() @@ -1959,7 +1958,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits KeysOpIndexSet & NonceChanged', async () => { const keysOpIndexBefore = await app.getKeysOpIndex() - const keysToAllocate = 10 + const { depositableValidatorsCount: keysToAllocate } = await app.getStakingModuleSummary() const receipt = await app.testing_obtainDepositData(keysToAllocate) const nonceAfter = await app.getNonce() assert.emits(receipt, 'KeysOpIndexSet', { keysOpIndex: keysOpIndexBefore.toNumber() + 1 }) @@ -1972,7 +1971,8 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.emits(receipt, 'DepositedSigningKeysCountChanged', { nodeOperatorId: firstNodeOperatorId, depositedValidatorsCount: 6 }) assert.emits(receipt, 'DepositedSigningKeysCountChanged', { nodeOperatorId: secondNodeOperatorId, depositedValidatorsCount: 8 }) - keysToAllocate = 10 + const stakingModuleSummary = await app.getStakingModuleSummary() + keysToAllocate = stakingModuleSummary.depositableValidatorsCount receipt = await app.testing_obtainDepositData(keysToAllocate) assert.notEmits(receipt, 'DepositedSigningKeysCountChanged', { nodeOperatorId: firstNodeOperatorId, depositedSigningKeysCount: 6 }) assert.emits(receipt, 'DepositedSigningKeysCountChanged', { nodeOperatorId: secondNodeOperatorId, depositedValidatorsCount: 10 }) diff --git a/test/0.8.9/staking-router.test.js b/test/0.8.9/staking-router.test.js index 883b5566e..29b2cfce7 100644 --- a/test/0.8.9/staking-router.test.js +++ b/test/0.8.9/staking-router.test.js @@ -6,6 +6,7 @@ const { assert } = require('../helpers/assert') const { EvmSnapshot } = require('../helpers/blockchain') const { newDao, newApp } = require('../helpers/dao') const { artifacts } = require('hardhat') +const { ETH } = require('../helpers/utils') const DepositContractMock = artifacts.require('DepositContractMock') const StakingRouterMock = artifacts.require('StakingRouterMock.sol') @@ -718,7 +719,7 @@ contract('StakingRouter', ([deployer, lido, admin, appManager, stranger]) => { it('deposit fails', async () => { await assert.revertsWithCustomError( - app.deposit(100, stakingModulesParams[0].expectedModuleId, '0x00', { value: 100, from: lido }), + app.deposit(100, stakingModulesParams[0].expectedModuleId, '0x00', { value: ETH(32 * 100), from: lido }), 'StakingModuleNotActive()' ) }) From ae1f6437a67b56e31e999bd00d506354ada6367b Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Fri, 17 Feb 2023 14:49:41 +0400 Subject: [PATCH 072/199] Fix some failed tests --- .../NodeOperatorsRegistryMock.sol | 4 +++ test/0.4.24/lido.test.js | 31 +++++-------------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index 8aea69d17..1e4809b19 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -149,6 +149,10 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { ACTIVE_OPERATORS_COUNT_POSITION.setStorageUint256(0); KEYS_OP_INDEX_POSITION.setStorageUint256(0); + _nodeOperatorTotals = NodeOperatorTotals({ + signingKeysStats: Packed64x4.Packed(0) + }); + Packed64x4.Packed memory tmp; for (uint256 i = 0; i < totalOperatorsCount; ++i) { _nodeOperators[i] = NodeOperator(false, address(0), new string(0), tmp, tmp, tmp); diff --git a/test/0.4.24/lido.test.js b/test/0.4.24/lido.test.js index 3543e6a06..490c07f12 100644 --- a/test/0.4.24/lido.test.js +++ b/test/0.4.24/lido.test.js @@ -411,27 +411,6 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody }) }) - describe('receiveStakingRouterRemainder()', async () => { - it('unable to receive eth from arbitrary account', async () => { - await assertRevert(app.receiveStakingRouterDepositRemainder({ from: nobody, value: ETH(1) })) - }) - - it('event work', async () => { - // unlock stakingRouter account (allow transactions originated from stakingRouter.address) - await ethers.provider.send('hardhat_impersonateAccount', [stakingRouter.address]) - - // add some amount to the sender - - await setBalance(stakingRouter.address, ETH(100)) - - const receipt = await app.receiveStakingRouterDepositRemainder({ from: stakingRouter.address, value: ETH(2) }) - - assertEvent(receipt, 'StakingRouterDepositRemainderReceived', { - expectedArgs: { amount: ETH(2) } - }) - }) - }) - it('setWithdrawalCredentials works', async () => { await stakingRouter.setWithdrawalCredentials(pad('0x0202', 32), { from: voting }) @@ -544,7 +523,10 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody // set withdrawalCredentials with keys, because they were trimmed await stakingRouter.setWithdrawalCredentials(pad('0x0202', 32), { from: voting }) - assertBn(await stakingRouter.getStakingModuleMaxDepositsCount(CURATED_MODULE_ID), 0) + assertBn( + await stakingRouter.getStakingModuleMaxDepositsCount(CURATED_MODULE_ID, await app.getDepositableEther()), + 0 + ) await operators.addSigningKeys(0, 1, pad('0x010203', 48), pad('0x01', 96), { from: voting }) await operators.addSigningKeys( @@ -556,7 +538,10 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody ) await operators.setNodeOperatorStakingLimit(0, UNLIMITED, { from: voting }) - assertBn(await stakingRouter.getStakingModuleMaxDepositsCount(CURATED_MODULE_ID), 1) + assertBn( + await stakingRouter.getStakingModuleMaxDepositsCount(CURATED_MODULE_ID, await app.getDepositableEther()), + 1 + ) assertBn(await app.getTotalPooledEther(), ETH(34)) assertBn(await app.getBufferedEther(), ETH(34)) From a5a6623c4220e474df032631ff7aba716b90229e Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Fri, 17 Feb 2023 15:22:32 +0400 Subject: [PATCH 073/199] Remove unaccounted eth check from deposit --- contracts/0.4.24/Lido.sol | 19 +++++++------------ contracts/0.4.24/test_helpers/LidoMock.sol | 7 ------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index 06d694319..f9e5d5475 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -702,15 +702,17 @@ contract Lido is Versioned, StETHPermit, AragonApp { _maxDepositsCount, stakingRouter.getStakingModuleMaxDepositsCount(_stakingModuleId, getDepositableEther()) ); - if (depositsCount == 0) return; - - uint256 unaccountedEth = _getUnaccountedEther(); uint256 depositsValue = depositsCount.mul(DEPOSIT_SIZE); + + /// @dev At first update the local state of the contract to reduce the chances of the + /// reentrancy attack, even though the StakingRouter is a trusted contract _markAsUnbuffered(depositsValue); - /// @dev transfer ether to SR and make deposit at the same time + + /// @dev transfer ether to StakingRouter and make a deposit at the same time. All the ether + /// sent to StakingRouter is counted as deposited. If StakingRouter can't deposit all + /// passed ether it will revert the whole transaction stakingRouter.deposit.value(depositsValue)(depositsCount, _stakingModuleId, _depositCalldata); - assert(_getUnaccountedEther() == unaccountedEth); uint256 newDepositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256().add(depositsCount); DEPOSITED_VALIDATORS_POSITION.setStorageUint256(newDepositedValidators); @@ -1093,13 +1095,6 @@ contract Lido is Versioned, StETHPermit, AragonApp { return BUFFERED_ETHER_POSITION.getStorageUint256(); } - /** - * @dev Gets unaccounted (excess) Ether on this contract balance - */ - function _getUnaccountedEther() internal view returns (uint256) { - return address(this).balance.sub(_getBufferedEther()); - } - /// @dev Calculates and returns the total base balance (multiple of 32) of validators in transient state, /// i.e. submitted to the official Deposit contract but not yet visible in the CL state. /// @return transient balance in wei (1e-18 Ether) diff --git a/contracts/0.4.24/test_helpers/LidoMock.sol b/contracts/0.4.24/test_helpers/LidoMock.sol index 171667e53..b519b5cd0 100644 --- a/contracts/0.4.24/test_helpers/LidoMock.sol +++ b/contracts/0.4.24/test_helpers/LidoMock.sol @@ -36,13 +36,6 @@ contract LidoMock is Lido { _resumeStaking(); } - /** - * @dev Gets unaccounted (excess) Ether on this contract balance - */ - function getUnaccountedEther() public view returns (uint256) { - return _getUnaccountedEther(); - } - /** * @dev Only for testing recovery vault */ From 644fadb692926f1bf9629023713d4900a481fed3 Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Fri, 17 Feb 2023 15:45:55 +0400 Subject: [PATCH 074/199] Remove stakingModuleId check from Lido --- contracts/0.4.24/Lido.sol | 1 - test/0.8.9/staking-router-deposits.test.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index f9e5d5475..1912486b1 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -694,7 +694,6 @@ contract Lido is Versioned, StETHPermit, AragonApp { ILidoLocator locator = getLidoLocator(); require(msg.sender == locator.depositSecurityModule(), "APP_AUTH_DSM_FAILED"); - require(_stakingModuleId <= uint24(-1), "STAKING_MODULE_ID_TOO_LARGE"); require(canDeposit(), "CAN_NOT_DEPOSIT"); IStakingRouter stakingRouter = IStakingRouter(locator.stakingRouter()); diff --git a/test/0.8.9/staking-router-deposits.test.js b/test/0.8.9/staking-router-deposits.test.js index e113010d1..d02528e31 100644 --- a/test/0.8.9/staking-router-deposits.test.js +++ b/test/0.8.9/staking-router-deposits.test.js @@ -118,7 +118,7 @@ contract('StakingRouter', ([depositor, stranger]) => { await assert.reverts( lido.methods[`deposit(uint256,uint256,bytes)`](maxDepositsCount, maxModuleId, '0x', { from: depositor }), - 'STAKING_MODULE_ID_TOO_LARGE' + 'StakingModuleIdTooLarge()' ) }) }) From 716651e25c98bf01bdf8413ae5a884ba5312ecf6 Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Fri, 17 Feb 2023 15:46:45 +0400 Subject: [PATCH 075/199] Update naming and comments in the StakingRouter --- contracts/0.8.9/StakingRouter.sol | 28 ++++++++++++++++------------ lib/abi/StakingRouter.json | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/contracts/0.8.9/StakingRouter.sol b/contracts/0.8.9/StakingRouter.sol index 788882ef4..40dfbfef6 100644 --- a/contracts/0.8.9/StakingRouter.sol +++ b/contracts/0.8.9/StakingRouter.sol @@ -824,21 +824,25 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version activeValidatorsCount = totalDepositedValidatorsCount - totalExitedValidatorsCount; } - /** - * @dev calculate max count of deposits which staking module can provide data for based on the - * current Staking Router balance and buffered Ether amount - * - * @param _stakingModuleId id of the staking module to be deposited - * @return max number of deposits might be done using given staking module - */ - function getStakingModuleMaxDepositsCount(uint256 _stakingModuleId, uint256 _depositableEther) public view + /// @dev calculate the max count of deposits which the staking module can provide data for based + /// on the passed `_maxDepositsValue` amount + /// @param _stakingModuleId id of the staking module to be deposited + /// @param _maxDepositsValue max amount of ether that might be used for deposits count calculation + /// @return max number of deposits might be done using the given staking module + function getStakingModuleMaxDepositsCount(uint256 _stakingModuleId, uint256 _maxDepositsValue) + public + view validStakingModuleId(_stakingModuleId) returns (uint256) { + ( + /* uint256 allocated */, + uint256[] memory newDepositsAllocation, + StakingModuleCache[] memory stakingModulesCache + ) = _getDepositsAllocation(_maxDepositsValue / DEPOSIT_SIZE); uint256 stakingModuleIndex = _getStakingModuleIndexById(_stakingModuleId); - (, uint256[] memory newDepositsAllocation, StakingModuleCache[] memory stakingModulesCache) - = _getDepositsAllocation(_depositableEther / DEPOSIT_SIZE); - return newDepositsAllocation[stakingModuleIndex] - stakingModulesCache[stakingModuleIndex].activeValidatorsCount; + return + newDepositsAllocation[stakingModuleIndex] - stakingModulesCache[stakingModuleIndex].activeValidatorsCount; } /** @@ -1014,7 +1018,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version ); uint256 etherBalanceAfterDeposits = address(this).balance; - /// @dev make sure that deposited correct amount of ETH + /// @dev make sure that was deposited exactly sent amount of ETH assert(etherBalanceBeforeDeposits - etherBalanceAfterDeposits == depositsValue); stakingModule.lastDepositAt = uint64(block.timestamp); diff --git a/lib/abi/StakingRouter.json b/lib/abi/StakingRouter.json index 14024d252..864da84bd 100644 --- a/lib/abi/StakingRouter.json +++ b/lib/abi/StakingRouter.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"desiredDepositsCount","type":"uint256"},{"internalType":"uint256","name":"actualDepositsCount","type":"uint256"}],"name":"DepositsCountMismatch","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"EmptyWithdrawalsCredentials","type":"error"},{"inputs":[],"name":"ExitedValidatorsCountCannotDecrease","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"etherValue","type":"uint256"}],"name":"InvalidDepositsValue","type":"error"},{"inputs":[],"name":"InvalidReportData","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotExpectedBalance","type":"error"},{"inputs":[],"name":"StakingModuleIdTooLarge","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","type":"error"},{"inputs":[],"name":"StakingModuleNotPaused","type":"error"},{"inputs":[],"name":"StakingModuleStatusTheSame","type":"error"},{"inputs":[],"name":"StakingModuleUnregistered","type":"error"},{"inputs":[],"name":"StakingModuleWrongName","type":"error"},{"inputs":[],"name":"StakingModulesLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpStuckValidatorsCount","type":"uint256"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ValueOver100Percent","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","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":false,"internalType":"address","name":"stakingModule","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"createdBy","type":"address"}],"name":"StakingModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unreportedExitedValidatorsCount","type":"uint256"}],"name":"StakingModuleExitedValidatorsIncompleteReporting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingModuleFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"enum StakingRouter.StakingModuleStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleTargetShareSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingRouterETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalCredentials","type":"bytes32"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"WithdrawalCredentialsSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PRECISION_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_WITHDRAWAL_CREDENTIALS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_REWARDS_MINTED_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_MANAGE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_SET_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_stakingModuleAddress","type":"address"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getAllNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"}],"name":"getDepositsAllocation","outputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256[]","name":"_nodeOperatorIds","type":"uint256[]"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"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":"getStakingFeeAggregateDistribution","outputs":[{"internalType":"uint96","name":"modulesFee","type":"uint96"},{"internalType":"uint96","name":"treasuryFee","type":"uint96"},{"internalType":"uint256","name":"basePrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingFeeAggregateDistributionE4Precision","outputs":[{"internalType":"uint16","name":"modulesFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModule","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleActiveValidatorsCount","outputs":[{"internalType":"uint256","name":"activeValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"}],"name":"getStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleIds","outputs":[{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleLastDepositBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_depositableEther","type":"uint256"}],"name":"getStakingModuleMaxDepositsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleStatus","outputs":[{"internalType":"enum StakingRouter.StakingModuleStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleSummary","outputs":[{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModules","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule[]","name":"res","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingRewardsDistribution","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"},{"internalType":"uint96[]","name":"stakingModuleFees","type":"uint96[]"},{"internalType":"uint96","name":"totalFee","type":"uint96"},{"internalType":"uint256","name":"precisionPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFeeE4Precision","outputs":[{"internalType":"uint16","name":"totalFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalCredentials","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"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"pauseStakingModule","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":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_totalShares","type":"uint256[]"}],"name":"reportRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"resumeStakingModule","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":"_stakingModuleId","type":"uint256"},{"internalType":"enum StakingRouter.StakingModuleStatus","name":"_status","type":"uint8"}],"name":"setStakingModuleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","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":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"_triggerUpdateFinish","type":"bool"},{"components":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorStuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorStuckValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.ValidatorsCountCorrection","name":"_correction","type":"tuple"}],"name":"unsafeSetExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"desiredDepositsCount","type":"uint256"},{"internalType":"uint256","name":"actualDepositsCount","type":"uint256"}],"name":"DepositsCountMismatch","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"EmptyWithdrawalsCredentials","type":"error"},{"inputs":[],"name":"ExitedValidatorsCountCannotDecrease","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"etherValue","type":"uint256"}],"name":"InvalidDepositsValue","type":"error"},{"inputs":[],"name":"InvalidReportData","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotExpectedBalance","type":"error"},{"inputs":[],"name":"StakingModuleIdTooLarge","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","type":"error"},{"inputs":[],"name":"StakingModuleNotPaused","type":"error"},{"inputs":[],"name":"StakingModuleStatusTheSame","type":"error"},{"inputs":[],"name":"StakingModuleUnregistered","type":"error"},{"inputs":[],"name":"StakingModuleWrongName","type":"error"},{"inputs":[],"name":"StakingModulesLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpStuckValidatorsCount","type":"uint256"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ValueOver100Percent","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","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":false,"internalType":"address","name":"stakingModule","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"createdBy","type":"address"}],"name":"StakingModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unreportedExitedValidatorsCount","type":"uint256"}],"name":"StakingModuleExitedValidatorsIncompleteReporting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingModuleFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"enum StakingRouter.StakingModuleStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleTargetShareSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingRouterETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalCredentials","type":"bytes32"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"WithdrawalCredentialsSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PRECISION_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_WITHDRAWAL_CREDENTIALS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_REWARDS_MINTED_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_MANAGE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_SET_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_stakingModuleAddress","type":"address"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getAllNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"}],"name":"getDepositsAllocation","outputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256[]","name":"_nodeOperatorIds","type":"uint256[]"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"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":"getStakingFeeAggregateDistribution","outputs":[{"internalType":"uint96","name":"modulesFee","type":"uint96"},{"internalType":"uint96","name":"treasuryFee","type":"uint96"},{"internalType":"uint256","name":"basePrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingFeeAggregateDistributionE4Precision","outputs":[{"internalType":"uint16","name":"modulesFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModule","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleActiveValidatorsCount","outputs":[{"internalType":"uint256","name":"activeValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"}],"name":"getStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleIds","outputs":[{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleLastDepositBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_maxDepositsValue","type":"uint256"}],"name":"getStakingModuleMaxDepositsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleStatus","outputs":[{"internalType":"enum StakingRouter.StakingModuleStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleSummary","outputs":[{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModules","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule[]","name":"res","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingRewardsDistribution","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"},{"internalType":"uint96[]","name":"stakingModuleFees","type":"uint96[]"},{"internalType":"uint96","name":"totalFee","type":"uint96"},{"internalType":"uint256","name":"precisionPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFeeE4Precision","outputs":[{"internalType":"uint16","name":"totalFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalCredentials","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"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"pauseStakingModule","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":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_totalShares","type":"uint256[]"}],"name":"reportRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"resumeStakingModule","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":"_stakingModuleId","type":"uint256"},{"internalType":"enum StakingRouter.StakingModuleStatus","name":"_status","type":"uint8"}],"name":"setStakingModuleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","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":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"_triggerUpdateFinish","type":"bool"},{"components":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorStuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorStuckValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.ValidatorsCountCorrection","name":"_correction","type":"tuple"}],"name":"unsafeSetExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file From eacf20475c9243a9b2e0dd7f676cacfad957303f Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Fri, 17 Feb 2023 14:03:19 +0200 Subject: [PATCH 076/199] feat: view to get claimable ether for request --- contracts/0.8.9/WithdrawalQueue.sol | 16 ++++++++- contracts/0.8.9/WithdrawalQueueBase.sol | 47 ++++++++++++++++++------- lib/abi/WithdrawalQueue.json | 2 +- lib/abi/WithdrawalRequestNFT.json | 2 +- test/0.8.9/withdrawal-queue.test.js | 38 +++++++++++++++++++- 5 files changed, 88 insertions(+), 17 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index b39d57215..be5a728aa 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -209,7 +209,21 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit uint256 hint; } - /// @notice Claim withdrawals batch once finalized (claimable). + /// @notice Return batch of claimable eth amounts that is locked for each request + /// @param _claimWithdrawalInputs list of withdrawal request ids and hints to claim + function getClaimableEther(ClaimWithdrawalInput[] calldata _claimWithdrawalInputs) + external + view + returns (uint256[] memory finalEthValues) + { + finalEthValues = new uint256[](_claimWithdrawalInputs.length); + for (uint256 i = 0; i < _claimWithdrawalInputs.length; ++i) { + (, finalEthValues[i]) = + _calculateClaimableEth(_claimWithdrawalInputs[i].requestId, _claimWithdrawalInputs[i].hint); + } + } + + /// @notice Claim withdrawals batch once finalized (claimable) and send claimable ether to `msg.sender` /// @param _claimWithdrawalInputs list of withdrawal request ids and hints to claim function claimWithdrawals(ClaimWithdrawalInput[] calldata _claimWithdrawalInputs) external { for (uint256 i = 0; i < _claimWithdrawalInputs.length; ++i) { diff --git a/contracts/0.8.9/WithdrawalQueueBase.sol b/contracts/0.8.9/WithdrawalQueueBase.sol index 10695fda8..d0c1d3d67 100644 --- a/contracts/0.8.9/WithdrawalQueueBase.sol +++ b/contracts/0.8.9/WithdrawalQueueBase.sol @@ -424,31 +424,56 @@ abstract contract WithdrawalQueueBase { } /// @notice Claim `_requestId` request and transfer related ether to the `_recipient`. Emits WithdrawalClaimed event + /// @dev Reverts if request is not finalized + /// Reverts if request is claimed /// @param _requestId request id to claim /// @param _hint hint for discount checkpoint index to avoid extensive search over the checkpoints. /// Can be found with `findCheckpointHint()` or `findCheckpointHintUnbounded()` /// @param _recipient address to send ether to. If `==address(0)` then will send to the owner. function _claimWithdrawalTo(uint256 _requestId, uint256 _hint, address _recipient) internal { - if (_hint == 0) revert InvalidHint(_hint); - - if (_requestId == 0) revert InvalidRequestId(0); if (_requestId > getLastFinalizedRequestId()) revert RequestNotFinalized(_requestId); - uint256 lastCheckpointIndex = getLastCheckpointIndex(); - if (_hint > lastCheckpointIndex) revert InvalidHint(_hint); - WithdrawalRequest storage request = _getQueue()[_requestId]; + (WithdrawalRequest storage request, uint256 ethWithDiscount) = _calculateClaimableEth(_requestId, _hint); + if (request.claimed) revert RequestAlreadyClaimed(_requestId); if (msg.sender != request.owner) revert NotOwner(msg.sender, request.owner); + if (_recipient == address(0)) _recipient = request.owner; request.claimed = true; + _setLockedEtherAmount(getLockedEtherAmount() - ethWithDiscount); + + _sendValue(payable(_recipient), ethWithDiscount); + + emit WithdrawalClaimed(_requestId, msg.sender, _recipient, ethWithDiscount); + } + + /// @notice Calculates discounted ether value for `_requestId` using a provided `_hint` + /// @return request link to request in storage + /// @return ethWithDiscount discounted eth for `_requestId`. Returns 0 if request is not claimable + function _calculateClaimableEth(uint256 _requestId, uint256 _hint) + internal + view + returns (WithdrawalRequest storage, uint256) + { + if (_hint == 0) revert InvalidHint(_hint); + if (_requestId == 0 || _requestId > getLastRequestId()) revert InvalidRequestId(_requestId); + + WithdrawalRequest storage request = _getQueue()[_requestId]; + + // shortcuts + if (_requestId > getLastFinalizedRequestId()) return (request, 0); + if (request.claimed) return (request, 0); + + uint256 lastCheckpointIndex = getLastCheckpointIndex(); + if (_hint > lastCheckpointIndex) revert InvalidHint(_hint); DiscountCheckpoint memory hintCheckpoint = _getCheckpoints()[_hint]; - // ______(_______ + // ______(>______ // ^ hint if (_requestId < hintCheckpoint.fromRequestId) revert InvalidHint(_hint); if (_hint < lastCheckpointIndex) { - // ______(_______(_________ + // ______(>______(>________ // hint hint+1 ^ DiscountCheckpoint memory nextCheckpoint = _getCheckpoints()[_hint + 1]; if (nextCheckpoint.fromRequestId <= _requestId) { @@ -459,11 +484,7 @@ abstract contract WithdrawalQueueBase { uint256 ethRequested = request.cumulativeStETH - _getQueue()[_requestId - 1].cumulativeStETH; uint256 ethWithDiscount = ethRequested * hintCheckpoint.discountFactor / E27_PRECISION_BASE; - _setLockedEtherAmount(getLockedEtherAmount() - ethWithDiscount); - - _sendValue(payable(_recipient), ethWithDiscount); - - emit WithdrawalClaimed(_requestId, msg.sender, _recipient, ethWithDiscount); + return (request, ethWithDiscount); } // quazi-constructor diff --git a/lib/abi/WithdrawalQueue.json b/lib/abi/WithdrawalQueue.json index e81ab351d..9d1c12fc8 100644 --- a/lib/abi/WithdrawalQueue.json +++ b/lib/abi/WithdrawalQueue.json @@ -1 +1 @@ -[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"finalEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalRequestNFT.json b/lib/abi/WithdrawalRequestNFT.json index 0ccb54190..a49aa4f4d 100644 --- a/lib/abi/WithdrawalRequestNFT.json +++ b/lib/abi/WithdrawalRequestNFT.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"finalEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/test/0.8.9/withdrawal-queue.test.js b/test/0.8.9/withdrawal-queue.test.js index bb859d0f4..cda146b6a 100644 --- a/test/0.8.9/withdrawal-queue.test.js +++ b/test/0.8.9/withdrawal-queue.test.js @@ -249,6 +249,42 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) }) + context('getClaimableEth()', () => { + beforeEach(async () => { + await withdrawalQueue.requestWithdrawals([ETH(1)], owner, { from: user }) + }) + + it('works', async () => { + await withdrawalQueue.requestWithdrawals([ETH(1)], owner, { from: user }) + await withdrawalQueue.finalize(1, { from: steth.address, value: ETH(1) }) + + assert.equals(await withdrawalQueue.getClaimableEther([[1, 1]]), ETH(1)) + }) + + it('return 0 for non-finalized request', async () => { + assert.equals(await withdrawalQueue.getClaimableEther([[1, 1]]), ETH(0)) + }) + + it('return 0 for claimed request', async () => { + await withdrawalQueue.finalize(1, { from: steth.address, value: ETH(1) }) + await withdrawalQueue.claimWithdrawalTo(1, 1, user, { from: owner }) + + assert.equals(await withdrawalQueue.getClaimableEther([[1, 1]]), ETH(0)) + }) + + it('reverts on invalid params', async () => { + await assert.reverts(withdrawalQueue.getClaimableEther([[0, 1]]), 'InvalidRequestId(0)') + await assert.reverts(withdrawalQueue.getClaimableEther([[2, 1]]), 'InvalidRequestId(2)') + await assert.reverts(withdrawalQueue.getClaimableEther([[1, 0]]), 'InvalidHint(0)') + + await withdrawalQueue.finalize(1, { from: steth.address, value: ETH(1) }) + await assert.reverts(withdrawalQueue.getClaimableEther([[1, 2]]), 'InvalidHint(2)') + + await withdrawalQueue.requestWithdrawals([ETH(1)], owner, { from: user }) + await assert.reverts(withdrawalQueue.getClaimableEther([[1, 2]]), 'InvalidHint(2)') + }) + }) + context('claimWithdrawal()', async () => { let requestId const amount = ETH(300) @@ -796,7 +832,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { it("Changing owner doesn't work with wrong request id", async () => { const wrongRequestId = requestId + 1 await assert.reverts(withdrawalQueue.transferFrom(user, owner, wrongRequestId, { from: user }), - `InvalidRequestId(${wrongRequestId})`) + `InvalidRequestId(${wrongRequestId})`) }) }) From 5e35d35a0c477a780bc2d1f82004789791140d6c Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Fri, 17 Feb 2023 14:22:44 +0200 Subject: [PATCH 077/199] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F:=20WithdrawalRequ?= =?UTF-8?q?estNFT=20->=20WithdrawalQueueERC721?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...questNFT.sol => WithdrawalQueueERC721.sol} | 8 +- ...estNFT.json => WithdrawalQueueERC721.json} | 0 test/0.8.9/withdrawal-request-nft.test.js | 152 +++++++++--------- test/helpers/withdrawals.js | 8 +- 4 files changed, 84 insertions(+), 84 deletions(-) rename contracts/0.8.9/{WithdrawalRequestNFT.sol => WithdrawalQueueERC721.sol} (98%) rename lib/abi/{WithdrawalRequestNFT.json => WithdrawalQueueERC721.json} (100%) diff --git a/contracts/0.8.9/WithdrawalRequestNFT.sol b/contracts/0.8.9/WithdrawalQueueERC721.sol similarity index 98% rename from contracts/0.8.9/WithdrawalRequestNFT.sol rename to contracts/0.8.9/WithdrawalQueueERC721.sol index b0d7930f1..5bcfefe60 100644 --- a/contracts/0.8.9/WithdrawalRequestNFT.sol +++ b/contracts/0.8.9/WithdrawalQueueERC721.sol @@ -21,15 +21,15 @@ import {UnstructuredRefStorage} from "./lib/UnstructuredRefStorage.sol"; /// NFT is minted on every request and burned on claim /// /// @author psirex, folkyatina -contract WithdrawalRequestNFT is IERC721Metadata, WithdrawalQueue { +contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { using Address for address; using Strings for uint256; using EnumerableSet for EnumerableSet.UintSet; using UnstructuredRefStorage for bytes32; - bytes32 internal constant TOKEN_APPROVALS_POSITION = keccak256("lido.WithdrawalRequestNFT.tokenApprovals"); - bytes32 internal constant OPERATOR_APPROVALS_POSITION = keccak256("lido.WithdrawalRequestNFT.operatorApprovals"); - bytes32 internal constant BASE_URI_POSITION = keccak256("lido.WithdrawalRequestNFT.baseUri"); + bytes32 internal constant TOKEN_APPROVALS_POSITION = keccak256("lido.WithdrawalQueueERC721.tokenApprovals"); + bytes32 internal constant OPERATOR_APPROVALS_POSITION = keccak256("lido.WithdrawalQueueERC721.operatorApprovals"); + bytes32 internal constant BASE_URI_POSITION = keccak256("lido.WithdrawalQueueERC721.baseUri"); bytes32 public constant SET_BASE_URI_ROLE = keccak256("SET_BASE_URI_ROLE"); diff --git a/lib/abi/WithdrawalRequestNFT.json b/lib/abi/WithdrawalQueueERC721.json similarity index 100% rename from lib/abi/WithdrawalRequestNFT.json rename to lib/abi/WithdrawalQueueERC721.json diff --git a/test/0.8.9/withdrawal-request-nft.test.js b/test/0.8.9/withdrawal-request-nft.test.js index 0a6e412f4..a66e29438 100644 --- a/test/0.8.9/withdrawal-request-nft.test.js +++ b/test/0.8.9/withdrawal-request-nft.test.js @@ -11,7 +11,7 @@ const ERC721ReceiverMock = hre.artifacts.require('ERC721ReceiverMock') hre.contract( 'WithdrawalNFT', ([deployer, stEthHolder, wstEthHolder, nftHolderStETH, nftHolderWstETH, recipient, stranger]) => { - let withdrawalRequestNFT, stETH, wstETH, erc721ReceiverMock + let withdrawalQueueERC721, stETH, wstETH, erc721ReceiverMock let nftHolderStETHTokenIds, nftHolderWstETHTokenIds, nonExistedTokenId const snapshot = new EvmSnapshot(hre.ethers.provider) @@ -21,26 +21,26 @@ hre.contract( wstETH = await WstETH.new(stETH.address, { from: deployer }) erc721ReceiverMock = await ERC721ReceiverMock.new({ from: deployer }) - withdrawalRequestNFT = (await withdrawals.deploy(deployer, wstETH.address)).queue - await withdrawalRequestNFT.initialize( + withdrawalQueueERC721 = (await withdrawals.deploy(deployer, wstETH.address, "Lido TEST Request", "unstEsT")).queue + await withdrawalQueueERC721.initialize( deployer, // owner deployer, // pauser deployer, // resumer deployer, // finalizer deployer ) - await withdrawalRequestNFT.resume({ from: deployer }) + await withdrawalQueueERC721.resume({ from: deployer }) await stETH.setTotalPooledEther(ETH(101)) await stETH.mintShares(stEthHolder, shares(50)) await stETH.mintShares(wstETH.address, shares(50)) await wstETH.mint(wstEthHolder, ETH(25)) - await stETH.approve(withdrawalRequestNFT.address, ETH(50), { from: stEthHolder }) - await wstETH.approve(withdrawalRequestNFT.address, ETH(25), { from: wstEthHolder }) - await withdrawalRequestNFT.requestWithdrawals([ETH(25), ETH(25)], nftHolderStETH,{ from: stEthHolder }) + await stETH.approve(withdrawalQueueERC721.address, ETH(50), { from: stEthHolder }) + await wstETH.approve(withdrawalQueueERC721.address, ETH(25), { from: wstEthHolder }) + await withdrawalQueueERC721.requestWithdrawals([ETH(25), ETH(25)], nftHolderStETH, { from: stEthHolder }) nftHolderStETHTokenIds = [1, 2] - await withdrawalRequestNFT.requestWithdrawalsWstETH([ETH(25)], nftHolderWstETH, { from: wstEthHolder }) + await withdrawalQueueERC721.requestWithdrawalsWstETH([ETH(25)], nftHolderWstETH, { from: wstEthHolder }) nftHolderWstETHTokenIds = [3] nonExistedTokenId = 4 await snapshot.make() @@ -52,81 +52,81 @@ hre.contract( describe('ERC721Metadata', () => { it('Initial properties', async () => { - assert.equals(await withdrawalRequestNFT.symbol(), "unstETH") - assert.equals(await withdrawalRequestNFT.name(), "Lido Withdrawal Request") + assert.equals(await withdrawalQueueERC721.symbol(), "unstEsT") + assert.equals(await withdrawalQueueERC721.name(), "Lido TEST Request") }) }) describe('supportsInterface()', () => { it('returns true for IERC165 interfaceiId (0x01ffc9a7)', async () => { - assert.isTrue(await withdrawalRequestNFT.supportsInterface('0x01ffc9a7')) + assert.isTrue(await withdrawalQueueERC721.supportsInterface('0x01ffc9a7')) }) it('returns true for IERC721 interface id (0x80ac58cd)', async () => { - assert.isTrue(await withdrawalRequestNFT.supportsInterface('0x80ac58cd')) + assert.isTrue(await withdrawalQueueERC721.supportsInterface('0x80ac58cd')) }) it('returns true for AccessControlEnumerable interface id (0x5a05180f)', async () => { - assert.isTrue(await withdrawalRequestNFT.supportsInterface('0x5a05180f')) + assert.isTrue(await withdrawalQueueERC721.supportsInterface('0x5a05180f')) }) it('returns false for unsupported e interface id (0xffffffff)', async () => { - assert.isFalse(await withdrawalRequestNFT.supportsInterface('0xffffffff')) + assert.isFalse(await withdrawalQueueERC721.supportsInterface('0xffffffff')) }) it('returns false for unsupported e interface id (0xdeadbeaf)', async () => { - assert.isFalse(await withdrawalRequestNFT.supportsInterface('0xdeadbeaf')) + assert.isFalse(await withdrawalQueueERC721.supportsInterface('0xdeadbeaf')) }) }) describe('balanceOf()', () => { it('return 0 when user has not withdrawal requests', async () => { - assert.equals(await withdrawalRequestNFT.balanceOf(recipient), 0) + assert.equals(await withdrawalQueueERC721.balanceOf(recipient), 0) }) it('return correct withdrawal requests count', async () => { - assert.equals(await withdrawalRequestNFT.balanceOf(nftHolderStETH), 2) - assert.equals(await withdrawalRequestNFT.balanceOf(nftHolderWstETH), 1) + assert.equals(await withdrawalQueueERC721.balanceOf(nftHolderStETH), 2) + assert.equals(await withdrawalQueueERC721.balanceOf(nftHolderWstETH), 1) }) }) describe('ownerOf()', () => { it('reverts with error InvalidRequestId() when token id is 0', async () => { - await assert.reverts(withdrawalRequestNFT.ownerOf(0), `InvalidRequestId(0)`) + await assert.reverts(withdrawalQueueERC721.ownerOf(0), `InvalidRequestId(0)`) }) it('reverts with error InvalidRequestId() when called with non existed token id', async () => { - await assert.reverts(withdrawalRequestNFT.ownerOf(nonExistedTokenId), `InvalidRequestId(${nonExistedTokenId})`) + await assert.reverts(withdrawalQueueERC721.ownerOf(nonExistedTokenId), `InvalidRequestId(${nonExistedTokenId})`) }) it('reverts correct owner', async () => { - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), nftHolderStETH) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[1]), nftHolderStETH) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderWstETHTokenIds[0]), nftHolderWstETH) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), nftHolderStETH) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[1]), nftHolderStETH) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderWstETHTokenIds[0]), nftHolderWstETH) }) }) describe('approve()', async () => { it('reverts with message "ApprovalToOwner()" when approval for owner address', async () => { await assert.reverts( - withdrawalRequestNFT.approve(nftHolderStETH, nftHolderStETHTokenIds[0], { from: nftHolderStETH }), + withdrawalQueueERC721.approve(nftHolderStETH, nftHolderStETHTokenIds[0], { from: nftHolderStETH }), 'ApprovalToOwner()' ) }) it('reverts with message "NotOwnerOrApprovedForAll()" when called noy by owner', async () => { await assert.reverts( - withdrawalRequestNFT.approve(recipient, nftHolderStETHTokenIds[0], { from: stranger }), + withdrawalQueueERC721.approve(recipient, nftHolderStETHTokenIds[0], { from: stranger }), `NotOwnerOrApprovedForAll("${stranger}")` ) }) it('sets approval for address', async () => { - await withdrawalRequestNFT.approve(recipient, nftHolderStETHTokenIds[0], { from: nftHolderStETH }) - assert.equal(await withdrawalRequestNFT.getApproved(nftHolderStETHTokenIds[0]), recipient) + await withdrawalQueueERC721.approve(recipient, nftHolderStETHTokenIds[0], { from: nftHolderStETH }) + assert.equal(await withdrawalQueueERC721.getApproved(nftHolderStETHTokenIds[0]), recipient) }) }) describe('getApproved()', async () => { it('reverts with message "InvalidRequestId()" when called with non existed token id', async () => { await assert.reverts( - withdrawalRequestNFT.getApproved(nonExistedTokenId), + withdrawalQueueERC721.getApproved(nonExistedTokenId), `InvalidRequestId(${nonExistedTokenId})` ) }) @@ -135,7 +135,7 @@ hre.contract( describe('setApprovalForAll()', async () => { it('reverts with message "ApproveToCaller()" when owner equal to operator', async () => { await assert.reverts( - withdrawalRequestNFT.setApprovalForAll(nftHolderStETH, true, { from: nftHolderStETH }), + withdrawalQueueERC721.setApprovalForAll(nftHolderStETH, true, { from: nftHolderStETH }), 'ApproveToCaller()' ) }) @@ -144,7 +144,7 @@ hre.contract( describe('safeTransferFrom(address,address,uint256)', async () => { it('reverts with message "NotOwnerOrApproved()" when approvalNotSet and not owner', async () => { await assert.reverts( - withdrawalRequestNFT.safeTransferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { + withdrawalQueueERC721.safeTransferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { from: stranger }), `NotOwnerOrApproved("${stranger}")` @@ -152,39 +152,39 @@ hre.contract( }) it('transfers if called by owner', async () => { - assert.notEqual(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) - await withdrawalRequestNFT.safeTransferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { + assert.notEqual(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) + await withdrawalQueueERC721.safeTransferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { from: nftHolderStETH }) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) }) it('transfers if token approval set', async () => { - await withdrawalRequestNFT.approve(recipient, nftHolderStETHTokenIds[0], { from: nftHolderStETH }) - assert.notEqual(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) - await withdrawalRequestNFT.safeTransferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { + await withdrawalQueueERC721.approve(recipient, nftHolderStETHTokenIds[0], { from: nftHolderStETH }) + assert.notEqual(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) + await withdrawalQueueERC721.safeTransferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { from: recipient }) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) }) it('transfers if operator approval set', async () => { - await withdrawalRequestNFT.setApprovalForAll(recipient, true, { from: nftHolderStETH }) - assert.notEqual(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) - assert.notEqual(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[1]), recipient) - await withdrawalRequestNFT.safeTransferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { + await withdrawalQueueERC721.setApprovalForAll(recipient, true, { from: nftHolderStETH }) + assert.notEqual(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) + assert.notEqual(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[1]), recipient) + await withdrawalQueueERC721.safeTransferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { from: recipient }) - await withdrawalRequestNFT.safeTransferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[1], { + await withdrawalQueueERC721.safeTransferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[1], { from: recipient }) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[1]), recipient) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[1]), recipient) }) it('reverts with message "TransferToNonIERC721Receiver()" when transfer to contract that not implements IERC721Receiver interface', async () => { await assert.reverts( - withdrawalRequestNFT.safeTransferFrom(nftHolderWstETH, stETH.address, nftHolderWstETHTokenIds[0], { + withdrawalQueueERC721.safeTransferFrom(nftHolderWstETH, stETH.address, nftHolderWstETHTokenIds[0], { from: nftHolderWstETH }), `TransferToNonIERC721Receiver("${stETH.address}")` @@ -194,7 +194,7 @@ hre.contract( it('reverts with propagated error message when recipient contract implements ERC721Receiver and reverts on onERC721Received call', async () => { await erc721ReceiverMock.setDoesAcceptTokens(false, { from: deployer }) await assert.reverts( - withdrawalRequestNFT.safeTransferFrom(nftHolderStETH, erc721ReceiverMock.address, nftHolderStETHTokenIds[0], { + withdrawalQueueERC721.safeTransferFrom(nftHolderStETH, erc721ReceiverMock.address, nftHolderStETHTokenIds[0], { from: nftHolderStETH }), 'ERC721_NOT_ACCEPT_TOKENS' @@ -203,8 +203,8 @@ hre.contract( it("doesn't revert when recipient contract implements ERC721Receiver interface and accepts tokens", async () => { await erc721ReceiverMock.setDoesAcceptTokens(true, { from: deployer }) - assert.notEqual(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), erc721ReceiverMock.address) - await withdrawalRequestNFT.safeTransferFrom( + assert.notEqual(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), erc721ReceiverMock.address) + await withdrawalQueueERC721.safeTransferFrom( nftHolderStETH, erc721ReceiverMock.address, nftHolderStETHTokenIds[0], @@ -212,23 +212,23 @@ hre.contract( from: nftHolderStETH } ) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), erc721ReceiverMock.address) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), erc721ReceiverMock.address) }) }) describe('transferFrom()', async () => { it('reverts with message "NotOwnerOrApproved()" when approvalNotSet and not owner', async () => { await assert.reverts( - withdrawalRequestNFT.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { from: stranger }), + withdrawalQueueERC721.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { from: stranger }), `NotOwnerOrApproved("${stranger}")` ) }) it('reverts with error "RequestAlreadyClaimed()" when called on claimed request', async () => { - const batch = await withdrawalRequestNFT.finalizationBatch(3, shareRate(1)) - await withdrawalRequestNFT.finalize(3, { from: deployer, value: batch.ethToLock }) + const batch = await withdrawalQueueERC721.finalizationBatch(3, shareRate(1)) + await withdrawalQueueERC721.finalize(3, { from: deployer, value: batch.ethToLock }) const ownerETHBefore = await hre.ethers.provider.getBalance(nftHolderStETH) - const tx = await withdrawalRequestNFT.methods['claimWithdrawal(uint256)'](nftHolderStETHTokenIds[0], { + const tx = await withdrawalQueueERC721.methods['claimWithdrawal(uint256)'](nftHolderStETHTokenIds[0], { from: nftHolderStETH }) const ownerETHAfter = await hre.ethers.provider.getBalance(nftHolderStETH) @@ -236,7 +236,7 @@ hre.contract( assert.almostEqual(ownerETHAfter, ownerETHBefore.add(ETH(25)), tx.receipt.gasUsed) await assert.reverts( - withdrawalRequestNFT.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { + withdrawalQueueERC721.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { from: nftHolderStETH }), `RequestAlreadyClaimed(${nftHolderStETHTokenIds[0]})` @@ -244,47 +244,47 @@ hre.contract( }) it('transfers if called by owner', async () => { - assert.notEqual(await withdrawalRequestNFT.ownerOf(nftHolderWstETHTokenIds[0]), recipient) - await withdrawalRequestNFT.transferFrom(nftHolderWstETH, recipient, nftHolderWstETHTokenIds[0], { + assert.notEqual(await withdrawalQueueERC721.ownerOf(nftHolderWstETHTokenIds[0]), recipient) + await withdrawalQueueERC721.transferFrom(nftHolderWstETH, recipient, nftHolderWstETHTokenIds[0], { from: nftHolderWstETH }) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderWstETHTokenIds[0]), recipient) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderWstETHTokenIds[0]), recipient) }) it('transfers if token approval set', async () => { - await withdrawalRequestNFT.approve(recipient, nftHolderStETHTokenIds[0], { from: nftHolderStETH }) - assert.notEqual(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) - await withdrawalRequestNFT.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { + await withdrawalQueueERC721.approve(recipient, nftHolderStETHTokenIds[0], { from: nftHolderStETH }) + assert.notEqual(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) + await withdrawalQueueERC721.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { from: recipient }) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) }) it('transfers if operator approval set', async () => { - await withdrawalRequestNFT.setApprovalForAll(recipient, true, { from: nftHolderStETH }) - assert.notEqual(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) - assert.notEqual(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[1]), recipient) - await withdrawalRequestNFT.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { + await withdrawalQueueERC721.setApprovalForAll(recipient, true, { from: nftHolderStETH }) + assert.notEqual(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) + assert.notEqual(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[1]), recipient) + await withdrawalQueueERC721.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { from: recipient }) - await withdrawalRequestNFT.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[1], { + await withdrawalQueueERC721.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[1], { from: recipient }) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[1]), recipient) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[1]), recipient) }) it('can claim request after transfer', async () => { - await withdrawalRequestNFT.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { + await withdrawalQueueERC721.transferFrom(nftHolderStETH, recipient, nftHolderStETHTokenIds[0], { from: nftHolderStETH }) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderStETHTokenIds[0]), recipient) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderStETHTokenIds[0]), recipient) - const batch = await withdrawalRequestNFT.finalizationBatch(3, shareRate(1)) - await withdrawalRequestNFT.finalize(3, { from: deployer, value: batch.ethToLock }) + const batch = await withdrawalQueueERC721.finalizationBatch(3, shareRate(1)) + await withdrawalQueueERC721.finalize(3, { from: deployer, value: batch.ethToLock }) const recipientETHBefore = await hre.ethers.provider.getBalance(recipient) - const tx = await withdrawalRequestNFT.methods['claimWithdrawal(uint256)'](nftHolderStETHTokenIds[0], { + const tx = await withdrawalQueueERC721.methods['claimWithdrawal(uint256)'](nftHolderStETHTokenIds[0], { from: recipient }) const recipientETHAfter = await hre.ethers.provider.getBalance(recipient) @@ -293,11 +293,11 @@ hre.contract( }) it("doesn't reverts when transfer to contract that not implements IERC721Receiver interface", async () => { - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderWstETHTokenIds[0]), nftHolderWstETH) - await withdrawalRequestNFT.transferFrom(nftHolderWstETH, stETH.address, nftHolderWstETHTokenIds[0], { + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderWstETHTokenIds[0]), nftHolderWstETH) + await withdrawalQueueERC721.transferFrom(nftHolderWstETH, stETH.address, nftHolderWstETHTokenIds[0], { from: nftHolderWstETH }) - assert.equal(await withdrawalRequestNFT.ownerOf(nftHolderWstETHTokenIds[0]), stETH.address) + assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderWstETHTokenIds[0]), stETH.address) }) }) } diff --git a/test/helpers/withdrawals.js b/test/helpers/withdrawals.js index b89d7a01f..9a247fc80 100644 --- a/test/helpers/withdrawals.js +++ b/test/helpers/withdrawals.js @@ -1,12 +1,12 @@ const { utils } = require('ethers') const OssifiableProxy = artifacts.require('OssifiableProxy.sol') -const WithdrawalRequestNFT = artifacts.require('WithdrawalRequestNFT.sol') +const WithdrawalQueueERC721 = artifacts.require('WithdrawalQueueERC721.sol') -async function deploy(ownerAddress, wstethAddress, name = "Lido Withdrawal Request", symbol = "unstETH") { - const impl = await WithdrawalRequestNFT.new(wstethAddress, name, symbol) +async function deploy(ownerAddress, wstethAddress, name = "Lido: Withdrawal Request NFT", symbol = "unstETH") { + const impl = await WithdrawalQueueERC721.new(wstethAddress, name, symbol) const proxy = await OssifiableProxy.new(impl.address, ownerAddress, '0x') - const queue = await WithdrawalRequestNFT.at(proxy.address) + const queue = await WithdrawalQueueERC721.at(proxy.address) return { impl, From 1278fb505ad611838c6589e3eb0f19b9f6cb8930 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Fri, 17 Feb 2023 20:36:18 +0700 Subject: [PATCH 078/199] feat: add WarnExtraDataIncompleteProcessing event test --- ...counting-oracle-submit-report-data.test.js | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js index a580ddca9..b6336ce88 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js @@ -1,6 +1,8 @@ const { assert } = require('../../helpers/assert') const { e9, e18, e27 } = require('../../helpers/utils') +const AccountingOracleAbi = require('../../../lib/abi/AccountingOracle.json') + const { CONSENSUS_VERSION, deployAndConfigureAccountingOracle, @@ -14,7 +16,8 @@ const { SLOTS_PER_FRAME, SECONDS_PER_SLOT, GENESIS_TIME, - ZERO_HASH + ZERO_HASH, + HASH_1 } = require('./accounting-oracle-deploy.test') contract('AccountingOracle', ([admin, account1, account2, member1, member2, stranger]) => { @@ -473,6 +476,27 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) }) + context('warns when prev extra data has not been processed yet', () => { + it('emits WarnExtraDataIncompleteProcessing', async () => { + await consensus.setTime(deadline) + const prevRefSlot = +(await consensus.getCurrentFrame()).refSlot + await oracle.submitReportData(reportItems, oracleVersion, { from: member1 }) + await consensus.advanceTimeToNextFrameStart() + const nextRefSlot = +(await consensus.getCurrentFrame()).refSlot + const tx = await consensus.submitReport(nextRefSlot, HASH_1, CONSENSUS_VERSION, { from: member1 }) + assert.emits( + tx, + 'WarnExtraDataIncompleteProcessing', + { + refSlot: prevRefSlot, + processedItemsCount: 0, + itemsCount: extraDataItems.length + }, + { abi: AccountingOracleAbi } + ) + }) + }) + context('enforces extra data format', () => { it('should revert on invalid extra data format', async () => { await consensus.setTime(deadline) From 75db5798974442361061490e934bdf8a21b4bc75 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Fri, 17 Feb 2023 14:39:53 +0100 Subject: [PATCH 079/199] refactor: update stuck/exited counts --- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 161c6bdd2..1858dcea5 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -437,11 +437,15 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 nodeOperatorId; uint64 validatorsCount; + uint256 _nodeOperatorIdsOffset; + uint256 _stuckValidatorsCountsOffset; + assembly { + _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) + _stuckValidatorsCountsOffset := add(calldataload(36), 36) // signature_bytes4 + arg2_bytes calldata offset + 32 (length slot)) + } for (uint256 i; i < nodeOperatorsCount; ) { /// @solidity memory-safe-assembly assembly { - let _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) - let _stuckValidatorsCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot) nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) validatorsCount := shr(128, calldataload(add(_stuckValidatorsCountsOffset, mul(i, 16)))) i := add(i, 1) @@ -471,12 +475,15 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 nodeOperatorId; uint64 validatorsCount; - + uint256 _nodeOperatorIdsOffset; + uint256 _stuckValidatorsCountsOffset; + assembly { + _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) + _stuckValidatorsCountsOffset := add(calldataload(36), 36) // signature_bytes4 + arg2_bytes calldata offset + 32 (length slot)) + } for (uint256 i; i < nodeOperatorsCount; ) { /// @solidity memory-safe-assembly assembly { - let _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) - let _stuckValidatorsCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot) nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) validatorsCount := shr(128, calldataload(add(_stuckValidatorsCountsOffset, mul(i, 16)))) i := add(i, 1) From cc3761a7c465d11d27281b62eafbe90a4d5d5e96 Mon Sep 17 00:00:00 2001 From: Artyom Veremeenko Date: Fri, 17 Feb 2023 17:57:16 +0400 Subject: [PATCH 080/199] fix and multiple improvements to OracleReportSanityChecker - make checks for extraDataListItems and nodeOperatorsPerExtraDataItem depend on two separate limits - add check for max (due packing) value of a limit in setters - refactor order of the limits - add 2 simple tests for the setters --- .../OracleReportSanityChecker.sol | 89 +++++++-- lib/abi/OracleReportSanityChecker.json | 2 +- test/0.4.24/lido-handle-oracle-report.test.js | 170 +++++------------- .../oracle-report-sanity-checker.test.js | 54 ++++-- .../oracle/accounting-oracle-deploy.test.js | 4 +- ...counting-oracle-submit-report-data.test.js | 4 +- .../validators-exit-bus-oracle-deploy.test.js | 4 +- test/helpers/config.js | 2 + 8 files changed, 162 insertions(+), 167 deletions(-) diff --git a/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol b/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol index ce741481b..3e45ab425 100644 --- a/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol +++ b/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol @@ -48,6 +48,17 @@ struct LimitsList { /// @dev Represented in the Basis Points (100% == 10_000) uint256 shareRateDeviationBPLimit; + /// @notice The max number of exit requests allowed in report to ValidatorsExitBusOracle + uint256 maxValidatorExitRequestsPerReport; + + /// @notice The max number of data list items reported to accounting oracle in extra data + /// @dev Must fit into uint16 (<= 65_535) + uint256 maxAccountingExtraDataListItemsCount; + + /// @notice The max number of node operators reported per extra data list item + /// @dev Must fit into uint16 (<= 65_535) + uint256 maxNodeOperatorsPerExtraDataItemCount; + /// @notice The min time required to be passed from the creation of the request to be /// finalized till the time of the oracle report uint256 requestTimestampMargin; @@ -56,12 +67,6 @@ struct LimitsList { /// @dev uses 1e9 precision, e.g.: 1e6 - 0.1%; 1e9 - 100%, see `setMaxPositiveTokenRebase()` uint256 maxPositiveTokenRebase; - /// @notice The max number of exit requests allowed in report to ValidatorsExitBusOracle - uint256 maxValidatorExitRequestsPerReport; - - /// @notice The max number of data list items reported to accounting oracle in extra data - /// @dev Must fit into uint16 (<= 65_535) - uint256 maxAccountingExtraDataListItemsCount; } /// @dev The packed version of the LimitsList struct to be effectively persisted in storage @@ -72,6 +77,7 @@ struct LimitsListPacked { uint16 shareRateDeviationBPLimit; uint16 maxValidatorExitRequestsPerReport; uint16 maxAccountingExtraDataListItemsCount; + uint16 maxNodeOperatorsPerExtraDataItemCount; uint64 requestTimestampMargin; uint64 maxPositiveTokenRebase; } @@ -98,11 +104,13 @@ contract OracleReportSanityChecker is AccessControlEnumerable { keccak256("SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE"); bytes32 public constant MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE = keccak256("MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE"); + bytes32 public constant MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE = + keccak256("MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE"); + bytes32 public constant MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE = + keccak256("MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE"); bytes32 public constant REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE = keccak256("REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE"); bytes32 public constant MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE = keccak256("MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE"); - bytes32 public constant MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE = - keccak256("MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE"); uint256 private constant DEFAULT_TIME_ELAPSED = 1 hours; uint256 private constant DEFAULT_CL_BALANCE = 1 gwei; @@ -120,6 +128,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { address[] shareRateDeviationLimitManagers; address[] maxValidatorExitRequestsPerReportManagers; address[] maxAccountingExtraDataListItemsCountManagers; + address[] maxNodeOperatorsPerExtraDataItemCountManagers; address[] requestTimestampMarginManagers; address[] maxPositiveTokenRebaseManagers; } @@ -144,13 +153,15 @@ contract OracleReportSanityChecker is AccessControlEnumerable { _grantRole(ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE, _managersRoster.oneOffCLBalanceDecreaseLimitManagers); _grantRole(ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE, _managersRoster.annualBalanceIncreaseLimitManagers); - _grantRole(SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE, _managersRoster.shareRateDeviationLimitManagers); - _grantRole(REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE, _managersRoster.requestTimestampMarginManagers); _grantRole(MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE, _managersRoster.maxPositiveTokenRebaseManagers); _grantRole(MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE, _managersRoster.maxValidatorExitRequestsPerReportManagers); _grantRole(MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE, _managersRoster.maxAccountingExtraDataListItemsCountManagers); + _grantRole(MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE, + _managersRoster.maxNodeOperatorsPerExtraDataItemCountManagers); + _grantRole(SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE, _managersRoster.shareRateDeviationLimitManagers); + _grantRole(REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE, _managersRoster.requestTimestampMarginManagers); } /// @notice returns the address of the LidoLocator @@ -202,6 +213,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(CHURN_VALIDATORS_PER_DAY_LIMIT_MANGER_ROLE) { + _checkLimitValue(_churnValidatorsPerDayLimit, type(uint16).max); LimitsList memory limitsList = _limits.unpack(); limitsList.churnValidatorsPerDayLimit = _churnValidatorsPerDayLimit; _updateLimits(limitsList); @@ -213,6 +225,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE) { + _checkLimitValue(_oneOffCLBalanceDecreaseBPLimit, type(uint16).max); LimitsList memory limitsList = _limits.unpack(); limitsList.oneOffCLBalanceDecreaseBPLimit = _oneOffCLBalanceDecreaseBPLimit; _updateLimits(limitsList); @@ -224,6 +237,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE) { + _checkLimitValue(_annualBalanceIncreaseBPLimit, type(uint16).max); LimitsList memory limitsList = _limits.unpack(); limitsList.annualBalanceIncreaseBPLimit = _annualBalanceIncreaseBPLimit; _updateLimits(limitsList); @@ -235,6 +249,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE) { + _checkLimitValue(_shareRateDeviationBPLimit, type(uint16).max); LimitsList memory limitsList = _limits.unpack(); limitsList.shareRateDeviationBPLimit = _shareRateDeviationBPLimit; _updateLimits(limitsList); @@ -246,6 +261,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE) { + _checkLimitValue(_maxValidatorExitRequestsPerReport, type(uint16).max); LimitsList memory limitsList = _limits.unpack(); limitsList.maxValidatorExitRequestsPerReport = _maxValidatorExitRequestsPerReport; _updateLimits(limitsList); @@ -257,6 +273,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE) { + _checkLimitValue(_requestTimestampMargin, type(uint64).max); LimitsList memory limitsList = _limits.unpack(); limitsList.requestTimestampMargin = _requestTimestampMargin; _updateLimits(limitsList); @@ -273,6 +290,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE) { + _checkLimitValue(_maxPositiveTokenRebase, type(uint64).max); LimitsList memory limitsList = _limits.unpack(); limitsList.maxPositiveTokenRebase = _maxPositiveTokenRebase; _updateLimits(limitsList); @@ -284,11 +302,24 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE) { + _checkLimitValue(_maxAccountingExtraDataListItemsCount, type(uint16).max); LimitsList memory limitsList = _limits.unpack(); limitsList.maxAccountingExtraDataListItemsCount = _maxAccountingExtraDataListItemsCount; _updateLimits(limitsList); } + /// @notice Sets the new value for the max maxNodeOperatorsPerExtraDataItemCount + /// @param _maxNodeOperatorsPerExtraDataItemCount new maxNodeOperatorsPerExtraDataItemCount value + function setMaxNodeOperatorsPerExtraDataItemCount(uint256 _maxNodeOperatorsPerExtraDataItemCount) + external + onlyRole(MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE) + { + _checkLimitValue(_maxNodeOperatorsPerExtraDataItemCount, type(uint16).max); + LimitsList memory limitsList = _limits.unpack(); + limitsList.maxNodeOperatorsPerExtraDataItemCount = _maxNodeOperatorsPerExtraDataItemCount; + _updateLimits(limitsList); + } + /// @notice Returns the allowed ETH amount that might be taken from the withdrawal vault and EL /// rewards vault during Lido's oracle report processing /// @param _preTotalPooledEther total amount of ETH controlled by the protocol @@ -404,7 +435,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external view { - uint256 limit = _limits.unpack().maxAccountingExtraDataListItemsCount; + uint256 limit = _limits.unpack().maxNodeOperatorsPerExtraDataItemCount; if (_nodeOperatorsCount > limit) { revert TooManyNodeOpsPerExtraDataItem(_itemIndex, _nodeOperatorsCount); } @@ -577,41 +608,61 @@ contract OracleReportSanityChecker is AccessControlEnumerable { function _updateLimits(LimitsList memory _newLimitsList) internal { LimitsList memory _oldLimitsList = _limits.unpack(); if (_oldLimitsList.churnValidatorsPerDayLimit != _newLimitsList.churnValidatorsPerDayLimit) { + _checkLimitValue(_newLimitsList.churnValidatorsPerDayLimit, type(uint16).max); emit ChurnValidatorsPerDayLimitSet(_newLimitsList.churnValidatorsPerDayLimit); } if (_oldLimitsList.oneOffCLBalanceDecreaseBPLimit != _newLimitsList.oneOffCLBalanceDecreaseBPLimit) { + _checkLimitValue(_newLimitsList.oneOffCLBalanceDecreaseBPLimit, type(uint16).max); emit OneOffCLBalanceDecreaseBPLimitSet(_newLimitsList.oneOffCLBalanceDecreaseBPLimit); } if (_oldLimitsList.annualBalanceIncreaseBPLimit != _newLimitsList.annualBalanceIncreaseBPLimit) { + _checkLimitValue(_newLimitsList.annualBalanceIncreaseBPLimit, type(uint16).max); emit AnnualBalanceIncreaseBPLimitSet(_newLimitsList.annualBalanceIncreaseBPLimit); } if (_oldLimitsList.shareRateDeviationBPLimit != _newLimitsList.shareRateDeviationBPLimit) { + _checkLimitValue(_newLimitsList.shareRateDeviationBPLimit, type(uint16).max); emit ShareRateDeviationBPLimitSet(_newLimitsList.shareRateDeviationBPLimit); } - if (_oldLimitsList.requestTimestampMargin != _newLimitsList.requestTimestampMargin) { - emit RequestTimestampMarginSet(_newLimitsList.requestTimestampMargin); - } - if (_oldLimitsList.maxPositiveTokenRebase != _newLimitsList.maxPositiveTokenRebase) { - emit MaxPositiveTokenRebaseSet(_newLimitsList.maxPositiveTokenRebase); - } if (_oldLimitsList.maxValidatorExitRequestsPerReport != _newLimitsList.maxValidatorExitRequestsPerReport) { + _checkLimitValue(_newLimitsList.maxValidatorExitRequestsPerReport, type(uint16).max); emit MaxValidatorExitRequestsPerReportSet(_newLimitsList.maxValidatorExitRequestsPerReport); } if (_oldLimitsList.maxAccountingExtraDataListItemsCount != _newLimitsList.maxAccountingExtraDataListItemsCount) { + _checkLimitValue(_newLimitsList.maxAccountingExtraDataListItemsCount, type(uint16).max); emit MaxAccountingExtraDataListItemsCountSet(_newLimitsList.maxAccountingExtraDataListItemsCount); } + if (_oldLimitsList.maxNodeOperatorsPerExtraDataItemCount != _newLimitsList.maxNodeOperatorsPerExtraDataItemCount) { + _checkLimitValue(_newLimitsList.maxNodeOperatorsPerExtraDataItemCount, type(uint16).max); + emit MaxNodeOperatorsPerExtraDataItemCountSet(_newLimitsList.maxNodeOperatorsPerExtraDataItemCount); + } + if (_oldLimitsList.requestTimestampMargin != _newLimitsList.requestTimestampMargin) { + _checkLimitValue(_newLimitsList.requestTimestampMargin, type(uint64).max); + emit RequestTimestampMarginSet(_newLimitsList.requestTimestampMargin); + } + if (_oldLimitsList.maxPositiveTokenRebase != _newLimitsList.maxPositiveTokenRebase) { + _checkLimitValue(_newLimitsList.maxPositiveTokenRebase, type(uint64).max); + emit MaxPositiveTokenRebaseSet(_newLimitsList.maxPositiveTokenRebase); + } _limits = _newLimitsList.pack(); } + function _checkLimitValue(uint256 _value, uint256 _maxAllowedValue) internal pure { + if (_value >= _maxAllowedValue) { + revert IncorrectLimitValue(_value, _maxAllowedValue); + } + } + event ChurnValidatorsPerDayLimitSet(uint256 churnValidatorsPerDayLimit); event OneOffCLBalanceDecreaseBPLimitSet(uint256 oneOffCLBalanceDecreaseBPLimit); event AnnualBalanceIncreaseBPLimitSet(uint256 annualBalanceIncreaseBPLimit); event ShareRateDeviationBPLimitSet(uint256 shareRateDeviationBPLimit); - event RequestTimestampMarginSet(uint256 requestTimestampMargin); event MaxPositiveTokenRebaseSet(uint256 maxPositiveTokenRebase); event MaxValidatorExitRequestsPerReportSet(uint256 maxValidatorExitRequestsPerReport); event MaxAccountingExtraDataListItemsCountSet(uint256 maxAccountingExtraDataListItemsCount); + event MaxNodeOperatorsPerExtraDataItemCountSet(uint256 maxNodeOperatorsPerExtraDataItemCount); + event RequestTimestampMarginSet(uint256 requestTimestampMargin); + error IncorrectLimitValue(uint256 value, uint256 maxAllowedValue); error IncorrectWithdrawalsVaultBalance(uint256 actualWithdrawalVaultBalance); error IncorrectELRewardsVaultBalance(uint256 actualELRewardsVaultBalance); error IncorrectCLBalanceDecrease(uint256 oneOffCLBalanceDecreaseBP); @@ -636,6 +687,7 @@ library LimitsListPacker { res.maxPositiveTokenRebase = SafeCast.toUint64(_limitsList.maxPositiveTokenRebase); res.maxValidatorExitRequestsPerReport = SafeCast.toUint16(_limitsList.maxValidatorExitRequestsPerReport); res.maxAccountingExtraDataListItemsCount = SafeCast.toUint16(_limitsList.maxAccountingExtraDataListItemsCount); + res.maxNodeOperatorsPerExtraDataItemCount = SafeCast.toUint16(_limitsList.maxNodeOperatorsPerExtraDataItemCount); } function _toBasisPoints(uint256 _value) private pure returns (uint16) { @@ -654,5 +706,6 @@ library LimitsListUnpacker { res.maxPositiveTokenRebase = _limitsList.maxPositiveTokenRebase; res.maxValidatorExitRequestsPerReport = _limitsList.maxValidatorExitRequestsPerReport; res.maxAccountingExtraDataListItemsCount = _limitsList.maxAccountingExtraDataListItemsCount; + res.maxNodeOperatorsPerExtraDataItemCount = _limitsList.maxNodeOperatorsPerExtraDataItemCount; } } diff --git a/lib/abi/OracleReportSanityChecker.json b/lib/abi/OracleReportSanityChecker.json index 0b666eab2..0f65d65db 100644 --- a/lib/abi/OracleReportSanityChecker.json +++ b/lib/abi/OracleReportSanityChecker.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_lidoLocator","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"shareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"}],"internalType":"struct LimitsList","name":"_limitsList","type":"tuple"},{"components":[{"internalType":"address[]","name":"allLimitsManagers","type":"address[]"},{"internalType":"address[]","name":"churnValidatorsPerDayLimitManagers","type":"address[]"},{"internalType":"address[]","name":"oneOffCLBalanceDecreaseLimitManagers","type":"address[]"},{"internalType":"address[]","name":"annualBalanceIncreaseLimitManagers","type":"address[]"},{"internalType":"address[]","name":"shareRateDeviationLimitManagers","type":"address[]"},{"internalType":"address[]","name":"maxValidatorExitRequestsPerReportManagers","type":"address[]"},{"internalType":"address[]","name":"maxAccountingExtraDataListItemsCountManagers","type":"address[]"},{"internalType":"address[]","name":"requestTimestampMarginManagers","type":"address[]"},{"internalType":"address[]","name":"maxPositiveTokenRebaseManagers","type":"address[]"}],"internalType":"struct OracleReportSanityChecker.ManagersRoster","name":"_managersRoster","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"limitPerDay","type":"uint256"},{"internalType":"uint256","name":"exitedPerDay","type":"uint256"}],"name":"ExitedValidatorsLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"churnLimit","type":"uint256"}],"name":"IncorrectAppearedValidators","type":"error"},{"inputs":[{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBP","type":"uint256"}],"name":"IncorrectCLBalanceDecrease","type":"error"},{"inputs":[{"internalType":"uint256","name":"annualBalanceDiff","type":"uint256"}],"name":"IncorrectCLBalanceIncrease","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualELRewardsVaultBalance","type":"uint256"}],"name":"IncorrectELRewardsVaultBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"churnLimit","type":"uint256"}],"name":"IncorrectExitedValidators","type":"error"},{"inputs":[{"internalType":"uint256","name":"finalizationShareDeviation","type":"uint256"}],"name":"IncorrectFinalizationShareRate","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxRequestsCount","type":"uint256"}],"name":"IncorrectNumberOfExitRequestsPerReport","type":"error"},{"inputs":[{"internalType":"uint256","name":"requestCreationBlock","type":"uint256"}],"name":"IncorrectRequestFinalization","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualWithdrawalVaultBalance","type":"uint256"}],"name":"IncorrectWithdrawalsVaultBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxItemsCount","type":"uint256"},{"internalType":"uint256","name":"receivedItemsCount","type":"uint256"}],"name":"MaxAccountingExtraDataItemsCountExceeded","type":"error"},{"inputs":[],"name":"TooHighTokenRebaseLimit","type":"error"},{"inputs":[],"name":"TooLowTokenRebaseLimit","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"},{"internalType":"uint256","name":"nodeOpsCount","type":"uint256"}],"name":"TooManyNodeOpsPerExtraDataItem","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"}],"name":"AnnualBalanceIncreaseBPLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"}],"name":"ChurnValidatorsPerDayLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"}],"name":"MaxAccountingExtraDataListItemsCountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"name":"MaxPositiveTokenRebaseSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"}],"name":"MaxValidatorExitRequestsPerReportSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"}],"name":"OneOffCLBalanceDecreaseBPLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"}],"name":"RequestTimestampMarginSet","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":"shareRateDeviationBPLimit","type":"uint256"}],"name":"ShareRateDeviationBPLimitSet","type":"event"},{"inputs":[],"name":"ALL_LIMITS_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CHURN_VALIDATORS_PER_DAY_LIMIT_MANGER_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":"MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_extraDataListItemsCount","type":"uint256"}],"name":"checkAccountingExtraDataListItemsCount","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timeElapsed","type":"uint256"},{"internalType":"uint256","name":"_preCLBalance","type":"uint256"},{"internalType":"uint256","name":"_postCLBalance","type":"uint256"},{"internalType":"uint256","name":"_withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_preCLValidators","type":"uint256"},{"internalType":"uint256","name":"_postCLValidators","type":"uint256"}],"name":"checkAccountingOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_exitRequestsCount","type":"uint256"}],"name":"checkExitBusOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_exitedValidatorsCount","type":"uint256"}],"name":"checkExitedValidatorsRatePerDay","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_itemIndex","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorsCount","type":"uint256"}],"name":"checkNodeOperatorsPerExtraDataItemCount","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_postTotalPooledEther","type":"uint256"},{"internalType":"uint256","name":"_postTotalShares","type":"uint256"},{"internalType":"uint256","name":"_etherLockedOnWithdrawalQueue","type":"uint256"},{"internalType":"uint256","name":"_sharesBurntFromWithdrawalQueue","type":"uint256"},{"internalType":"uint256","name":"_simulatedShareRate","type":"uint256"}],"name":"checkSimulatedShareRate","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lastFinalizableRequestId","type":"uint256"},{"internalType":"uint256","name":"_reportTimestamp","type":"uint256"}],"name":"checkWithdrawalQueueOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLidoLocator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxPositiveTokenRebase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOracleReportLimits","outputs":[{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"shareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"}],"internalType":"struct LimitsList","name":"","type":"tuple"}],"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":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","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":"uint256","name":"_annualBalanceIncreaseBPLimit","type":"uint256"}],"name":"setAnnualBalanceIncreaseBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_churnValidatorsPerDayLimit","type":"uint256"}],"name":"setChurnValidatorsPerDayLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxAccountingExtraDataListItemsCount","type":"uint256"}],"name":"setMaxAccountingExtraDataListItemsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxValidatorExitRequestsPerReport","type":"uint256"}],"name":"setMaxExitRequestsPerOracleReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPositiveTokenRebase","type":"uint256"}],"name":"setMaxPositiveTokenRebase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_oneOffCLBalanceDecreaseBPLimit","type":"uint256"}],"name":"setOneOffCLBalanceDecreaseBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"shareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"}],"internalType":"struct LimitsList","name":"_limitsList","type":"tuple"}],"name":"setOracleReportLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestTimestampMargin","type":"uint256"}],"name":"setRequestTimestampMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shareRateDeviationBPLimit","type":"uint256"}],"name":"setShareRateDeviationBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_preTotalPooledEther","type":"uint256"},{"internalType":"uint256","name":"_preTotalShares","type":"uint256"},{"internalType":"uint256","name":"_preCLBalance","type":"uint256"},{"internalType":"uint256","name":"_postCLBalance","type":"uint256"},{"internalType":"uint256","name":"_withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_etherToLockForWithdrawals","type":"uint256"}],"name":"smoothenTokenRebase","outputs":[{"internalType":"uint256","name":"withdrawals","type":"uint256"},{"internalType":"uint256","name":"elRewards","type":"uint256"},{"internalType":"uint256","name":"sharesToBurnLimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_lidoLocator","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"shareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"},{"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"internalType":"struct LimitsList","name":"_limitsList","type":"tuple"},{"components":[{"internalType":"address[]","name":"allLimitsManagers","type":"address[]"},{"internalType":"address[]","name":"churnValidatorsPerDayLimitManagers","type":"address[]"},{"internalType":"address[]","name":"oneOffCLBalanceDecreaseLimitManagers","type":"address[]"},{"internalType":"address[]","name":"annualBalanceIncreaseLimitManagers","type":"address[]"},{"internalType":"address[]","name":"shareRateDeviationLimitManagers","type":"address[]"},{"internalType":"address[]","name":"maxValidatorExitRequestsPerReportManagers","type":"address[]"},{"internalType":"address[]","name":"maxAccountingExtraDataListItemsCountManagers","type":"address[]"},{"internalType":"address[]","name":"maxNodeOperatorsPerExtraDataItemCountManagers","type":"address[]"},{"internalType":"address[]","name":"requestTimestampMarginManagers","type":"address[]"},{"internalType":"address[]","name":"maxPositiveTokenRebaseManagers","type":"address[]"}],"internalType":"struct OracleReportSanityChecker.ManagersRoster","name":"_managersRoster","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"limitPerDay","type":"uint256"},{"internalType":"uint256","name":"exitedPerDay","type":"uint256"}],"name":"ExitedValidatorsLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"churnLimit","type":"uint256"}],"name":"IncorrectAppearedValidators","type":"error"},{"inputs":[{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBP","type":"uint256"}],"name":"IncorrectCLBalanceDecrease","type":"error"},{"inputs":[{"internalType":"uint256","name":"annualBalanceDiff","type":"uint256"}],"name":"IncorrectCLBalanceIncrease","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualELRewardsVaultBalance","type":"uint256"}],"name":"IncorrectELRewardsVaultBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"churnLimit","type":"uint256"}],"name":"IncorrectExitedValidators","type":"error"},{"inputs":[{"internalType":"uint256","name":"finalizationShareDeviation","type":"uint256"}],"name":"IncorrectFinalizationShareRate","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"maxAllowedValue","type":"uint256"}],"name":"IncorrectLimitValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxRequestsCount","type":"uint256"}],"name":"IncorrectNumberOfExitRequestsPerReport","type":"error"},{"inputs":[{"internalType":"uint256","name":"requestCreationBlock","type":"uint256"}],"name":"IncorrectRequestFinalization","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualWithdrawalVaultBalance","type":"uint256"}],"name":"IncorrectWithdrawalsVaultBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxItemsCount","type":"uint256"},{"internalType":"uint256","name":"receivedItemsCount","type":"uint256"}],"name":"MaxAccountingExtraDataItemsCountExceeded","type":"error"},{"inputs":[],"name":"TooHighTokenRebaseLimit","type":"error"},{"inputs":[],"name":"TooLowTokenRebaseLimit","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"},{"internalType":"uint256","name":"nodeOpsCount","type":"uint256"}],"name":"TooManyNodeOpsPerExtraDataItem","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"}],"name":"AnnualBalanceIncreaseBPLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"}],"name":"ChurnValidatorsPerDayLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"}],"name":"MaxAccountingExtraDataListItemsCountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"}],"name":"MaxNodeOperatorsPerExtraDataItemCountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"name":"MaxPositiveTokenRebaseSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"}],"name":"MaxValidatorExitRequestsPerReportSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"}],"name":"OneOffCLBalanceDecreaseBPLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"}],"name":"RequestTimestampMarginSet","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":"shareRateDeviationBPLimit","type":"uint256"}],"name":"ShareRateDeviationBPLimitSet","type":"event"},{"inputs":[],"name":"ALL_LIMITS_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CHURN_VALIDATORS_PER_DAY_LIMIT_MANGER_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":"MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_extraDataListItemsCount","type":"uint256"}],"name":"checkAccountingExtraDataListItemsCount","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timeElapsed","type":"uint256"},{"internalType":"uint256","name":"_preCLBalance","type":"uint256"},{"internalType":"uint256","name":"_postCLBalance","type":"uint256"},{"internalType":"uint256","name":"_withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_preCLValidators","type":"uint256"},{"internalType":"uint256","name":"_postCLValidators","type":"uint256"}],"name":"checkAccountingOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_exitRequestsCount","type":"uint256"}],"name":"checkExitBusOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_exitedValidatorsCount","type":"uint256"}],"name":"checkExitedValidatorsRatePerDay","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_itemIndex","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorsCount","type":"uint256"}],"name":"checkNodeOperatorsPerExtraDataItemCount","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_postTotalPooledEther","type":"uint256"},{"internalType":"uint256","name":"_postTotalShares","type":"uint256"},{"internalType":"uint256","name":"_etherLockedOnWithdrawalQueue","type":"uint256"},{"internalType":"uint256","name":"_sharesBurntFromWithdrawalQueue","type":"uint256"},{"internalType":"uint256","name":"_simulatedShareRate","type":"uint256"}],"name":"checkSimulatedShareRate","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lastFinalizableRequestId","type":"uint256"},{"internalType":"uint256","name":"_reportTimestamp","type":"uint256"}],"name":"checkWithdrawalQueueOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLidoLocator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxPositiveTokenRebase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOracleReportLimits","outputs":[{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"shareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"},{"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"internalType":"struct LimitsList","name":"","type":"tuple"}],"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":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","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":"uint256","name":"_annualBalanceIncreaseBPLimit","type":"uint256"}],"name":"setAnnualBalanceIncreaseBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_churnValidatorsPerDayLimit","type":"uint256"}],"name":"setChurnValidatorsPerDayLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxAccountingExtraDataListItemsCount","type":"uint256"}],"name":"setMaxAccountingExtraDataListItemsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxValidatorExitRequestsPerReport","type":"uint256"}],"name":"setMaxExitRequestsPerOracleReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxNodeOperatorsPerExtraDataItemCount","type":"uint256"}],"name":"setMaxNodeOperatorsPerExtraDataItemCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPositiveTokenRebase","type":"uint256"}],"name":"setMaxPositiveTokenRebase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_oneOffCLBalanceDecreaseBPLimit","type":"uint256"}],"name":"setOneOffCLBalanceDecreaseBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"shareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"},{"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"internalType":"struct LimitsList","name":"_limitsList","type":"tuple"}],"name":"setOracleReportLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestTimestampMargin","type":"uint256"}],"name":"setRequestTimestampMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shareRateDeviationBPLimit","type":"uint256"}],"name":"setShareRateDeviationBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_preTotalPooledEther","type":"uint256"},{"internalType":"uint256","name":"_preTotalShares","type":"uint256"},{"internalType":"uint256","name":"_preCLBalance","type":"uint256"},{"internalType":"uint256","name":"_postCLBalance","type":"uint256"},{"internalType":"uint256","name":"_withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_etherToLockForWithdrawals","type":"uint256"}],"name":"smoothenTokenRebase","outputs":[{"internalType":"uint256","name":"withdrawals","type":"uint256"},{"internalType":"uint256","name":"elRewards","type":"uint256"},{"internalType":"uint256","name":"sharesToBurnLimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/test/0.4.24/lido-handle-oracle-report.test.js b/test/0.4.24/lido-handle-oracle-report.test.js index a94fb0913..e53bcac6f 100644 --- a/test/0.4.24/lido-handle-oracle-report.test.js +++ b/test/0.4.24/lido-handle-oracle-report.test.js @@ -8,6 +8,17 @@ const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') const ONE_YEAR = 3600 * 24 * 365 const ONE_DAY = 3600 * 24 +const ORACLE_REPORT_LIMITS_BOILERPLATE = { + churnValidatorsPerDayLimit: 255, + oneOffCLBalanceDecreaseBPLimit: 100, + annualBalanceIncreaseBPLimit: 10000, + shareRateDeviationBPLimit: 10000, + maxValidatorExitRequestsPerReport: 10000, + maxAccountingExtraDataListItemsCount: 10000, + maxNodeOperatorsPerExtraDataItemCount: 10000, + requestTimestampMargin: 0, + maxPositiveTokenRebase: 1000000000, +} contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, anotherStranger, depositor, operator]) => { let deployed, snapshot, lido, treasury, voting, oracle @@ -242,16 +253,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('does not revert on new total balance decrease under the limit', async () => { // set oneOffCLBalanceDecreaseBPLimit = 1% await oracleReportSanityChecker.setOracleReportLimits( - { - churnValidatorsPerDayLimit: 255, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, - maxPositiveTokenRebase: 1000000000, - maxAccountingExtraDataListItemsCount: 10000 - }, + ORACLE_REPORT_LIMITS_BOILERPLATE, { from: voting } ) @@ -279,16 +281,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('reverts on new total balance decrease over the limit', async () => { // set oneOffCLBalanceDecreaseBPLimit = 1% await oracleReportSanityChecker.setOracleReportLimits( - { - churnValidatorsPerDayLimit: 255, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, - maxPositiveTokenRebase: 1000000000, - maxAccountingExtraDataListItemsCount: 10000 - }, + ORACLE_REPORT_LIMITS_BOILERPLATE, { from: voting } ) @@ -309,16 +302,9 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('does not revert on new total balance increase under the limit', async () => { // set annualBalanceIncreaseBPLimit = 1% - await oracleReportSanityChecker.setOracleReportLimits( - { - churnValidatorsPerDayLimit: 255, - oneOffCLBalanceDecreaseBPLimit: 100, + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, annualBalanceIncreaseBPLimit: 100, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, - maxPositiveTokenRebase: 1000000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting } ) @@ -346,16 +332,9 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('reverts on new total balance increase over the limit', async () => { // set annualBalanceIncreaseBPLimit = 1% - await oracleReportSanityChecker.setOracleReportLimits( - { - churnValidatorsPerDayLimit: 255, - oneOffCLBalanceDecreaseBPLimit: 100, + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, annualBalanceIncreaseBPLimit: 100, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, - maxPositiveTokenRebase: 1000000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting } ) @@ -378,16 +357,10 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('does not revert on validators reported under limit', async () => { await lido.submit(ZERO_ADDRESS, { from: stranger, value: ETH(3100), gasPrice: 1 }) await lido.deposit(100, 1, '0x', { from: depositor }) - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, annualBalanceIncreaseBPLimit: 100, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, - maxPositiveTokenRebase: 1000000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting, gasPrice: 1 } ) @@ -399,16 +372,10 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('reverts on validators reported when over limit', async () => { await lido.submit(ZERO_ADDRESS, { from: stranger, value: ETH(3200), gasPrice: 1 }) await lido.deposit(101, 1, '0x', { from: depositor }) - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, annualBalanceIncreaseBPLimit: 100, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, - maxPositiveTokenRebase: 1000000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting, gasPrice: 1 } ) @@ -433,16 +400,9 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another }) it('does not smooth if report in limits', async () => { - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, - maxPositiveTokenRebase: 10000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting, gasPrice: 1 } ) @@ -451,16 +411,9 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another }) it('does not smooth if cl balance report over limit', async () => { - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, - maxPositiveTokenRebase: 1000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting, gasPrice: 1 } ) @@ -478,16 +431,10 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('does not smooth withdrawals if report in limits', async () => { await setBalance(withdrawalVault, ETH(1)) - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, - maxPositiveTokenRebase: 10000000, - maxAccountingExtraDataListItemsCount: 10000 + annualBalanceIncreaseBPLimit: 100, }, { from: voting, gasPrice: 1 } ) @@ -506,16 +453,10 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('smooths withdrawals if report out of limit', async () => { await setBalance(withdrawalVault, ETH(1.1)) - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, maxPositiveTokenRebase: 10000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting, gasPrice: 1 } ) @@ -535,16 +476,10 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('does not smooth el rewards if report in limit without lido fee', async () => { await setBalance(elRewardsVault, ETH(1)) - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, maxPositiveTokenRebase: 10000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting, gasPrice: 1 } ) @@ -565,16 +500,10 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('does not smooth el rewards if report in limit without lido fee', async () => { await setBalance(elRewardsVault, ETH(1.5)) - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, maxPositiveTokenRebase: 10000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting, gasPrice: 1 } ) @@ -594,16 +523,10 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('smooths el rewards if report out of limit without lido fee', async () => { await setBalance(elRewardsVault, ETH(1.1)) - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, maxPositiveTokenRebase: 10000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting, gasPrice: 1 } ) @@ -623,16 +546,9 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('does not smooth el rewards if report in limit', async () => { await setBalance(elRewardsVault, ETH(1)) - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, - maxPositiveTokenRebase: 10000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting, gasPrice: 1 } ) @@ -653,16 +569,10 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another it('smooths el rewards if report out of limit', async () => { await setBalance(elRewardsVault, ETH(1.1)) - await oracleReportSanityChecker.setOracleReportLimits( - { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, churnValidatorsPerDayLimit: 100, - oneOffCLBalanceDecreaseBPLimit: 100, - annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, - maxValidatorExitRequestsPerReport: 10000, - requestTimestampMargin: 0, maxPositiveTokenRebase: 10000000, - maxAccountingExtraDataListItemsCount: 10000 }, { from: voting, gasPrice: 1 } ) diff --git a/test/0.8.9/oracle-report-sanity-checker.test.js b/test/0.8.9/oracle-report-sanity-checker.test.js index aec6dab7d..2baeb068f 100644 --- a/test/0.8.9/oracle-report-sanity-checker.test.js +++ b/test/0.8.9/oracle-report-sanity-checker.test.js @@ -27,20 +27,22 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa oneOffCLBalanceDecreaseLimitManagers: accounts.slice(4, 6), annualBalanceIncreaseLimitManagers: accounts.slice(6, 8), shareRateDeviationLimitManagers: accounts.slice(8, 10), - requestCreationBlockMarginManagers: accounts.slice(10, 12), - maxPositiveTokenRebaseManagers: accounts.slice(12, 14), - maxValidatorExitRequestsPerReportManagers: accounts.slice(14, 16), - maxAccountingExtraDataListItemsCountManagers: accounts.slice(16, 18), + maxValidatorExitRequestsPerReportManagers: accounts.slice(10, 12), + maxAccountingExtraDataListItemsCountManagers: accounts.slice(12, 14), + maxNodeOperatorsPerExtraDataItemCountManagers: accounts.slice(14, 16), + requestTimestampMarginManagers: accounts.slice(16, 18), + maxPositiveTokenRebaseManagers: accounts.slice(18, 20), } const defaultLimitsList = { churnValidatorsPerDayLimit: 55, oneOffCLBalanceDecreaseBPLimit: 5_00, // 5% annualBalanceIncreaseBPLimit: 10_00, // 10% shareRateDeviationBPLimit: 2_50, // 2.5% - requestTimestampMargin: 128, - maxPositiveTokenRebase: 5_000_000, // 0.05% maxValidatorExitRequestsPerReport: 2000, maxAccountingExtraDataListItemsCount: 15, + maxNodeOperatorsPerExtraDataItemCount: 16, + requestTimestampMargin: 128, + maxPositiveTokenRebase: 5_000_000, // 0.05% } const correctLidoOracleReport = { timeElapsed: 24 * 60 * 60, @@ -80,20 +82,22 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa oneOffCLBalanceDecreaseBPLimit: 10_00, annualBalanceIncreaseBPLimit: 15_00, shareRateDeviationBPLimit: 1_50, // 1.5% - requestTimestampMargin: 2048, - maxPositiveTokenRebase: 10_000_000, maxValidatorExitRequestsPerReport: 3000, maxAccountingExtraDataListItemsCount: 15 + 1, + maxNodeOperatorsPerExtraDataItemCount: 16 + 1, + requestTimestampMargin: 2048, + maxPositiveTokenRebase: 10_000_000, } const limitsBefore = await oracleReportSanityChecker.getOracleReportLimits() assert.notEquals(limitsBefore.churnValidatorsPerDayLimit, newLimitsList.churnValidatorsPerDayLimit) assert.notEquals(limitsBefore.oneOffCLBalanceDecreaseBPLimit, newLimitsList.oneOffCLBalanceDecreaseBPLimit) assert.notEquals(limitsBefore.annualBalanceIncreaseBPLimit, newLimitsList.annualBalanceIncreaseBPLimit) assert.notEquals(limitsBefore.shareRateDeviationBPLimit, newLimitsList.shareRateDeviationBPLimit) - assert.notEquals(limitsBefore.requestTimestampMargin, newLimitsList.requestTimestampMargin) - assert.notEquals(limitsBefore.maxPositiveTokenRebase, newLimitsList.maxPositiveTokenRebase) assert.notEquals(limitsBefore.maxValidatorExitRequestsPerReport, newLimitsList.maxValidatorExitRequestsPerReport) assert.notEquals(limitsBefore.maxAccountingExtraDataListItemsCount, newLimitsList.maxAccountingExtraDataListItemsCount) + assert.notEquals(limitsBefore.maxNodeOperatorsPerExtraDataItemCount, newLimitsList.maxNodeOperatorsPerExtraDataItemCount) + assert.notEquals(limitsBefore.requestTimestampMargin, newLimitsList.requestTimestampMargin) + assert.notEquals(limitsBefore.maxPositiveTokenRebase, newLimitsList.maxPositiveTokenRebase) await oracleReportSanityChecker.setOracleReportLimits(Object.values(newLimitsList), { from: managersRoster.allLimitsManagers[0] @@ -104,10 +108,11 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa assert.equals(limitsAfter.oneOffCLBalanceDecreaseBPLimit, newLimitsList.oneOffCLBalanceDecreaseBPLimit) assert.equals(limitsAfter.annualBalanceIncreaseBPLimit, newLimitsList.annualBalanceIncreaseBPLimit) assert.equals(limitsAfter.shareRateDeviationBPLimit, newLimitsList.shareRateDeviationBPLimit) - assert.equals(limitsAfter.requestTimestampMargin, newLimitsList.requestTimestampMargin) - assert.equals(limitsAfter.maxPositiveTokenRebase, newLimitsList.maxPositiveTokenRebase) assert.equals(limitsAfter.maxValidatorExitRequestsPerReport, newLimitsList.maxValidatorExitRequestsPerReport) assert.equals(limitsAfter.maxAccountingExtraDataListItemsCount, newLimitsList.maxAccountingExtraDataListItemsCount) + assert.equals(limitsAfter.maxNodeOperatorsPerExtraDataItemCount, newLimitsList.maxNodeOperatorsPerExtraDataItemCount) + assert.equals(limitsAfter.requestTimestampMargin, newLimitsList.requestTimestampMargin) + assert.equals(limitsAfter.maxPositiveTokenRebase, newLimitsList.maxPositiveTokenRebase) }) }) @@ -180,6 +185,31 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa it('passes all checks with correct oracle report data', async () => { await oracleReportSanityChecker.checkAccountingOracleReport(...Object.values(correctLidoOracleReport)) }) + + it('set maxAccountingExtraDataListItemsCount', async () => { + const previousValue = (await oracleReportSanityChecker.getOracleReportLimits()).maxAccountingExtraDataListItemsCount + const newValue = 31 + assert.notEquals(newValue, previousValue) + await oracleReportSanityChecker.setMaxAccountingExtraDataListItemsCount(newValue, + { from: managersRoster.maxAccountingExtraDataListItemsCountManagers[0] }) + assert.equals( + (await oracleReportSanityChecker.getOracleReportLimits()).maxAccountingExtraDataListItemsCount, + newValue + ) + }) + + it('set maxNodeOperatorsPerExtraDataItemCount', async () => { + const previousValue = (await oracleReportSanityChecker.getOracleReportLimits()).maxNodeOperatorsPerExtraDataItemCount + const newValue = 33 + assert.notEquals(newValue, previousValue) + await oracleReportSanityChecker.setMaxNodeOperatorsPerExtraDataItemCount(newValue, + { from: managersRoster.maxNodeOperatorsPerExtraDataItemCountManagers[0] }) + assert.equals( + (await oracleReportSanityChecker.getOracleReportLimits()).maxNodeOperatorsPerExtraDataItemCount, + newValue + ) + }) + }) describe('checkWithdrawalQueueOracleReport()', async () => { diff --git a/test/0.8.9/oracle/accounting-oracle-deploy.test.js b/test/0.8.9/oracle/accounting-oracle-deploy.test.js index 588a1d06c..b9ecb3fa5 100644 --- a/test/0.8.9/oracle/accounting-oracle-deploy.test.js +++ b/test/0.8.9/oracle/accounting-oracle-deploy.test.js @@ -108,8 +108,8 @@ function calcExtraDataListHash(packedExtraDataList) { } async function deployOracleReportSanityCheckerForAccounting(lidoLocator, admin) { const churnValidatorsPerDayLimit = 100 - const limitsList = [churnValidatorsPerDayLimit, 0, 0, 0, 0, 0, 32 * 12, 15] - const managersRoster = [[admin], [admin], [admin], [admin], [admin], [admin], [admin], [admin], [admin]] + const limitsList = [churnValidatorsPerDayLimit, 0, 0, 0, 32 * 12, 15, 16, 0, 0] + const managersRoster = [[admin], [admin], [admin], [admin], [admin], [admin], [admin], [admin], [admin], [admin]] const OracleReportSanityChecker = artifacts.require('OracleReportSanityChecker') diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js index ea0c5851a..58d765ee5 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js @@ -197,8 +197,8 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra } const reportItems = getReportDataItems(newReportFields) - const reportFiledsPrevVersion = { ...reportFields, consensusVersion: incorrectPrevVersion } - const reportItemsPrevVersion = getReportDataItems(reportFiledsPrevVersion) + const reportFieldsPrevVersion = { ...reportFields, consensusVersion: incorrectPrevVersion } + const reportItemsPrevVersion = getReportDataItems(reportFieldsPrevVersion) await assert.reverts( oracle.submitReportData(reportItems, oracleVersion, { from: member1 }), diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js index afac6493f..ffc9721aa 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js @@ -67,8 +67,8 @@ module.exports = { async function deployOracleReportSanityCheckerForExitBus(lidoLocator, admin) { const maxValidatorExitRequestsPerReport = 2000 - const limitsList = [0, 0, 0, 0, 0, 0, maxValidatorExitRequestsPerReport, 0] - const managersRoster = [[admin], [], [], [], [], [], [], [], []] + const limitsList = [0, 0, 0, 0, maxValidatorExitRequestsPerReport, 0, 0, 0, 0] + const managersRoster = [[admin], [], [], [], [], [], [], [], [], []] const OracleReportSanityChecker = artifacts.require('OracleReportSanityChecker') diff --git a/test/helpers/config.js b/test/helpers/config.js index 8167d6f8a..a760a27ad 100644 --- a/test/helpers/config.js +++ b/test/helpers/config.js @@ -26,6 +26,7 @@ const DEFAULT_DEPLOY_PARAMS = { shareRateDeviationBPLimit: 10000, maxValidatorExitRequestsPerReport: 10000, maxAccountingExtraDataListItemsCount: 100, + maxNodeOperatorsPerExtraDataItemCount: 100, requestTimestampMargin: 0, maxPositiveTokenRebase: 1000000000, }, @@ -37,6 +38,7 @@ const DEFAULT_DEPLOY_PARAMS = { shareRateDeviationLimitManagers: [], maxValidatorExitRequestsPerReportManagers: [], maxAccountingExtraDataListItemsCountManagers: [], + maxNodeOperatorsPerExtraDataItemCountManagers: [], requestTimestampMarginManagers: [], maxPositiveTokenRebaseManagers: [], } From d88250c575b5d758e96fbcd3f8ffbaed343adc88 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Fri, 17 Feb 2023 15:10:49 +0100 Subject: [PATCH 081/199] refactor: remove Math64 lib --- contracts/0.4.24/lib/Math64.sol | 15 --------------- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 10 +++------- 2 files changed, 3 insertions(+), 22 deletions(-) delete mode 100644 contracts/0.4.24/lib/Math64.sol diff --git a/contracts/0.4.24/lib/Math64.sol b/contracts/0.4.24/lib/Math64.sol deleted file mode 100644 index c95bd919b..000000000 --- a/contracts/0.4.24/lib/Math64.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Lido -// SPDX-License-Identifier: MIT - -// See contracts/COMPILERS.md -pragma solidity 0.4.24; - -library Math64 { - function max(uint64 a, uint64 b) internal pure returns (uint64) { - return a > b ? a : b; - } - - function min(uint64 a, uint64 b) internal pure returns (uint64) { - return a < b ? a : b; - } -} diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 1858dcea5..3f8a0a7f8 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -9,9 +9,7 @@ import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol"; import {SafeMath64} from "@aragon/os/contracts/lib/math/SafeMath64.sol"; import {UnstructuredStorage} from "@aragon/os/contracts/common/UnstructuredStorage.sol"; -import {Math64} from "../lib/Math64.sol"; import {Math256} from "../../common/lib/Math256.sol"; -import {MemUtils} from "../../common/lib/MemUtils.sol"; import {MinFirstAllocationStrategy} from "../../common/lib/MinFirstAllocationStrategy.sol"; import {ILidoLocator} from "../../common/interfaces/ILidoLocator.sol"; import {IBurner} from "../../common/interfaces/IBurner.sol"; @@ -224,8 +222,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // trim vetted signing keys count when node operator is not active vettedSigningKeysCountAfter = depositedSigningKeysCount; } else { - vettedSigningKeysCountAfter = - Math64.min(totalSigningKeysCount, Math64.max(depositedSigningKeysCount, vettedSigningKeysCountBefore)); + vettedSigningKeysCountAfter = uint64(Math256.min(totalSigningKeysCount, Math256.max(uint256(depositedSigningKeysCount), uint256(vettedSigningKeysCountBefore)))); } if (vettedSigningKeysCountBefore != vettedSigningKeysCountAfter) { @@ -393,8 +390,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint64 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); uint64 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); - uint64 vettedSigningKeysCountAfter = - Math64.min(totalSigningKeysCount, Math64.max(_vettedSigningKeysCount, depositedSigningKeysCount)); + uint64 vettedSigningKeysCountAfter = uint64(Math256.min(totalSigningKeysCount, Math256.max(uint256(_vettedSigningKeysCount), uint256(depositedSigningKeysCount)))); if (vettedSigningKeysCountAfter == vettedSigningKeysCountBefore) { return; @@ -734,7 +730,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // correct max count according to target if target is enabled uint64 targetLimit = exitedSigningKeysCount.add(operatorTargetStats.get(TARGET_VALIDATORS_COUNT_OFFSET)); if (targetLimit > depositedSigningKeysCount) { - newMaxSigningKeysCount = Math64.min(vettedSigningKeysCount, targetLimit); + newMaxSigningKeysCount = uint64(Math256.max(uint256(vettedSigningKeysCount), uint256(targetLimit))); } } } // else newMaxSigningKeysCount = depositedSigningKeysCount, so depositable keys count = 0 From 8a55b07f2012a596dc2487a92f165bfb9a06df47 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Fri, 17 Feb 2023 21:18:27 +0700 Subject: [PATCH 082/199] feat: add trailing byte tests --- ...ng-oracle-submit-report-extra-data.test.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 40741e184..12dc6fe66 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -517,6 +517,34 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra ) }) }) + + it('reverts on extra bytes in data', async () => { + await consensus.advanceTimeToNextFrameStart() + const { refSlot } = await consensus.getCurrentFrame() + + const extraDataItems = encodeExtraDataItems(getDefaultExtraData()) + const extraDataList = packExtraDataList(extraDataItems) + 'ffff' + const extraDataHash = calcExtraDataListHash(extraDataList) + + const reportFields = getDefaultReportFields({ + extraDataHash, + extraDataItemsCount: extraDataItems.length, + refSlot + }) + + const reportItems = getReportDataItems(reportFields) + const reportHash = calcReportDataHash(reportItems) + + await consensus.submitReport(reportFields.refSlot, reportHash, CONSENSUS_VERSION, { + from: member1 + }) + await oracle.submitReportData(reportItems, oracleVersion, { from: member1 }) + + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, { from: member1 }), + 'UnexpectedExtraDataIndex(5, 16776960)' + ) + }) }) context('delivers the data to staking router', () => { From 7a7c9ebdb9b08ae531e0cfd3455a686a8787520d Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Fri, 17 Feb 2023 21:48:12 +0700 Subject: [PATCH 083/199] feat: test for successful legacy oracle migration --- test/0.8.9/oracle/accounting-oracle-deploy.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/0.8.9/oracle/accounting-oracle-deploy.test.js b/test/0.8.9/oracle/accounting-oracle-deploy.test.js index c249cf936..8ce8fc2d9 100644 --- a/test/0.8.9/oracle/accounting-oracle-deploy.test.js +++ b/test/0.8.9/oracle/accounting-oracle-deploy.test.js @@ -319,6 +319,9 @@ contract('AccountingOracle', ([admin, member1]) => { const deployed = await deployAccountingOracleSetup(admin, { initialEpoch: 3 + 10 * EPOCHS_PER_FRAME }) await deployed.legacyOracle.setLastCompletedEpochId(3 + 9 * EPOCHS_PER_FRAME) await initAccountingOracle({ admin, ...deployed }) + const refSlot = await deployed.oracle.getLastProcessingRefSlot() + const epoch = await deployed.legacyOracle.getLastCompletedEpochId() + assert.equals(refSlot, epoch.muln(SLOTS_PER_EPOCH)) }) it('deployment and init finishes successfully (default setup)', async () => { From 8073c3dd0080c3e48eef83eb822b7fbf622e2a1e Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Fri, 17 Feb 2023 16:53:44 +0200 Subject: [PATCH 084/199] fix: transfer to themselves --- contracts/0.8.9/WithdrawalQueueERC721.sol | 4 +++- lib/abi/WithdrawalQueueERC721.json | 2 +- test/0.8.9/withdrawal-request-nft.test.js | 10 ++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueueERC721.sol b/contracts/0.8.9/WithdrawalQueueERC721.sol index 5bcfefe60..46e46af43 100644 --- a/contracts/0.8.9/WithdrawalQueueERC721.sol +++ b/contracts/0.8.9/WithdrawalQueueERC721.sol @@ -48,6 +48,7 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { error TransferFromIncorrectOwner(address from, address realOwner); error TransferToZeroAddress(); error TransferFromZeroAddress(); + error TransferToThemselves(); error TransferToNonIERC721Receiver(address); error InvalidOwnerAddress(address); error StringTooLong(string str); @@ -178,6 +179,7 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { /// - `msg.sender` should be approved, or approved for all, or owner function _transfer(address _from, address _to, uint256 _requestId) internal { if (_to == address(0)) revert TransferToZeroAddress(); + if (_to == _from) revert TransferToThemselves(); if (_requestId == 0 || _requestId > getLastRequestId()) revert InvalidRequestId(_requestId); WithdrawalRequest storage request = _getQueue()[_requestId]; @@ -191,8 +193,8 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { delete _getTokenApprovals()[_requestId]; request.owner = payable(_to); - _getRequestsByOwner()[_to].add(_requestId); _getRequestsByOwner()[_from].remove(_requestId); + _getRequestsByOwner()[_to].add(_requestId); _emitTransfer(_from, _to, _requestId); } diff --git a/lib/abi/WithdrawalQueueERC721.json b/lib/abi/WithdrawalQueueERC721.json index 0ccb54190..1b0b63abc 100644 --- a/lib/abi/WithdrawalQueueERC721.json +++ b/lib/abi/WithdrawalQueueERC721.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/test/0.8.9/withdrawal-request-nft.test.js b/test/0.8.9/withdrawal-request-nft.test.js index a66e29438..b976c7205 100644 --- a/test/0.8.9/withdrawal-request-nft.test.js +++ b/test/0.8.9/withdrawal-request-nft.test.js @@ -224,6 +224,16 @@ hre.contract( ) }) + it('reverts when transfer to the same address', async () => { + await assert.reverts( + withdrawalQueueERC721.transferFrom( + nftHolderWstETH, nftHolderWstETH, nftHolderWstETHTokenIds[0], + {from: nftHolderWstETH } + ), + 'TransferToThemselves()' + ) + }) + it('reverts with error "RequestAlreadyClaimed()" when called on claimed request', async () => { const batch = await withdrawalQueueERC721.finalizationBatch(3, shareRate(1)) await withdrawalQueueERC721.finalize(3, { from: deployer, value: batch.ethToLock }) From 4b566e798971ae747338197a727c6969a42a7136 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Fri, 17 Feb 2023 16:10:51 +0100 Subject: [PATCH 085/199] fix: limit recalc, tests --- .../0.4.24/nos/NodeOperatorsRegistry.sol | 2 +- .../NodeOperatorsRegistryMock.sol | 4 +-- test/0.4.24/node-operators-registry.test.js | 30 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 3f8a0a7f8..741c33720 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -730,7 +730,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // correct max count according to target if target is enabled uint64 targetLimit = exitedSigningKeysCount.add(operatorTargetStats.get(TARGET_VALIDATORS_COUNT_OFFSET)); if (targetLimit > depositedSigningKeysCount) { - newMaxSigningKeysCount = uint64(Math256.max(uint256(vettedSigningKeysCount), uint256(targetLimit))); + newMaxSigningKeysCount = uint64(Math256.min(uint256(vettedSigningKeysCount), uint256(targetLimit))); } } } // else newMaxSigningKeysCount = depositedSigningKeysCount, so depositable keys count = 0 diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index 71bfc19e2..3cfeb7c8f 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -186,8 +186,8 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { return false; } - function testing_getCorrectedNodeOperator(uint256 operatorId) external view - returns (uint64 vettedSigningKeysCount, uint64 exitedSigningKeysCount, uint64 depositedSigningKeysCount) + function testing_getNodeOperatorWithLimitApplied(uint256 operatorId) external view + returns (uint64 maxSigningKeysCount, uint64 exitedSigningKeysCount, uint64 depositedSigningKeysCount) { return _getNodeOperatorWithLimitApplied(operatorId); } diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index 1491a5268..f0b7b9a03 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -1532,48 +1532,48 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await nodeOperators.addNodeOperator(app, { ...NODE_OPERATORS[1], depositedSigningKeysCount: 5 }, { from: voting }) }) - it('_getCorrectedNodeOperator() - deposited < target < vetted', async () => { - let firstNodeOperatorKeysStats = await app.testing_getCorrectedNodeOperator(firstNodeOperatorId) + it('_getCorrectedNodeOperator() - deposited < exited+target < vetted', async () => { + let firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) - assert.equals(+firstNodeOperatorKeysStats.vettedSigningKeysCount, 8) + assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) assert.equals(+firstNodeOperatorKeysStats.exitedSigningKeysCount, 1) await app.updateTargetValidatorsLimits(firstNodeOperatorId, true, 6, { from: voting }) - firstNodeOperatorKeysStats = await app.testing_getCorrectedNodeOperator(firstNodeOperatorId) - assert.equals(+firstNodeOperatorKeysStats.vettedSigningKeysCount, 7) + firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 7) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) assert.equals(+firstNodeOperatorKeysStats.exitedSigningKeysCount, 1) }) - it('_getCorrectedNodeOperator() - target >= vetted', async () => { - let firstNodeOperatorKeysStats = await app.testing_getCorrectedNodeOperator(firstNodeOperatorId) + it('_getNodeOperatorWithLimitApplied() - exited+target >= vetted', async () => { + let firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) - assert.equals(+firstNodeOperatorKeysStats.vettedSigningKeysCount, 8) + assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) assert.equals(+firstNodeOperatorKeysStats.exitedSigningKeysCount, 1) await app.updateTargetValidatorsLimits(firstNodeOperatorId, true, 1000, { from: voting }) - firstNodeOperatorKeysStats = await app.testing_getCorrectedNodeOperator(firstNodeOperatorId) - assert.equals(+firstNodeOperatorKeysStats.vettedSigningKeysCount, 8) + firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) assert.equals(+firstNodeOperatorKeysStats.exitedSigningKeysCount, 1) }) - it('_getCorrectedNodeOperator() - target <= deposited-exited', async () => { - let firstNodeOperatorKeysStats = await app.testing_getCorrectedNodeOperator(firstNodeOperatorId) + it('_getNodeOperatorWithLimitApplied() - exited+target <= deposited', async () => { + let firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) - assert.equals(+firstNodeOperatorKeysStats.vettedSigningKeysCount, 8) + assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) assert.equals(+firstNodeOperatorKeysStats.exitedSigningKeysCount, 1) await app.updateTargetValidatorsLimits(firstNodeOperatorId, true, 4, { from: voting }) - firstNodeOperatorKeysStats = await app.testing_getCorrectedNodeOperator(firstNodeOperatorId) + firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) assert.equals( - +firstNodeOperatorKeysStats.vettedSigningKeysCount, + +firstNodeOperatorKeysStats.maxSigningKeysCount, firstNodeOperatorKeysStats.depositedSigningKeysCount ) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) From 10ac6cb2f3a626562eaa1dd31d2548ad1449599c Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Fri, 17 Feb 2023 18:23:26 +0300 Subject: [PATCH 086/199] fix: add OracleDaemonConfig to LidoLocator --- contracts/0.8.9/LidoLocator.sol | 3 +++ contracts/0.8.9/test_helpers/LidoLocatorMock.sol | 3 +++ contracts/common/interfaces/ILidoLocator.sol | 1 + lib/abi/LidoLocator.json | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/contracts/0.8.9/LidoLocator.sol b/contracts/0.8.9/LidoLocator.sol index 721875b00..07392a280 100644 --- a/contracts/0.8.9/LidoLocator.sol +++ b/contracts/0.8.9/LidoLocator.sol @@ -27,6 +27,7 @@ contract LidoLocator is ILidoLocator { address validatorsExitBusOracle; address withdrawalQueue; address withdrawalVault; + address oracleDaemonConfig; } error ZeroAddress(); @@ -44,6 +45,7 @@ contract LidoLocator is ILidoLocator { address public immutable validatorsExitBusOracle; address public immutable withdrawalQueue; address public immutable withdrawalVault; + address public immutable oracleDaemonConfig; /** * @notice declare service locations @@ -64,6 +66,7 @@ contract LidoLocator is ILidoLocator { validatorsExitBusOracle = _assertNonZero(_config.validatorsExitBusOracle); withdrawalQueue = _assertNonZero(_config.withdrawalQueue); withdrawalVault = _assertNonZero(_config.withdrawalVault); + oracleDaemonConfig = _assertNonZero(_config.oracleDaemonConfig); } function coreComponents() external view returns( diff --git a/contracts/0.8.9/test_helpers/LidoLocatorMock.sol b/contracts/0.8.9/test_helpers/LidoLocatorMock.sol index 7d00ea62e..d4bd92f5a 100644 --- a/contracts/0.8.9/test_helpers/LidoLocatorMock.sol +++ b/contracts/0.8.9/test_helpers/LidoLocatorMock.sol @@ -21,6 +21,7 @@ contract LidoLocatorMock is ILidoLocator { address withdrawalQueue; address withdrawalVault; address postTokenRebaseReceiver; + address oracleDaemonConfig; } address public immutable lido; @@ -36,6 +37,7 @@ contract LidoLocatorMock is ILidoLocator { address public immutable withdrawalQueue; address public immutable withdrawalVault; address public immutable postTokenRebaseReceiver; + address public immutable oracleDaemonConfig; constructor ( ContractAddresses memory addresses @@ -53,6 +55,7 @@ contract LidoLocatorMock is ILidoLocator { withdrawalQueue = addresses.withdrawalQueue; withdrawalVault = addresses.withdrawalVault; postTokenRebaseReceiver = addresses.postTokenRebaseReceiver; + oracleDaemonConfig = addresses.oracleDaemonConfig; } function coreComponents() external view returns(address,address,address,address,address,address) { diff --git a/contracts/common/interfaces/ILidoLocator.sol b/contracts/common/interfaces/ILidoLocator.sol index 3b996b8b2..a2bdc764d 100644 --- a/contracts/common/interfaces/ILidoLocator.sol +++ b/contracts/common/interfaces/ILidoLocator.sol @@ -19,6 +19,7 @@ interface ILidoLocator { function withdrawalQueue() external view returns(address); function withdrawalVault() external view returns(address); function postTokenRebaseReceiver() external view returns(address); + function oracleDaemonConfig() external view returns(address); function coreComponents() external view returns( address elRewardsVault, address oracleReportSanityChecker, diff --git a/lib/abi/LidoLocator.json b/lib/abi/LidoLocator.json index a75b6f4bc..f2145f2d8 100644 --- a/lib/abi/LidoLocator.json +++ b/lib/abi/LidoLocator.json @@ -1 +1 @@ -[{"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":"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":"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":"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 From 77fcbae97f829dedc090a7be745310a9ac325543 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Fri, 17 Feb 2023 17:50:59 +0200 Subject: [PATCH 087/199] fix: balanceOf decreasing on claim --- contracts/0.8.9/WithdrawalQueueBase.sol | 1 + test/0.8.9/withdrawal-request-nft.test.js | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/contracts/0.8.9/WithdrawalQueueBase.sol b/contracts/0.8.9/WithdrawalQueueBase.sol index 10695fda8..7b8b9de0c 100644 --- a/contracts/0.8.9/WithdrawalQueueBase.sol +++ b/contracts/0.8.9/WithdrawalQueueBase.sol @@ -442,6 +442,7 @@ abstract contract WithdrawalQueueBase { if (_recipient == address(0)) _recipient = request.owner; request.claimed = true; + _getRequestsByOwner()[request.owner].remove(_requestId); DiscountCheckpoint memory hintCheckpoint = _getCheckpoints()[_hint]; // ______(_______ diff --git a/test/0.8.9/withdrawal-request-nft.test.js b/test/0.8.9/withdrawal-request-nft.test.js index b976c7205..d38a37440 100644 --- a/test/0.8.9/withdrawal-request-nft.test.js +++ b/test/0.8.9/withdrawal-request-nft.test.js @@ -310,5 +310,20 @@ hre.contract( assert.equal(await withdrawalQueueERC721.ownerOf(nftHolderWstETHTokenIds[0]), stETH.address) }) }) + + describe('Burn', () => { + it('balanceOf decreases after claim', async () => { + const balanceBefore = await withdrawalQueueERC721.balanceOf(nftHolderStETH); + + const batch = await withdrawalQueueERC721.finalizationBatch(3, shareRate(1)) + await withdrawalQueueERC721.finalize(3, { from: deployer, value: batch.ethToLock }) + + await withdrawalQueueERC721.methods['claimWithdrawal(uint256)'](nftHolderStETHTokenIds[0], { + from: nftHolderStETH + }) + + assert.equals(balanceBefore - await withdrawalQueueERC721.balanceOf(nftHolderStETH), 1) + }) + }) } ) From 8932c106617f8b4eef32192c98d6da1ea11054e7 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Fri, 17 Feb 2023 18:55:38 +0200 Subject: [PATCH 088/199] =?UTF-8?q?=F0=9F=92=85:=20remove=20payable=20addr?= =?UTF-8?q?ess=20from=20WithdrawalRequest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/0.8.9/WithdrawalQueueBase.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueueBase.sol b/contracts/0.8.9/WithdrawalQueueBase.sol index 7b8b9de0c..47a71dd51 100644 --- a/contracts/0.8.9/WithdrawalQueueBase.sol +++ b/contracts/0.8.9/WithdrawalQueueBase.sol @@ -49,7 +49,7 @@ abstract contract WithdrawalQueueBase { /// @notice sum of the all shares locked for withdrawal up to this request uint128 cumulativeShares; /// @notice address that can claim or transfer the request - address payable owner; + address owner; /// @notice block.timestamp when the request was created uint64 timestamp; /// @notice flag if the request was claimed @@ -417,7 +417,7 @@ abstract contract WithdrawalQueueBase { _setLastRequestId(requestId); _getQueue()[requestId] = - WithdrawalRequest(cumulativeStETH, cumulativeShares, payable(_owner), uint64(block.timestamp), false); + WithdrawalRequest(cumulativeStETH, cumulativeShares, _owner, uint64(block.timestamp), false); _getRequestsByOwner()[_owner].add(requestId); emit WithdrawalRequested(requestId, msg.sender, _owner, _amountOfStETH, _amountOfShares); @@ -462,7 +462,7 @@ abstract contract WithdrawalQueueBase { _setLockedEtherAmount(getLockedEtherAmount() - ethWithDiscount); - _sendValue(payable(_recipient), ethWithDiscount); + _sendValue(_recipient, ethWithDiscount); emit WithdrawalClaimed(_requestId, msg.sender, _recipient, ethWithDiscount); } @@ -472,11 +472,11 @@ abstract contract WithdrawalQueueBase { // setting dummy zero structs in checkpoints and queue beginning // to avoid uint underflows and related if-branches // 0-index is reserved as 'not_found' response in the interface everywhere - _getQueue()[0] = WithdrawalRequest(0, 0, payable(0), uint64(block.number), true); + _getQueue()[0] = WithdrawalRequest(0, 0, address(0), uint64(block.number), true); _getCheckpoints()[getLastCheckpointIndex()] = DiscountCheckpoint(0, 0); } - function _sendValue(address payable _recipient, uint256 _amount) internal { + function _sendValue(address _recipient, uint256 _amount) internal { if (address(this).balance < _amount) revert NotEnoughEther(); // solhint-disable-next-line From cb9049a140e3c6a0c3a87ae303a8d2116a6b0913 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Fri, 17 Feb 2023 18:57:25 +0200 Subject: [PATCH 089/199] fix: optimize binary search by excluding last element --- contracts/0.8.9/WithdrawalQueueBase.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/0.8.9/WithdrawalQueueBase.sol b/contracts/0.8.9/WithdrawalQueueBase.sol index 47a71dd51..f2966443b 100644 --- a/contracts/0.8.9/WithdrawalQueueBase.sol +++ b/contracts/0.8.9/WithdrawalQueueBase.sol @@ -218,7 +218,7 @@ abstract contract WithdrawalQueueBase { // Binary search uint256 min = _start; - uint256 max = _end; + uint256 max = _end - 1; while (max > min) { uint256 mid = (max + min + 1) / 2; From fa03bfc0bed90dcbf747c8709f7687a6f8516497 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Fri, 17 Feb 2023 18:58:59 +0200 Subject: [PATCH 090/199] fix: remove unnecessary variable --- contracts/0.8.9/WithdrawalQueue.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index b39d57215..941557304 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -142,8 +142,7 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit if (_owner == address(0)) _owner = msg.sender; requestIds = new uint256[](amounts.length); for (uint256 i = 0; i < amounts.length; ++i) { - uint256 amountOfWstETH = amounts[i]; - requestIds[i] = _requestWithdrawalWstETH(amountOfWstETH, _owner); + requestIds[i] = _requestWithdrawalWstETH(amounts[i], _owner); } } From 8aa6a71693212a954bd1e32f42c736447dc9cd7d Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Fri, 17 Feb 2023 19:15:50 +0200 Subject: [PATCH 091/199] fix: move pause on initialize to PausableUntil --- contracts/0.8.9/WithdrawalQueue.sol | 1 - contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol | 1 - contracts/0.8.9/utils/PausableUntil.sol | 2 ++ 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index 941557304..06d47c253 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -335,7 +335,6 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit _grantRole(FINALIZE_ROLE, _finalizer); _grantRole(BUNKER_MODE_REPORT_ROLE, _bunkerReporter); - RESUME_SINCE_TIMESTAMP_POSITION.setStorageUint256(PAUSE_INFINITELY); // pause it explicitly BUNKER_MODE_SINCE_TIMESTAMP_POSITION.setStorageUint256(BUNKER_MODE_DISABLED_TIMESTAMP); emit InitializedV1(_admin, _pauser, _resumer, _finalizer, msg.sender); diff --git a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol index 9ac99f019..1cb5cecf6 100644 --- a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol +++ b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol @@ -100,7 +100,6 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil { _setupRole(DEFAULT_ADMIN_ROLE, admin); _initializePausable(); _initialize(consensusContract, consensusVersion, lastProcessingRefSlot); - RESUME_SINCE_TIMESTAMP_POSITION.setStorageUint256(PAUSE_INFINITELY); // pause it explicitly } /// @notice Resume accepting validator exit requests diff --git a/contracts/0.8.9/utils/PausableUntil.sol b/contracts/0.8.9/utils/PausableUntil.sol index b4aff4e93..76ccf160a 100644 --- a/contracts/0.8.9/utils/PausableUntil.sol +++ b/contracts/0.8.9/utils/PausableUntil.sol @@ -44,6 +44,8 @@ contract PausableUntil { } function _initializePausable() internal { + RESUME_SINCE_TIMESTAMP_POSITION.setStorageUint256(PAUSE_INFINITELY); + emit Paused(PAUSE_INFINITELY); } From 271f9c710a95b9c69157957229d043b1beb79a5c Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Fri, 17 Feb 2023 19:17:05 +0200 Subject: [PATCH 092/199] fix: right arg for InitializedV1 --- contracts/0.8.9/WithdrawalQueue.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index 06d47c253..066172e79 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -337,7 +337,7 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit BUNKER_MODE_SINCE_TIMESTAMP_POSITION.setStorageUint256(BUNKER_MODE_DISABLED_TIMESTAMP); - emit InitializedV1(_admin, _pauser, _resumer, _finalizer, msg.sender); + emit InitializedV1(_admin, _pauser, _resumer, _finalizer, _bunkerReporter); } function _requestWithdrawal(uint256 _amountOfStETH, address _owner) internal returns (uint256 requestId) { From 97f11205c69bc1a655a139f0de4dd5b5e36ab2df Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Fri, 17 Feb 2023 19:21:41 +0200 Subject: [PATCH 093/199] fix: remove unused errors --- contracts/0.8.9/Burner.sol | 1 - contracts/0.8.9/WithdrawalQueue.sol | 4 ---- lib/abi/Burner.json | 2 +- lib/abi/WithdrawalQueue.json | 2 +- lib/abi/WithdrawalQueueERC721.json | 2 +- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/contracts/0.8.9/Burner.sol b/contracts/0.8.9/Burner.sol index 5cfd927f4..c4997062c 100644 --- a/contracts/0.8.9/Burner.sol +++ b/contracts/0.8.9/Burner.sol @@ -57,7 +57,6 @@ contract Burner is IBurner, AccessControlEnumerable { error ZeroRecoveryAmount(); error StETHRecoveryWrongFunc(); error ZeroBurnAmount(); - error NotEnoughExcessStETH(); error ZeroAddress(string field); bytes32 public constant REQUEST_BURN_MY_STETH_ROLE = keccak256("REQUEST_BURN_MY_STETH_ROLE"); diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index 066172e79..e03e2fbb1 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -65,13 +65,9 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit event BunkerModeDisabled(); error AdminZeroAddress(); - error AlreadyInitialized(); - error Uninitialized(); - error Unimplemented(); error RequestAmountTooSmall(uint256 _amountOfStETH); error RequestAmountTooLarge(uint256 _amountOfStETH); error InvalidReportTimestamp(); - error LengthsMismatch(uint256 _expectedLength, uint256 _actualLength); error RequestIdsNotSorted(); /// @param _wstETH address of WstETH contract diff --git a/lib/abi/Burner.json b/lib/abi/Burner.json index 07d05ab96..07cd2ab43 100644 --- a/lib/abi/Burner.json +++ b/lib/abi/Burner.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_stETH","type":"address"},{"internalType":"uint256","name":"_totalCoverSharesBurnt","type":"uint256"},{"internalType":"uint256","name":"_totalNonCoverSharesBurnt","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"NotEnoughExcessStETH","type":"error"},{"inputs":[],"name":"StETHRecoveryWrongFunc","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroBurnAmount","type":"error"},{"inputs":[],"name":"ZeroRecoveryAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestedBy","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestedBy","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestedBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"ExcessStETHRecovered","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":"bool","name":"isCover","type":"bool"},{"indexed":true,"internalType":"address","name":"requestedBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"StETHBurnRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"isCover","type":"bool"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"StETHBurnt","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECOVER_ASSETS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUEST_BURN_MY_STETH_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUEST_BURN_SHARES_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TREASURY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sharesToBurnLimit","type":"uint256"}],"name":"commitSharesToBurn","outputs":[{"internalType":"uint256","name":"sharesToBurnNow","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCoverSharesBurnt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExcessStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNonCoverSharesBurnt","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":"getSharesRequestedToBurn","outputs":[{"internalType":"uint256","name":"coverShares","type":"uint256"},{"internalType":"uint256","name":"nonCoverShares","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":"_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":"recoverExcessStETH","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":[{"internalType":"uint256","name":"_stETHAmountToBurn","type":"uint256"}],"name":"requestBurnMyStETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stETHAmountToBurn","type":"uint256"}],"name":"requestBurnMyStETHForCover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_sharesAmountToBurn","type":"uint256"}],"name":"requestBurnShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_sharesAmountToBurn","type":"uint256"}],"name":"requestBurnSharesForCover","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"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_stETH","type":"address"},{"internalType":"uint256","name":"_totalCoverSharesBurnt","type":"uint256"},{"internalType":"uint256","name":"_totalNonCoverSharesBurnt","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"StETHRecoveryWrongFunc","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroBurnAmount","type":"error"},{"inputs":[],"name":"ZeroRecoveryAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestedBy","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestedBy","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestedBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"ExcessStETHRecovered","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":"bool","name":"isCover","type":"bool"},{"indexed":true,"internalType":"address","name":"requestedBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"StETHBurnRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"isCover","type":"bool"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"StETHBurnt","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECOVER_ASSETS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUEST_BURN_MY_STETH_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUEST_BURN_SHARES_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TREASURY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sharesToBurnLimit","type":"uint256"}],"name":"commitSharesToBurn","outputs":[{"internalType":"uint256","name":"sharesToBurnNow","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCoverSharesBurnt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExcessStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNonCoverSharesBurnt","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":"getSharesRequestedToBurn","outputs":[{"internalType":"uint256","name":"coverShares","type":"uint256"},{"internalType":"uint256","name":"nonCoverShares","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":"_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":"recoverExcessStETH","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":[{"internalType":"uint256","name":"_stETHAmountToBurn","type":"uint256"}],"name":"requestBurnMyStETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stETHAmountToBurn","type":"uint256"}],"name":"requestBurnMyStETHForCover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_sharesAmountToBurn","type":"uint256"}],"name":"requestBurnShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_sharesAmountToBurn","type":"uint256"}],"name":"requestBurnSharesForCover","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"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueue.json b/lib/abi/WithdrawalQueue.json index e81ab351d..b2b850c03 100644 --- a/lib/abi/WithdrawalQueue.json +++ b/lib/abi/WithdrawalQueue.json @@ -1 +1 @@ -[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueueERC721.json b/lib/abi/WithdrawalQueueERC721.json index 1b0b63abc..3984b3b9b 100644 --- a/lib/abi/WithdrawalQueueERC721.json +++ b/lib/abi/WithdrawalQueueERC721.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"_expectedLength","type":"uint256"},{"internalType":"uint256","name":"_actualLength","type":"uint256"}],"name":"LengthsMismatch","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"Unimplemented","type":"error"},{"inputs":[],"name":"Uninitialized","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file From 6da696cfb90b1f39deb2ebb79a733c9205e9f9cb Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 18 Feb 2023 18:43:22 +0300 Subject: [PATCH 094/199] chore: comments about initial token holder --- contracts/0.4.24/Lido.sol | 5 +++++ contracts/0.4.24/StETH.sol | 14 +++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index e5cafda30..40fbe7657 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -250,6 +250,9 @@ contract Lido is Versioned, StETHPermit, AragonApp { /** * @dev As AragonApp, Lido contract must be initialized with following variables: * NB: by default, staking and the whole Lido pool are in paused state + * + * The contract's balance must be non-zero to allow initial holder bootstrap. + * * @param _lidoLocator lido locator contract * @param _eip712StETH eip712 helper contract for StETH */ @@ -291,6 +294,8 @@ contract Lido is Versioned, StETHPermit, AragonApp { * @notice A function to finalize upgrade to v2 (from v1). Can be called only once * @dev Value "1" in CONTRACT_VERSION_POSITION is skipped due to change in numbering * + * The initial protocol token holder must exist. + * * For more details see https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-10.md */ function finalizeUpgrade_v2(address _lidoLocator, address _eip712StETH) external { diff --git a/contracts/0.4.24/StETH.sol b/contracts/0.4.24/StETH.sol index 8ce41868c..0261fe377 100644 --- a/contracts/0.4.24/StETH.sol +++ b/contracts/0.4.24/StETH.sol @@ -503,17 +503,21 @@ contract StETH is IERC20, Pausable { } /** - * @notice Mints amount of shares equal to contract balance to 0xdead address - * It allows to get rid of zero checks and corner cases - * @dev should be invoked before using the token + * @notice Mints shares on behalf of 0xdead address, + * the shares amount is equal to the contract's balance. * + * + * Allows to get rid of zero checks for `totalShares` and `totalPooledEther` + * and overcome corner cases. + * + * @dev must be invoked before using the token */ function _bootstrapInitialHolder() internal returns (uint256) { uint256 balance = address(this).balance; require(balance != 0, "EMPTY_INIT_BALANCE"); if (_getTotalShares() == 0) { - // if protocol is empty bootstrap it with the contract's balance - // 0xdead is a holder for initial shares + // if protocol is empty bootstrap it with the contract's balance + // address(0xdead) is a holder for initial shares _mintShares(INITIAL_TOKEN_HOLDER, balance); emit Transfer(0x0, INITIAL_TOKEN_HOLDER, balance); From 9ecf5f42ab91a7f5f1b50a69b3321a37f517e53d Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 18 Feb 2023 19:04:10 +0300 Subject: [PATCH 095/199] doc: mention foundry in README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index ce9f98e40..deec7515a 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ The contract also works as a wrapper that accepts stETH tokens and mints wstETH * docker * node.js v12 * (optional) Lerna +* (optional) Foundry ### Installing Aragon & other deps @@ -239,6 +240,14 @@ so full branch coverage will never be reported until [solidity-coverage#219]: https://github.com/sc-forks/solidity-coverage/issues/269 +Run fuzzing tests with foundry: + +```bash +curl -L https://foundry.paradigm.xyz | bash +foundry up +forge test +``` + ## Deploying We have several ways to deploy lido smart-contracts and run DAO locally, you can find documents here: From 3d25bffae6026180d3ee7329095ebc28cd1c735f Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 18 Feb 2023 19:06:33 +0300 Subject: [PATCH 096/199] chore: remove extra space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index deec7515a..edec88af6 100644 --- a/README.md +++ b/README.md @@ -244,7 +244,7 @@ Run fuzzing tests with foundry: ```bash curl -L https://foundry.paradigm.xyz | bash -foundry up +foundryup forge test ``` From 01c603877e12e0390f3062d9170dc62f1fca508b Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 18 Feb 2023 20:45:04 +0300 Subject: [PATCH 097/199] chore: format one-liners, tighten BP limits --- .../OracleReportSanityChecker.sol | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol b/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol index 3e45ab425..a2b2ccf26 100644 --- a/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol +++ b/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol @@ -66,7 +66,6 @@ struct LimitsList { /// @notice The positive token rebase allowed per single LidoOracle report /// @dev uses 1e9 precision, e.g.: 1e6 - 0.1%; 1e9 - 100%, see `setMaxPositiveTokenRebase()` uint256 maxPositiveTokenRebase; - } /// @dev The packed version of the LimitsList struct to be effectively persisted in storage @@ -225,7 +224,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE) { - _checkLimitValue(_oneOffCLBalanceDecreaseBPLimit, type(uint16).max); + _checkLimitValue(_oneOffCLBalanceDecreaseBPLimit, MAX_BASIS_POINTS); LimitsList memory limitsList = _limits.unpack(); limitsList.oneOffCLBalanceDecreaseBPLimit = _oneOffCLBalanceDecreaseBPLimit; _updateLimits(limitsList); @@ -237,7 +236,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE) { - _checkLimitValue(_annualBalanceIncreaseBPLimit, type(uint16).max); + _checkLimitValue(_annualBalanceIncreaseBPLimit, MAX_BASIS_POINTS); LimitsList memory limitsList = _limits.unpack(); limitsList.annualBalanceIncreaseBPLimit = _annualBalanceIncreaseBPLimit; _updateLimits(limitsList); @@ -249,7 +248,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { external onlyRole(SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE) { - _checkLimitValue(_shareRateDeviationBPLimit, type(uint16).max); + _checkLimitValue(_shareRateDeviationBPLimit, MAX_BASIS_POINTS); LimitsList memory limitsList = _limits.unpack(); limitsList.shareRateDeviationBPLimit = _shareRateDeviationBPLimit; _updateLimits(limitsList); @@ -500,16 +499,18 @@ contract OracleReportSanityChecker is AccessControlEnumerable { uint256 _actualWithdrawalVaultBalance, uint256 _reportedWithdrawalVaultBalance ) internal pure { - if (_reportedWithdrawalVaultBalance > _actualWithdrawalVaultBalance) + if (_reportedWithdrawalVaultBalance > _actualWithdrawalVaultBalance) { revert IncorrectWithdrawalsVaultBalance(_actualWithdrawalVaultBalance); + } } function _checkELRewardsVaultBalance( uint256 _actualELRewardsVaultBalance, uint256 _reportedELRewardsVaultBalance ) internal pure { - if (_reportedELRewardsVaultBalance > _actualELRewardsVaultBalance) + if (_reportedELRewardsVaultBalance > _actualELRewardsVaultBalance) { revert IncorrectELRewardsVaultBalance(_actualELRewardsVaultBalance); + } } function _checkOneOffCLBalanceDecrease( @@ -520,8 +521,9 @@ contract OracleReportSanityChecker is AccessControlEnumerable { if (_preCLBalance <= _unifiedPostCLBalance) return; uint256 oneOffCLBalanceDecreaseBP = (MAX_BASIS_POINTS * (_preCLBalance - _unifiedPostCLBalance)) / _preCLBalance; - if (oneOffCLBalanceDecreaseBP > _limitsList.oneOffCLBalanceDecreaseBPLimit) + if (oneOffCLBalanceDecreaseBP > _limitsList.oneOffCLBalanceDecreaseBPLimit) { revert IncorrectCLBalanceDecrease(oneOffCLBalanceDecreaseBP); + } } function _checkAnnualBalancesIncrease( @@ -546,8 +548,10 @@ contract OracleReportSanityChecker is AccessControlEnumerable { uint256 annualBalanceIncrease = ((365 days * MAX_BASIS_POINTS * balanceIncrease) / _preCLBalance) / _timeElapsed; - if (annualBalanceIncrease > _limitsList.annualBalanceIncreaseBPLimit) + + if (annualBalanceIncrease > _limitsList.annualBalanceIncreaseBPLimit) { revert IncorrectCLBalanceIncrease(annualBalanceIncrease); + } } function _checkValidatorsChurnLimit( @@ -595,8 +599,10 @@ contract OracleReportSanityChecker is AccessControlEnumerable { SafeCast.toInt256(_simulatedShareRate) - SafeCast.toInt256(actualShareRate) ); uint256 finalizationShareDeviation = (MAX_BASIS_POINTS * finalizationShareDiff) / actualShareRate; - if (finalizationShareDeviation > _limitsList.shareRateDeviationBPLimit) + + if (finalizationShareDeviation > _limitsList.shareRateDeviationBPLimit) { revert IncorrectFinalizationShareRate(finalizationShareDeviation); + } } function _grantRole(bytes32 _role, address[] memory _accounts) internal { From 69f174401a6165b9ce3e9574601c1810cf2484be Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 18 Feb 2023 20:47:30 +0300 Subject: [PATCH 098/199] chore: _checkLimitValue > instead of >= --- contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol b/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol index a2b2ccf26..90932feed 100644 --- a/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol +++ b/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol @@ -653,7 +653,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { } function _checkLimitValue(uint256 _value, uint256 _maxAllowedValue) internal pure { - if (_value >= _maxAllowedValue) { + if (_value > _maxAllowedValue) { revert IncorrectLimitValue(_value, _maxAllowedValue); } } From 113fb2934de6f0accd65b0d88b96e8ba8870069e Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Sat, 18 Feb 2023 20:53:45 +0200 Subject: [PATCH 099/199] oracles: fix: prevent re-submitting data for the same ref. slot again fixes #634 --- contracts/0.8.9/oracle/BaseOracle.sol | 8 ++++++++ .../oracle/accounting-oracle-happy-path.test.js | 14 ++++++++++++++ .../accounting-oracle-submit-report-data.test.js | 12 ++++++++++++ .../0.8.9/oracle/base-oracle-submit-report.test.js | 10 +++------- .../validators-exit-bus-oracle-happy-path.test.js | 7 +++++++ 5 files changed, 44 insertions(+), 7 deletions(-) diff --git a/contracts/0.8.9/oracle/BaseOracle.sol b/contracts/0.8.9/oracle/BaseOracle.sol index ce36c002e..1292db0d2 100644 --- a/contracts/0.8.9/oracle/BaseOracle.sol +++ b/contracts/0.8.9/oracle/BaseOracle.sol @@ -42,6 +42,7 @@ abstract contract BaseOracle is IReportAsyncProcessor, AccessControlEnumerable, error RefSlotMustBeGreaterThanProcessingOne(uint256 refSlot, uint256 processingRefSlot); error RefSlotCannotDecrease(uint256 refSlot, uint256 prevRefSlot); error ProcessingDeadlineMissed(uint256 deadline); + error RefSlotAlreadyProcessing(); error UnexpectedRefSlot(uint256 consensusRefSlot, uint256 dataRefSlot); error UnexpectedConsensusVersion(uint256 expectedVersion, uint256 receivedVersion); error UnexpectedDataHash(bytes32 consensusHash, bytes32 receivedHash); @@ -267,9 +268,16 @@ abstract contract BaseOracle is IReportAsyncProcessor, AccessControlEnumerable, /// function _startProcessing() internal returns (uint256) { _checkProcessingDeadline(); + ConsensusReport memory report = _storageConsensusReport().value; + uint256 prevProcessingRefSlot = LAST_PROCESSING_REF_SLOT_POSITION.getStorageUint256(); + if (prevProcessingRefSlot == report.refSlot) { + revert RefSlotAlreadyProcessing(); + } + LAST_PROCESSING_REF_SLOT_POSITION.setStorageUint256(report.refSlot); + emit ProcessingStarted(report.refSlot, report.hash); return prevProcessingRefSlot; } diff --git a/test/0.8.9/oracle/accounting-oracle-happy-path.test.js b/test/0.8.9/oracle/accounting-oracle-happy-path.test.js index b9838fac2..18bdc4939 100644 --- a/test/0.8.9/oracle/accounting-oracle-happy-path.test.js +++ b/test/0.8.9/oracle/accounting-oracle-happy-path.test.js @@ -258,6 +258,13 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { assert.equal(+lastLegacyOracleCall.clValidators, reportFields.numValidators) }) + it(`no data can be submitted for the same reference slot again`, async () => { + await assert.reverts( + oracle.submitReportData(reportItems, oracleVersion, {from: member2}), + 'RefSlotAlreadyProcessing()' + ) + }) + it('some time passes', async () => { const deadline = (await oracle.getConsensusReport()).processingDeadlineTime await consensus.setTime(deadline) @@ -345,5 +352,12 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { assert.equal(call3.nodeOperatorIds, '0x' + [2].map(i => hex(i, 8)).join('')) assert.equal(call3.keysCounts, '0x' + [3].map(i => hex(i, 16)).join('')) }) + + it(`extra data for the same reference slot cannot be re-submitted`, async () => { + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, {from: member1}), + 'ExtraDataAlreadyProcessed()' + ) + }) }) }) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js index b6336ce88..e724540a8 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-data.test.js @@ -192,6 +192,18 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) }) + context('only allows submitting main data for the same ref. slot once', () => { + it('reverts on trying to submit the second time', async () => { + const tx = await oracle.submitReportData(reportItems, oracleVersion, { from: member1 }) + assert.emits(tx, 'ProcessingStarted', { refSlot: reportFields.refSlot }) + + await assert.reverts( + oracle.submitReportData(reportItems, oracleVersion, { from: member1 }), + 'RefSlotAlreadyProcessing()' + ) + }) + }) + context('checks consensus version', () => { it('should revert if incorrect consensus version', async () => { await consensus.setTime(deadline) diff --git a/test/0.8.9/oracle/base-oracle-submit-report.test.js b/test/0.8.9/oracle/base-oracle-submit-report.test.js index 39003637c..feb145ea2 100644 --- a/test/0.8.9/oracle/base-oracle-submit-report.test.js +++ b/test/0.8.9/oracle/base-oracle-submit-report.test.js @@ -158,7 +158,7 @@ contract('BaseOracle', ([admin]) => { describe('_startProcessing safely advances processing state', () => { before(deployContract) - it('initial contract state,no reports, can not startProcessing', async () => { + it('initial contract state, no reports, cannot startProcessing', async () => { await assert.revertsWithCustomError(baseOracle.startProcessing(), 'ProcessingDeadlineMissed(0)') }) @@ -169,12 +169,8 @@ contract('BaseOracle', ([admin]) => { assert.emits(tx, 'MockStartProcessingResult', { prevProcessingRefSlot: '0' }) }) - it('no next report, processing same slot again, state is not changed', async () => { - const tx = await baseOracle.startProcessing() - assert.emits(tx, 'ProcessingStarted', { refSlot: initialRefSlot, hash: HASH_1 }) - assert.emits(tx, 'MockStartProcessingResult', { prevProcessingRefSlot: String(initialRefSlot) }) - const processingSlot = await baseOracle.getLastProcessingRefSlot() - assert.equals(processingSlot, initialRefSlot) + it('trying to start processing the same slot again reverts', async () => { + await assert.reverts(baseOracle.startProcessing(), 'RefSlotAlreadyProcessing()') }) it('next report comes in, start processing, state advances', async () => { diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-happy-path.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-happy-path.test.js index 1a4293154..9aa1f7fbc 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-happy-path.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-happy-path.test.js @@ -213,5 +213,12 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger assert.sameOrderedMembers(toNum(indices1), [2, -1, -1]) assert.sameOrderedMembers(toNum(indices2), [1, -1, -1]) }) + + it(`no data can be submitted for the same reference slot again`, async () => { + await assert.reverts( + oracle.submitReportData(reportItems, oracleVersion, {from: member2}), + 'RefSlotAlreadyProcessing()' + ) + }) }) }) From e769b9c8cc82375d3c33a84ee7cd349d173f15e4 Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Sat, 18 Feb 2023 21:06:27 +0200 Subject: [PATCH 100/199] oracles: remove incorrect test (fix copy-paste) --- test/0.8.9/oracle/base-oracle-access-control.test.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/0.8.9/oracle/base-oracle-access-control.test.js b/test/0.8.9/oracle/base-oracle-access-control.test.js index 2df45f632..9ea82362a 100644 --- a/test/0.8.9/oracle/base-oracle-access-control.test.js +++ b/test/0.8.9/oracle/base-oracle-access-control.test.js @@ -36,11 +36,6 @@ contract('BaseOracle', ([admin, account1, account2, member1, member2]) => { assert.isNotNull(oracle) assert.isNotNull(consensus) }) - - it('gives default roles', async () => { - const DEFAULT_ADMIN_ROLE = await oracle.DEFAULT_ADMIN_ROLE - await assert.emits(initTx, 'RoleGranted', { role: DEFAULT_ADMIN_ROLE, account: admin, sender: admin }) - }) }) context('MANAGE_CONSENSUS_CONTRACT_ROLE', () => { From 3201eb8c093fce9dbbc6d3d64f99d27453f26dea Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Sat, 18 Feb 2023 21:08:16 +0200 Subject: [PATCH 101/199] accounting oracle (code style): fix code layout --- contracts/0.8.9/oracle/AccountingOracle.sol | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/contracts/0.8.9/oracle/AccountingOracle.sol b/contracts/0.8.9/oracle/AccountingOracle.sol index 09c533d38..991548831 100644 --- a/contracts/0.8.9/oracle/AccountingOracle.sol +++ b/contracts/0.8.9/oracle/AccountingOracle.sol @@ -171,17 +171,6 @@ contract AccountingOracle is BaseOracle { _initialize(admin, consensusContract, consensusVersion, lastProcessingRefSlot); } - function _initialize( - address admin, - address consensusContract, - uint256 consensusVersion, - uint256 lastProcessingRefSlot - ) internal { - _setupRole(DEFAULT_ADMIN_ROLE, admin); - - BaseOracle._initialize(consensusContract, consensusVersion, lastProcessingRefSlot); - } - /// /// Data provider interface /// @@ -517,6 +506,17 @@ contract AccountingOracle is BaseOracle { return legacyProcessedEpoch * slotsPerEpoch; } + function _initialize( + address admin, + address consensusContract, + uint256 consensusVersion, + uint256 lastProcessingRefSlot + ) internal { + _setupRole(DEFAULT_ADMIN_ROLE, admin); + + BaseOracle._initialize(consensusContract, consensusVersion, lastProcessingRefSlot); + } + function _handleConsensusReport( ConsensusReport memory /* report */, uint256 /* prevSubmittedRefSlot */, From fece521c232b7cd6239dc57541d2877f3c292f15 Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Sat, 18 Feb 2023 21:12:01 +0200 Subject: [PATCH 102/199] tests: remove unused var --- test/0.8.9/oracle/base-oracle-access-control.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/0.8.9/oracle/base-oracle-access-control.test.js b/test/0.8.9/oracle/base-oracle-access-control.test.js index 9ea82362a..640093f26 100644 --- a/test/0.8.9/oracle/base-oracle-access-control.test.js +++ b/test/0.8.9/oracle/base-oracle-access-control.test.js @@ -16,7 +16,6 @@ const { const MockConsensusContract = artifacts.require('MockConsensusContract') contract('BaseOracle', ([admin, account1, account2, member1, member2]) => { - let initTx let oracle = null let consensus = null const manageConsensusContractRoleKeccak156 = web3.utils.keccak256('MANAGE_CONSENSUS_CONTRACT_ROLE') @@ -24,7 +23,6 @@ contract('BaseOracle', ([admin, account1, account2, member1, member2]) => { const deploy = async (options = undefined) => { const deployed = await deployBaseOracle(admin, options) - initTx = deployed.initTx oracle = deployed.oracle consensus = deployed.consensusContract } From 21aaf33c7cc83b53637b41bc9aeb80dc13e82d46 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 18 Feb 2023 22:12:13 +0300 Subject: [PATCH 103/199] test: revive some oracle tests --- .../oracle/accounting-oracle-submit-report-extra-data.test.js | 2 +- test/scenario/changing_oracles_during_epoch.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 3a7c49b55..d369aed3f 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -387,7 +387,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra } const problematicItemsCount = extraData.stuckKeys[problematicItemIdx].nodeOpIds.length const { extraDataList } = await prepareNextReportInNextFrame({ extraData }) - await oracleReportSanityChecker.setMaxAccountingExtraDataListItemsCount(problematicItemsCount - 1) + await oracleReportSanityChecker.setMaxNodeOperatorsPerExtraDataItemCount(problematicItemsCount - 1) await assert.reverts( oracle.submitReportExtraDataList(extraDataList, { from: member1 }), `TooManyNodeOpsPerExtraDataItem(${problematicItemIdx}, ${problematicItemsCount})` diff --git a/test/scenario/changing_oracles_during_epoch.js b/test/scenario/changing_oracles_during_epoch.js index d041a9ba6..53d8495be 100644 --- a/test/scenario/changing_oracles_during_epoch.js +++ b/test/scenario/changing_oracles_during_epoch.js @@ -38,7 +38,7 @@ contract('AccountingOracle', ([appManager, voting, malicious1, malicious2, membe lastWithdrawalRequestIdToFinalize: 0, finalizationShareRate: 0, isBunkerMode: false, - extraDataFormat: 1, + extraDataFormat: 0, extraDataHash: ZERO_HASH, extraDataItemsCount: 0 } From c0437d4ac4cfda9ec0b9ccc61d093ecc14c3a14a Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 18 Feb 2023 22:31:13 +0300 Subject: [PATCH 104/199] fix: update locator test stubs/structs --- test/helpers/locator-deploy.js | 2 ++ test/helpers/locator.js | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/helpers/locator-deploy.js b/test/helpers/locator-deploy.js index c54ff12ce..0ddd3e0ca 100644 --- a/test/helpers/locator-deploy.js +++ b/test/helpers/locator-deploy.js @@ -16,6 +16,7 @@ const invalidButNonZeroLocatorConfig = { validatorsExitBusOracle: DUMMY_ADDRESS, withdrawalQueue: DUMMY_ADDRESS, withdrawalVault: DUMMY_ADDRESS, + oracleDaemonConfig: DUMMY_ADDRESS } @@ -56,6 +57,7 @@ async function getLocatorConfig(locatorAddress) { validatorsExitBusOracle: await locator.validatorsExitBusOracle(), withdrawalQueue: await locator.withdrawalQueue(), withdrawalVault: await locator.withdrawalVault(), + oracleDaemonConfig: await locator.oracleDaemonConfig() } return config } diff --git a/test/helpers/locator.js b/test/helpers/locator.js index b4218c879..7b44d1897 100644 --- a/test/helpers/locator.js +++ b/test/helpers/locator.js @@ -14,7 +14,8 @@ const locatorServices = [ 'validatorsExitBusOracle', 'withdrawalQueue', 'withdrawalVault', - 'postTokenRebaseReceiver' + 'postTokenRebaseReceiver', + 'oracleDaemonConfig' ] function getRandomLocatorConfig(overrides = {}) { From 86987eb8e389fa2b78c6ece078ae3b9f81e92fd6 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 18 Feb 2023 22:32:57 +0300 Subject: [PATCH 105/199] chore: hashconsensus acl tests using evmsnapshot --- .../hash-consensus-access-control.test.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/0.8.9/oracle/hash-consensus-access-control.test.js b/test/0.8.9/oracle/hash-consensus-access-control.test.js index c4776fb6f..1da7ceb2d 100644 --- a/test/0.8.9/oracle/hash-consensus-access-control.test.js +++ b/test/0.8.9/oracle/hash-consensus-access-control.test.js @@ -1,5 +1,8 @@ +const hre = require('hardhat') + const { MaxUint256 } = require('@ethersproject/constants') const { assert } = require('../../helpers/assert') +const { EvmSnapshot } = require('../../helpers/blockchain') const { deployHashConsensus, EPOCHS_PER_FRAME, CONSENSUS_VERSION } = require('./hash-consensus-deploy.test') @@ -18,6 +21,9 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2]) => { const deployed = await deployHashConsensus(admin, options) consensus = deployed.consensus reportProcessor = deployed.reportProcessor + + snapshot = new EvmSnapshot(hre.ethers.provider) + await snapshot.make() } context('deploying', () => { @@ -29,9 +35,11 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2]) => { }) }) - context('MANAGE_MEMBERS_AND_QUORUM_ROLE', () => { - beforeEach(deploy) + afterEach(async () => { + await snapshot.rollback() + }) + context('MANAGE_MEMBERS_AND_QUORUM_ROLE', () => { context('addMember', () => { it('should revert without MANAGE_MEMBERS_AND_QUORUM_ROLE role', async () => { await assert.revertsOZAccessControl( @@ -106,8 +114,6 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2]) => { }) context('DISABLE_CONSENSUS_ROLE', () => { - beforeEach(deploy) - context('setQuorum', () => { it('should revert without DISABLE_CONSENSUS_ROLE role', async () => { await assert.revertsOZAccessControl( @@ -146,8 +152,6 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2]) => { }) context('MANAGE_FRAME_CONFIG_ROLE', () => { - beforeEach(deploy) - context('setFrameConfig', () => { it('should revert without MANAGE_FRAME_CONFIG_ROLE role', async () => { await assert.revertsOZAccessControl( @@ -168,8 +172,6 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2]) => { }) context('MANAGE_REPORT_PROCESSOR_ROLE', () => { - beforeEach(deploy) - context('setReportProcessor', async () => { const reportProcessor2 = await MockReportProcessor.new(CONSENSUS_VERSION, { from: admin }) @@ -191,8 +193,6 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2]) => { }) context('MANAGE_FAST_LANE_CONFIG_ROLE', () => { - beforeEach(deploy) - context('setFastLaneLengthSlots', () => { it('should revert without MANAGE_FAST_LANE_CONFIG_ROLE role', async () => { await assert.revertsOZAccessControl( From 5b2c9d8a90f42872b1e6bde0033dc38127ab6824 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 18 Feb 2023 22:39:41 +0300 Subject: [PATCH 106/199] test: +reportComponents of LidoLocator --- test/0.8.9/lido-locator.test.js | 42 +++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/0.8.9/lido-locator.test.js b/test/0.8.9/lido-locator.test.js index 030dbd55f..aea91152c 100644 --- a/test/0.8.9/lido-locator.test.js +++ b/test/0.8.9/lido-locator.test.js @@ -53,6 +53,27 @@ contract('LidoLocator', ([deployer, agent]) => { assert(actual === expected, 'coreComponents mismatch') } }) + + it('oracleReportComponentsForLido() matches', async () => { + const actualReportComponents = await lidoLocatorProxy.oracleReportComponentsForLido() + + const expectedReportComponents = [ + initialConfig.accountingOracle, + initialConfig.elRewardsVault, + initialConfig.oracleReportSanityChecker, + initialConfig.burner, + initialConfig.withdrawalQueue, + initialConfig.withdrawalVault, + initialConfig.postTokenRebaseReceiver + ] + + for (let i = 0; i < actualReportComponents.length; i++) { + const actual = actualReportComponents[i] + const expected = expectedReportComponents[i] + + assert(actual === expected, 'reportComponentsForLido mismatch') + } + }) }) describe('breaking constructor', () => { @@ -107,6 +128,27 @@ contract('LidoLocator', ([deployer, agent]) => { assert(actual === expected, 'coreComponents mismatch') } }) + + it('oracleReportComponentsForLido() matches', async () => { + const actualReportComponents = await lidoLocatorProxy.oracleReportComponentsForLido() + + const expectedReportComponents = [ + initialConfig.accountingOracle, + initialConfig.elRewardsVault, + initialConfig.oracleReportSanityChecker, + initialConfig.burner, + initialConfig.withdrawalQueue, + initialConfig.withdrawalVault, + initialConfig.postTokenRebaseReceiver + ] + + for (let i = 0; i < actualReportComponents.length; i++) { + const actual = actualReportComponents[i] + const expected = expectedReportComponents[i] + + assert(actual === expected, 'reportComponentsForLido mismatch') + } + }) }) }) }) From b18a1e7bc533693edb9fc3527a46007b5ab8ddfe Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 18 Feb 2023 23:05:46 +0300 Subject: [PATCH 107/199] doc: handleOracleReport with eth_call JSON-RPC API --- contracts/0.4.24/Lido.sol | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index 40fbe7657..9173f3929 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -564,10 +564,9 @@ contract Lido is Versioned, StETHPermit, AragonApp { * @param _lastFinalizableRequestId right boundary of requestId range if equals 0, no requests should be finalized * @param _simulatedShareRate share rate that was simulated by oracle when the report data created (1e27 precision) * - * NB: `_simulatedShareRate` should be calculated by the Oracle daemon - * invoking the method with static call and passing `_lastFinalizableRequestId` == `_simulatedShareRate` == 0 - * plugging the returned values to the following formula: - * `_simulatedShareRate = (postTotalPooledEther * 1e27) / postTotalShares` + * NB: `_simulatedShareRate` should be calculated off-chain by calling the method with `eth_call` JSON-RPC API + * while passing `_lastFinalizableRequestId` == `_simulatedShareRate` == 0, and plugging the returned values + * to the following formula: `_simulatedShareRate = (postTotalPooledEther * 1e27) / postTotalShares` * * @return postTotalPooledEther amount of ether in the protocol after report * @return postTotalShares amount of shares in the protocol after report From ce3bdabf77b4f570017342c0a6c7ecba2986e35a Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Sat, 18 Feb 2023 23:00:50 +0200 Subject: [PATCH 108/199] fix: replace _initializePausable() with _pause --- contracts/0.8.9/WithdrawalQueue.sol | 2 +- contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol | 2 +- contracts/0.8.9/utils/PausableUntil.sol | 6 ------ 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index e03e2fbb1..61c92101c 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -321,7 +321,7 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit internal { _initializeQueue(); - _initializePausable(); + _pause(PAUSE_INFINITELY); _initializeContractVersionTo(1); diff --git a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol index 1cb5cecf6..3d8557159 100644 --- a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol +++ b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol @@ -98,7 +98,7 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil { ) external { if (admin == address(0)) revert AdminCannotBeZero(); _setupRole(DEFAULT_ADMIN_ROLE, admin); - _initializePausable(); + _pause(PAUSE_INFINITELY); _initialize(consensusContract, consensusVersion, lastProcessingRefSlot); } diff --git a/contracts/0.8.9/utils/PausableUntil.sol b/contracts/0.8.9/utils/PausableUntil.sol index 76ccf160a..3bbd1b570 100644 --- a/contracts/0.8.9/utils/PausableUntil.sol +++ b/contracts/0.8.9/utils/PausableUntil.sol @@ -43,12 +43,6 @@ contract PausableUntil { return block.timestamp < RESUME_SINCE_TIMESTAMP_POSITION.getStorageUint256(); } - function _initializePausable() internal { - RESUME_SINCE_TIMESTAMP_POSITION.setStorageUint256(PAUSE_INFINITELY); - - emit Paused(PAUSE_INFINITELY); - } - function _resume() internal { RESUME_SINCE_TIMESTAMP_POSITION.setStorageUint256(block.timestamp); From c621c91fa0ef306738528a8e02d2d72ec95db6e7 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Sat, 18 Feb 2023 23:05:40 +0200 Subject: [PATCH 109/199] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F:=20skip=20grantRo?= =?UTF-8?q?le=20if=20zero=20address?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/0.8.9/WithdrawalQueue.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index 61c92101c..8b149e74e 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -326,10 +326,10 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit _initializeContractVersionTo(1); _grantRole(DEFAULT_ADMIN_ROLE, _admin); - _grantRole(PAUSE_ROLE, _pauser); - _grantRole(RESUME_ROLE, _resumer); - _grantRole(FINALIZE_ROLE, _finalizer); - _grantRole(BUNKER_MODE_REPORT_ROLE, _bunkerReporter); + if (_pauser != address(0)) _grantRole(PAUSE_ROLE, _pauser); + if (_resumer != address(0)) _grantRole(RESUME_ROLE, _resumer); + if (_finalizer != address(0)) _grantRole(FINALIZE_ROLE, _finalizer); + if (_bunkerReporter != address(0)) _grantRole(BUNKER_MODE_REPORT_ROLE, _bunkerReporter); BUNKER_MODE_SINCE_TIMESTAMP_POSITION.setStorageUint256(BUNKER_MODE_DISABLED_TIMESTAMP); From bdb8f78112ba895a5ffe9e51d4c12e081fe6126d Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Sat, 18 Feb 2023 23:10:57 +0200 Subject: [PATCH 110/199] fix: add assert to EnumerableSet remove --- contracts/0.8.9/WithdrawalQueueBase.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/0.8.9/WithdrawalQueueBase.sol b/contracts/0.8.9/WithdrawalQueueBase.sol index f2966443b..7d284df93 100644 --- a/contracts/0.8.9/WithdrawalQueueBase.sol +++ b/contracts/0.8.9/WithdrawalQueueBase.sol @@ -442,7 +442,7 @@ abstract contract WithdrawalQueueBase { if (_recipient == address(0)) _recipient = request.owner; request.claimed = true; - _getRequestsByOwner()[request.owner].remove(_requestId); + assert(_getRequestsByOwner()[request.owner].remove(_requestId)); DiscountCheckpoint memory hintCheckpoint = _getCheckpoints()[_hint]; // ______(_______ From 36693c125339a1ca344aff69cb515596745bf8f8 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Sat, 18 Feb 2023 23:19:59 +0200 Subject: [PATCH 111/199] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F:=20skip=20=5Fgran?= =?UTF-8?q?tRole=20for=20zero=20addresses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol index b3a1cb180..40a3498e4 100644 --- a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol +++ b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol @@ -100,8 +100,8 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil { ) external { if (admin == address(0)) revert AdminCannotBeZero(); _setupRole(DEFAULT_ADMIN_ROLE, admin); - _grantRole(PAUSE_ROLE, pauser); - _grantRole(RESUME_ROLE, resumer); + if (pauser != address(0)) _grantRole(PAUSE_ROLE, pauser); + if (resumer != address(0)) _grantRole(RESUME_ROLE, resumer); _pause(PAUSE_INFINITELY); _initialize(consensusContract, consensusVersion, lastProcessingRefSlot); From 91a9ffe795ecc447fcef546c0826db2222fa5752 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Sat, 18 Feb 2023 23:28:44 +0200 Subject: [PATCH 112/199] fix: add asserts to EnumerableSet operations --- contracts/0.8.9/WithdrawalQueueBase.sol | 2 +- contracts/0.8.9/WithdrawalQueueERC721.sol | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueueBase.sol b/contracts/0.8.9/WithdrawalQueueBase.sol index 10695fda8..ddce8c2dc 100644 --- a/contracts/0.8.9/WithdrawalQueueBase.sol +++ b/contracts/0.8.9/WithdrawalQueueBase.sol @@ -418,7 +418,7 @@ abstract contract WithdrawalQueueBase { _setLastRequestId(requestId); _getQueue()[requestId] = WithdrawalRequest(cumulativeStETH, cumulativeShares, payable(_owner), uint64(block.timestamp), false); - _getRequestsByOwner()[_owner].add(requestId); + assert(_getRequestsByOwner()[_owner].add(requestId)); emit WithdrawalRequested(requestId, msg.sender, _owner, _amountOfStETH, _amountOfShares); } diff --git a/contracts/0.8.9/WithdrawalQueueERC721.sol b/contracts/0.8.9/WithdrawalQueueERC721.sol index 46e46af43..52c3b648a 100644 --- a/contracts/0.8.9/WithdrawalQueueERC721.sol +++ b/contracts/0.8.9/WithdrawalQueueERC721.sol @@ -193,8 +193,8 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { delete _getTokenApprovals()[_requestId]; request.owner = payable(_to); - _getRequestsByOwner()[_from].remove(_requestId); - _getRequestsByOwner()[_to].add(_requestId); + assert(_getRequestsByOwner()[_from].remove(_requestId)); + assert(_getRequestsByOwner()[_to].add(_requestId)); _emitTransfer(_from, _to, _requestId); } From 8c16b5dedb74abee2dc597c47d431b33022cafcf Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sun, 19 Feb 2023 14:49:14 +0300 Subject: [PATCH 113/199] doc: provide an explainer about burn limits --- contracts/0.4.24/Lido.sol | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index 9173f3929..c558b710b 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -1209,7 +1209,7 @@ contract Lido is Versioned, StETHPermit, AragonApp { * (i.e., postpone the extra rewards to be applied during the next rounds) * 5. Invoke finalization of the withdrawal requests * 6. Distribute protocol fee (treasury & node operators) - * 7. Burn excess shares (withdrawn stETH at least) + * 7. Burn excess shares within the allowed limit (can postpone some shares to be burnt later) * 8. Complete token rebase by informing observers (emit an event and call the external receivers if any) * 9. Sanity check for the provided simulated share rate */ @@ -1294,8 +1294,9 @@ contract Lido is Versioned, StETHPermit, AragonApp { ); // Step 7. - // Burn excess shares (withdrawn stETH at least) - uint256 burntWithdrawalQueueShares = _burnSharesLimited( + // Burn excess shares within the allowed limit (can postpone some shares to be burnt later) + // Return actually burnt shares of the current report's finalized withdrawal requests to use in sanity checks + uint256 burntCurrentWithdrawalShares = _burnSharesLimited( IBurner(_contracts.burner), _contracts.withdrawalQueue, reportContext.sharesToBurnFromWithdrawalQueue, @@ -1319,7 +1320,7 @@ contract Lido is Versioned, StETHPermit, AragonApp { postTotalPooledEther, postTotalShares, reportContext.etherToLockOnWithdrawalQueue, - burntWithdrawalQueueShares, + burntCurrentWithdrawalShares, _reportedData.simulatedShareRate ); } @@ -1383,17 +1384,20 @@ contract Lido is Versioned, StETHPermit, AragonApp { /* * @dev Perform burning of `stETH` shares via the dedicated `Burner` contract. * - * NB: some of the burning amount can be postponed for the next reports - * if positive token rebase smoothened. + * NB: some of the burning amount can be postponed for the next reports if positive token rebase smoothened. + * It's possible that underlying shares of the current oracle report's finalized withdrawals won't be burnt + * completely in a single oracle report round due to the provided `_sharesToBurnLimit` limit * - * @return burnt shares from withdrawals queue (when some requests finalized) + * @return shares actually burnt for the current oracle report's finalized withdrawals + * these shares are assigned to be burnt most recently, so the amount can be calculated deducting + * `postponedSharesToBurn` shares (if any) after the burn commitment & execution */ function _burnSharesLimited( IBurner _burner, address _withdrawalQueue, uint256 _sharesToBurnFromWithdrawalQueue, uint256 _sharesToBurnLimit - ) internal returns (uint256 burntWithdrawalsShares) { + ) internal returns (uint256 burntCurrentWithdrawalShares) { if (_sharesToBurnFromWithdrawalQueue > 0) { _burner.requestBurnShares(_withdrawalQueue, _sharesToBurnFromWithdrawalQueue); } @@ -1409,7 +1413,7 @@ contract Lido is Versioned, StETHPermit, AragonApp { (uint256 coverShares, uint256 nonCoverShares) = _burner.getSharesRequestedToBurn(); uint256 postponedSharesToBurn = coverShares.add(nonCoverShares); - burntWithdrawalsShares = + burntCurrentWithdrawalShares = postponedSharesToBurn < _sharesToBurnFromWithdrawalQueue ? _sharesToBurnFromWithdrawalQueue - postponedSharesToBurn : 0; } From 616f4342165236c8176e60d58a5800206ec0b8ed Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sun, 19 Feb 2023 15:33:05 +0300 Subject: [PATCH 114/199] chore: revertsWithCustomError for hashconsensus --- test/0.8.9/oracle/hash-consensus-deploy.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/0.8.9/oracle/hash-consensus-deploy.test.js b/test/0.8.9/oracle/hash-consensus-deploy.test.js index b2ddd2f5f..f8bcd930a 100644 --- a/test/0.8.9/oracle/hash-consensus-deploy.test.js +++ b/test/0.8.9/oracle/hash-consensus-deploy.test.js @@ -127,7 +127,7 @@ contract('HashConsensus', ([admin, member1]) => { }) it('reverts if report processor address is zero', async () => { - await assert.reverts(HashConsensus.new( + await assert.revertsWithCustomError(HashConsensus.new( SLOTS_PER_EPOCH, SECONDS_PER_SLOT, GENESIS_TIME, @@ -144,7 +144,7 @@ contract('HashConsensus', ([admin, member1]) => { it('reverts if admin address is zero', async () => { const reportProcessor = await MockReportProcessor.new(CONSENSUS_VERSION, { from: admin }) - await assert.reverts(HashConsensus.new( + await assert.revertsWithCustomError(HashConsensus.new( SLOTS_PER_EPOCH, SECONDS_PER_SLOT, GENESIS_TIME, From f016373fbd39bd0ed18a7f5563ccd91c1ec3e711 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sun, 19 Feb 2023 15:33:52 +0300 Subject: [PATCH 115/199] refactor: simulated share rate naming everywhere --- .../OracleReportSanityChecker.sol | 46 +++++++++---------- lib/abi/OracleReportSanityChecker.json | 2 +- test/0.4.24/lido-handle-oracle-report.test.js | 2 +- .../oracle-report-sanity-checker.test.js | 22 ++++----- test/helpers/config.js | 2 +- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol b/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol index 90932feed..624ed8e37 100644 --- a/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol +++ b/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol @@ -43,10 +43,10 @@ struct LimitsList { /// @dev Represented in the Basis Points (100% == 10_000) uint256 annualBalanceIncreaseBPLimit; - /// @notice The max deviation of stETH.totalPooledEther() / stETH.totalShares() ratio since - /// the previous oracle report + /// @notice The max deviation of the provided `simulatedShareRate` + /// and the actual one within the currently processing oracle report /// @dev Represented in the Basis Points (100% == 10_000) - uint256 shareRateDeviationBPLimit; + uint256 simulatedShareRateDeviationBPLimit; /// @notice The max number of exit requests allowed in report to ValidatorsExitBusOracle uint256 maxValidatorExitRequestsPerReport; @@ -73,7 +73,7 @@ struct LimitsListPacked { uint16 churnValidatorsPerDayLimit; uint16 oneOffCLBalanceDecreaseBPLimit; uint16 annualBalanceIncreaseBPLimit; - uint16 shareRateDeviationBPLimit; + uint16 simulatedShareRateDeviationBPLimit; uint16 maxValidatorExitRequestsPerReport; uint16 maxAccountingExtraDataListItemsCount; uint16 maxNodeOperatorsPerExtraDataItemCount; @@ -242,15 +242,15 @@ contract OracleReportSanityChecker is AccessControlEnumerable { _updateLimits(limitsList); } - /// @notice Sets the new value for the shareRateDeviationBPLimit - /// @param _shareRateDeviationBPLimit new shareRateDeviationBPLimit value - function setShareRateDeviationBPLimit(uint256 _shareRateDeviationBPLimit) + /// @notice Sets the new value for the simulatedShareRateDeviationBPLimit + /// @param _simulatedShareRateDeviationBPLimit new simulatedShareRateDeviationBPLimit value + function setSimulatedShareRateDeviationBPLimit(uint256 _simulatedShareRateDeviationBPLimit) external onlyRole(SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE) { - _checkLimitValue(_shareRateDeviationBPLimit, MAX_BASIS_POINTS); + _checkLimitValue(_simulatedShareRateDeviationBPLimit, MAX_BASIS_POINTS); LimitsList memory limitsList = _limits.unpack(); - limitsList.shareRateDeviationBPLimit = _shareRateDeviationBPLimit; + limitsList.simulatedShareRateDeviationBPLimit = _simulatedShareRateDeviationBPLimit; _updateLimits(limitsList); } @@ -487,7 +487,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { // Pretending that withdrawals were not processed // virtually return locked ether back to postTotalPooledEther // virtually return burnt shares back to postTotalShares - _checkFinalizationShareRate( + _checkSimulatedShareRate( limitsList, _postTotalPooledEther + _etherLockedOnWithdrawalQueue, _postTotalShares + _sharesBurntFromWithdrawalQueue, @@ -580,7 +580,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { revert IncorrectRequestFinalization(requestTimestampToFinalizeUpTo); } - function _checkFinalizationShareRate( + function _checkSimulatedShareRate( LimitsList memory _limitsList, uint256 _noWithdrawalsPostTotalPooledEther, uint256 _noWithdrawalsPostTotalShares, @@ -592,16 +592,16 @@ contract OracleReportSanityChecker is AccessControlEnumerable { if (actualShareRate == 0) { // can't finalize anything if the actual share rate is zero - revert IncorrectFinalizationShareRate(MAX_BASIS_POINTS); + revert IncorrectSimulatedShareRate(MAX_BASIS_POINTS); } - uint256 finalizationShareDiff = Math256.abs( + uint256 simulatedShareDiff = Math256.abs( SafeCast.toInt256(_simulatedShareRate) - SafeCast.toInt256(actualShareRate) ); - uint256 finalizationShareDeviation = (MAX_BASIS_POINTS * finalizationShareDiff) / actualShareRate; + uint256 simulatedShareDeviation = (MAX_BASIS_POINTS * simulatedShareDiff) / actualShareRate; - if (finalizationShareDeviation > _limitsList.shareRateDeviationBPLimit) { - revert IncorrectFinalizationShareRate(finalizationShareDeviation); + if (simulatedShareDeviation > _limitsList.simulatedShareRateDeviationBPLimit) { + revert IncorrectSimulatedShareRate(simulatedShareDeviation); } } @@ -625,9 +625,9 @@ contract OracleReportSanityChecker is AccessControlEnumerable { _checkLimitValue(_newLimitsList.annualBalanceIncreaseBPLimit, type(uint16).max); emit AnnualBalanceIncreaseBPLimitSet(_newLimitsList.annualBalanceIncreaseBPLimit); } - if (_oldLimitsList.shareRateDeviationBPLimit != _newLimitsList.shareRateDeviationBPLimit) { - _checkLimitValue(_newLimitsList.shareRateDeviationBPLimit, type(uint16).max); - emit ShareRateDeviationBPLimitSet(_newLimitsList.shareRateDeviationBPLimit); + if (_oldLimitsList.simulatedShareRateDeviationBPLimit != _newLimitsList.simulatedShareRateDeviationBPLimit) { + _checkLimitValue(_newLimitsList.simulatedShareRateDeviationBPLimit, type(uint16).max); + emit SimulatedShareRateDeviationBPLimitSet(_newLimitsList.simulatedShareRateDeviationBPLimit); } if (_oldLimitsList.maxValidatorExitRequestsPerReport != _newLimitsList.maxValidatorExitRequestsPerReport) { _checkLimitValue(_newLimitsList.maxValidatorExitRequestsPerReport, type(uint16).max); @@ -661,7 +661,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { event ChurnValidatorsPerDayLimitSet(uint256 churnValidatorsPerDayLimit); event OneOffCLBalanceDecreaseBPLimitSet(uint256 oneOffCLBalanceDecreaseBPLimit); event AnnualBalanceIncreaseBPLimitSet(uint256 annualBalanceIncreaseBPLimit); - event ShareRateDeviationBPLimitSet(uint256 shareRateDeviationBPLimit); + event SimulatedShareRateDeviationBPLimitSet(uint256 simulatedShareRateDeviationBPLimit); event MaxPositiveTokenRebaseSet(uint256 maxPositiveTokenRebase); event MaxValidatorExitRequestsPerReportSet(uint256 maxValidatorExitRequestsPerReport); event MaxAccountingExtraDataListItemsCountSet(uint256 maxAccountingExtraDataListItemsCount); @@ -677,7 +677,7 @@ contract OracleReportSanityChecker is AccessControlEnumerable { error IncorrectNumberOfExitRequestsPerReport(uint256 maxRequestsCount); error IncorrectExitedValidators(uint256 churnLimit); error IncorrectRequestFinalization(uint256 requestCreationBlock); - error IncorrectFinalizationShareRate(uint256 finalizationShareDeviation); + error IncorrectSimulatedShareRate(uint256 simulatedShareDeviation); error MaxAccountingExtraDataItemsCountExceeded(uint256 maxItemsCount, uint256 receivedItemsCount); error ExitedValidatorsLimitExceeded(uint256 limitPerDay, uint256 exitedPerDay); error TooManyNodeOpsPerExtraDataItem(uint256 itemIndex, uint256 nodeOpsCount); @@ -688,7 +688,7 @@ library LimitsListPacker { res.churnValidatorsPerDayLimit = SafeCast.toUint16(_limitsList.churnValidatorsPerDayLimit); res.oneOffCLBalanceDecreaseBPLimit = _toBasisPoints(_limitsList.oneOffCLBalanceDecreaseBPLimit); res.annualBalanceIncreaseBPLimit = _toBasisPoints(_limitsList.annualBalanceIncreaseBPLimit); - res.shareRateDeviationBPLimit = _toBasisPoints(_limitsList.shareRateDeviationBPLimit); + res.simulatedShareRateDeviationBPLimit = _toBasisPoints(_limitsList.simulatedShareRateDeviationBPLimit); res.requestTimestampMargin = SafeCast.toUint64(_limitsList.requestTimestampMargin); res.maxPositiveTokenRebase = SafeCast.toUint64(_limitsList.maxPositiveTokenRebase); res.maxValidatorExitRequestsPerReport = SafeCast.toUint16(_limitsList.maxValidatorExitRequestsPerReport); @@ -707,7 +707,7 @@ library LimitsListUnpacker { res.churnValidatorsPerDayLimit = _limitsList.churnValidatorsPerDayLimit; res.oneOffCLBalanceDecreaseBPLimit = _limitsList.oneOffCLBalanceDecreaseBPLimit; res.annualBalanceIncreaseBPLimit = _limitsList.annualBalanceIncreaseBPLimit; - res.shareRateDeviationBPLimit = _limitsList.shareRateDeviationBPLimit; + res.simulatedShareRateDeviationBPLimit = _limitsList.simulatedShareRateDeviationBPLimit; res.requestTimestampMargin = _limitsList.requestTimestampMargin; res.maxPositiveTokenRebase = _limitsList.maxPositiveTokenRebase; res.maxValidatorExitRequestsPerReport = _limitsList.maxValidatorExitRequestsPerReport; diff --git a/lib/abi/OracleReportSanityChecker.json b/lib/abi/OracleReportSanityChecker.json index 0f65d65db..17a81a848 100644 --- a/lib/abi/OracleReportSanityChecker.json +++ b/lib/abi/OracleReportSanityChecker.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_lidoLocator","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"shareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"},{"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"internalType":"struct LimitsList","name":"_limitsList","type":"tuple"},{"components":[{"internalType":"address[]","name":"allLimitsManagers","type":"address[]"},{"internalType":"address[]","name":"churnValidatorsPerDayLimitManagers","type":"address[]"},{"internalType":"address[]","name":"oneOffCLBalanceDecreaseLimitManagers","type":"address[]"},{"internalType":"address[]","name":"annualBalanceIncreaseLimitManagers","type":"address[]"},{"internalType":"address[]","name":"shareRateDeviationLimitManagers","type":"address[]"},{"internalType":"address[]","name":"maxValidatorExitRequestsPerReportManagers","type":"address[]"},{"internalType":"address[]","name":"maxAccountingExtraDataListItemsCountManagers","type":"address[]"},{"internalType":"address[]","name":"maxNodeOperatorsPerExtraDataItemCountManagers","type":"address[]"},{"internalType":"address[]","name":"requestTimestampMarginManagers","type":"address[]"},{"internalType":"address[]","name":"maxPositiveTokenRebaseManagers","type":"address[]"}],"internalType":"struct OracleReportSanityChecker.ManagersRoster","name":"_managersRoster","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"limitPerDay","type":"uint256"},{"internalType":"uint256","name":"exitedPerDay","type":"uint256"}],"name":"ExitedValidatorsLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"churnLimit","type":"uint256"}],"name":"IncorrectAppearedValidators","type":"error"},{"inputs":[{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBP","type":"uint256"}],"name":"IncorrectCLBalanceDecrease","type":"error"},{"inputs":[{"internalType":"uint256","name":"annualBalanceDiff","type":"uint256"}],"name":"IncorrectCLBalanceIncrease","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualELRewardsVaultBalance","type":"uint256"}],"name":"IncorrectELRewardsVaultBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"churnLimit","type":"uint256"}],"name":"IncorrectExitedValidators","type":"error"},{"inputs":[{"internalType":"uint256","name":"finalizationShareDeviation","type":"uint256"}],"name":"IncorrectFinalizationShareRate","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"maxAllowedValue","type":"uint256"}],"name":"IncorrectLimitValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxRequestsCount","type":"uint256"}],"name":"IncorrectNumberOfExitRequestsPerReport","type":"error"},{"inputs":[{"internalType":"uint256","name":"requestCreationBlock","type":"uint256"}],"name":"IncorrectRequestFinalization","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualWithdrawalVaultBalance","type":"uint256"}],"name":"IncorrectWithdrawalsVaultBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxItemsCount","type":"uint256"},{"internalType":"uint256","name":"receivedItemsCount","type":"uint256"}],"name":"MaxAccountingExtraDataItemsCountExceeded","type":"error"},{"inputs":[],"name":"TooHighTokenRebaseLimit","type":"error"},{"inputs":[],"name":"TooLowTokenRebaseLimit","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"},{"internalType":"uint256","name":"nodeOpsCount","type":"uint256"}],"name":"TooManyNodeOpsPerExtraDataItem","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"}],"name":"AnnualBalanceIncreaseBPLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"}],"name":"ChurnValidatorsPerDayLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"}],"name":"MaxAccountingExtraDataListItemsCountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"}],"name":"MaxNodeOperatorsPerExtraDataItemCountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"name":"MaxPositiveTokenRebaseSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"}],"name":"MaxValidatorExitRequestsPerReportSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"}],"name":"OneOffCLBalanceDecreaseBPLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"}],"name":"RequestTimestampMarginSet","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":"shareRateDeviationBPLimit","type":"uint256"}],"name":"ShareRateDeviationBPLimitSet","type":"event"},{"inputs":[],"name":"ALL_LIMITS_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CHURN_VALIDATORS_PER_DAY_LIMIT_MANGER_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":"MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_extraDataListItemsCount","type":"uint256"}],"name":"checkAccountingExtraDataListItemsCount","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timeElapsed","type":"uint256"},{"internalType":"uint256","name":"_preCLBalance","type":"uint256"},{"internalType":"uint256","name":"_postCLBalance","type":"uint256"},{"internalType":"uint256","name":"_withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_preCLValidators","type":"uint256"},{"internalType":"uint256","name":"_postCLValidators","type":"uint256"}],"name":"checkAccountingOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_exitRequestsCount","type":"uint256"}],"name":"checkExitBusOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_exitedValidatorsCount","type":"uint256"}],"name":"checkExitedValidatorsRatePerDay","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_itemIndex","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorsCount","type":"uint256"}],"name":"checkNodeOperatorsPerExtraDataItemCount","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_postTotalPooledEther","type":"uint256"},{"internalType":"uint256","name":"_postTotalShares","type":"uint256"},{"internalType":"uint256","name":"_etherLockedOnWithdrawalQueue","type":"uint256"},{"internalType":"uint256","name":"_sharesBurntFromWithdrawalQueue","type":"uint256"},{"internalType":"uint256","name":"_simulatedShareRate","type":"uint256"}],"name":"checkSimulatedShareRate","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lastFinalizableRequestId","type":"uint256"},{"internalType":"uint256","name":"_reportTimestamp","type":"uint256"}],"name":"checkWithdrawalQueueOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLidoLocator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxPositiveTokenRebase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOracleReportLimits","outputs":[{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"shareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"},{"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"internalType":"struct LimitsList","name":"","type":"tuple"}],"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":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","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":"uint256","name":"_annualBalanceIncreaseBPLimit","type":"uint256"}],"name":"setAnnualBalanceIncreaseBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_churnValidatorsPerDayLimit","type":"uint256"}],"name":"setChurnValidatorsPerDayLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxAccountingExtraDataListItemsCount","type":"uint256"}],"name":"setMaxAccountingExtraDataListItemsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxValidatorExitRequestsPerReport","type":"uint256"}],"name":"setMaxExitRequestsPerOracleReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxNodeOperatorsPerExtraDataItemCount","type":"uint256"}],"name":"setMaxNodeOperatorsPerExtraDataItemCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPositiveTokenRebase","type":"uint256"}],"name":"setMaxPositiveTokenRebase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_oneOffCLBalanceDecreaseBPLimit","type":"uint256"}],"name":"setOneOffCLBalanceDecreaseBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"shareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"},{"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"internalType":"struct LimitsList","name":"_limitsList","type":"tuple"}],"name":"setOracleReportLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestTimestampMargin","type":"uint256"}],"name":"setRequestTimestampMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shareRateDeviationBPLimit","type":"uint256"}],"name":"setShareRateDeviationBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_preTotalPooledEther","type":"uint256"},{"internalType":"uint256","name":"_preTotalShares","type":"uint256"},{"internalType":"uint256","name":"_preCLBalance","type":"uint256"},{"internalType":"uint256","name":"_postCLBalance","type":"uint256"},{"internalType":"uint256","name":"_withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_etherToLockForWithdrawals","type":"uint256"}],"name":"smoothenTokenRebase","outputs":[{"internalType":"uint256","name":"withdrawals","type":"uint256"},{"internalType":"uint256","name":"elRewards","type":"uint256"},{"internalType":"uint256","name":"sharesToBurnLimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_lidoLocator","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"simulatedShareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"},{"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"internalType":"struct LimitsList","name":"_limitsList","type":"tuple"},{"components":[{"internalType":"address[]","name":"allLimitsManagers","type":"address[]"},{"internalType":"address[]","name":"churnValidatorsPerDayLimitManagers","type":"address[]"},{"internalType":"address[]","name":"oneOffCLBalanceDecreaseLimitManagers","type":"address[]"},{"internalType":"address[]","name":"annualBalanceIncreaseLimitManagers","type":"address[]"},{"internalType":"address[]","name":"shareRateDeviationLimitManagers","type":"address[]"},{"internalType":"address[]","name":"maxValidatorExitRequestsPerReportManagers","type":"address[]"},{"internalType":"address[]","name":"maxAccountingExtraDataListItemsCountManagers","type":"address[]"},{"internalType":"address[]","name":"maxNodeOperatorsPerExtraDataItemCountManagers","type":"address[]"},{"internalType":"address[]","name":"requestTimestampMarginManagers","type":"address[]"},{"internalType":"address[]","name":"maxPositiveTokenRebaseManagers","type":"address[]"}],"internalType":"struct OracleReportSanityChecker.ManagersRoster","name":"_managersRoster","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"limitPerDay","type":"uint256"},{"internalType":"uint256","name":"exitedPerDay","type":"uint256"}],"name":"ExitedValidatorsLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"churnLimit","type":"uint256"}],"name":"IncorrectAppearedValidators","type":"error"},{"inputs":[{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBP","type":"uint256"}],"name":"IncorrectCLBalanceDecrease","type":"error"},{"inputs":[{"internalType":"uint256","name":"annualBalanceDiff","type":"uint256"}],"name":"IncorrectCLBalanceIncrease","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualELRewardsVaultBalance","type":"uint256"}],"name":"IncorrectELRewardsVaultBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"churnLimit","type":"uint256"}],"name":"IncorrectExitedValidators","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"maxAllowedValue","type":"uint256"}],"name":"IncorrectLimitValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxRequestsCount","type":"uint256"}],"name":"IncorrectNumberOfExitRequestsPerReport","type":"error"},{"inputs":[{"internalType":"uint256","name":"requestCreationBlock","type":"uint256"}],"name":"IncorrectRequestFinalization","type":"error"},{"inputs":[{"internalType":"uint256","name":"simulatedShareDeviation","type":"uint256"}],"name":"IncorrectSimulatedShareRate","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualWithdrawalVaultBalance","type":"uint256"}],"name":"IncorrectWithdrawalsVaultBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxItemsCount","type":"uint256"},{"internalType":"uint256","name":"receivedItemsCount","type":"uint256"}],"name":"MaxAccountingExtraDataItemsCountExceeded","type":"error"},{"inputs":[],"name":"TooHighTokenRebaseLimit","type":"error"},{"inputs":[],"name":"TooLowTokenRebaseLimit","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"},{"internalType":"uint256","name":"nodeOpsCount","type":"uint256"}],"name":"TooManyNodeOpsPerExtraDataItem","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"}],"name":"AnnualBalanceIncreaseBPLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"}],"name":"ChurnValidatorsPerDayLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"}],"name":"MaxAccountingExtraDataListItemsCountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"}],"name":"MaxNodeOperatorsPerExtraDataItemCountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"name":"MaxPositiveTokenRebaseSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"}],"name":"MaxValidatorExitRequestsPerReportSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"}],"name":"OneOffCLBalanceDecreaseBPLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"}],"name":"RequestTimestampMarginSet","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":"simulatedShareRateDeviationBPLimit","type":"uint256"}],"name":"SimulatedShareRateDeviationBPLimitSet","type":"event"},{"inputs":[],"name":"ALL_LIMITS_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CHURN_VALIDATORS_PER_DAY_LIMIT_MANGER_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":"MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_extraDataListItemsCount","type":"uint256"}],"name":"checkAccountingExtraDataListItemsCount","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timeElapsed","type":"uint256"},{"internalType":"uint256","name":"_preCLBalance","type":"uint256"},{"internalType":"uint256","name":"_postCLBalance","type":"uint256"},{"internalType":"uint256","name":"_withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_preCLValidators","type":"uint256"},{"internalType":"uint256","name":"_postCLValidators","type":"uint256"}],"name":"checkAccountingOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_exitRequestsCount","type":"uint256"}],"name":"checkExitBusOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_exitedValidatorsCount","type":"uint256"}],"name":"checkExitedValidatorsRatePerDay","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_itemIndex","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorsCount","type":"uint256"}],"name":"checkNodeOperatorsPerExtraDataItemCount","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_postTotalPooledEther","type":"uint256"},{"internalType":"uint256","name":"_postTotalShares","type":"uint256"},{"internalType":"uint256","name":"_etherLockedOnWithdrawalQueue","type":"uint256"},{"internalType":"uint256","name":"_sharesBurntFromWithdrawalQueue","type":"uint256"},{"internalType":"uint256","name":"_simulatedShareRate","type":"uint256"}],"name":"checkSimulatedShareRate","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lastFinalizableRequestId","type":"uint256"},{"internalType":"uint256","name":"_reportTimestamp","type":"uint256"}],"name":"checkWithdrawalQueueOracleReport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLidoLocator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxPositiveTokenRebase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOracleReportLimits","outputs":[{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"simulatedShareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"},{"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"internalType":"struct LimitsList","name":"","type":"tuple"}],"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":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","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":"uint256","name":"_annualBalanceIncreaseBPLimit","type":"uint256"}],"name":"setAnnualBalanceIncreaseBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_churnValidatorsPerDayLimit","type":"uint256"}],"name":"setChurnValidatorsPerDayLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxAccountingExtraDataListItemsCount","type":"uint256"}],"name":"setMaxAccountingExtraDataListItemsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxValidatorExitRequestsPerReport","type":"uint256"}],"name":"setMaxExitRequestsPerOracleReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxNodeOperatorsPerExtraDataItemCount","type":"uint256"}],"name":"setMaxNodeOperatorsPerExtraDataItemCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPositiveTokenRebase","type":"uint256"}],"name":"setMaxPositiveTokenRebase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_oneOffCLBalanceDecreaseBPLimit","type":"uint256"}],"name":"setOneOffCLBalanceDecreaseBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"churnValidatorsPerDayLimit","type":"uint256"},{"internalType":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"annualBalanceIncreaseBPLimit","type":"uint256"},{"internalType":"uint256","name":"simulatedShareRateDeviationBPLimit","type":"uint256"},{"internalType":"uint256","name":"maxValidatorExitRequestsPerReport","type":"uint256"},{"internalType":"uint256","name":"maxAccountingExtraDataListItemsCount","type":"uint256"},{"internalType":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","type":"uint256"},{"internalType":"uint256","name":"requestTimestampMargin","type":"uint256"},{"internalType":"uint256","name":"maxPositiveTokenRebase","type":"uint256"}],"internalType":"struct LimitsList","name":"_limitsList","type":"tuple"}],"name":"setOracleReportLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestTimestampMargin","type":"uint256"}],"name":"setRequestTimestampMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_simulatedShareRateDeviationBPLimit","type":"uint256"}],"name":"setSimulatedShareRateDeviationBPLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_preTotalPooledEther","type":"uint256"},{"internalType":"uint256","name":"_preTotalShares","type":"uint256"},{"internalType":"uint256","name":"_preCLBalance","type":"uint256"},{"internalType":"uint256","name":"_postCLBalance","type":"uint256"},{"internalType":"uint256","name":"_withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"_etherToLockForWithdrawals","type":"uint256"}],"name":"smoothenTokenRebase","outputs":[{"internalType":"uint256","name":"withdrawals","type":"uint256"},{"internalType":"uint256","name":"elRewards","type":"uint256"},{"internalType":"uint256","name":"sharesToBurnLimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/test/0.4.24/lido-handle-oracle-report.test.js b/test/0.4.24/lido-handle-oracle-report.test.js index ea2d086e8..fb9cd8faf 100644 --- a/test/0.4.24/lido-handle-oracle-report.test.js +++ b/test/0.4.24/lido-handle-oracle-report.test.js @@ -12,7 +12,7 @@ const ORACLE_REPORT_LIMITS_BOILERPLATE = { churnValidatorsPerDayLimit: 255, oneOffCLBalanceDecreaseBPLimit: 100, annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, + simulatedShareRateDeviationBPLimit: 10000, maxValidatorExitRequestsPerReport: 10000, maxAccountingExtraDataListItemsCount: 10000, maxNodeOperatorsPerExtraDataItemCount: 10000, diff --git a/test/0.8.9/oracle-report-sanity-checker.test.js b/test/0.8.9/oracle-report-sanity-checker.test.js index 06871c0be..c464de2f9 100644 --- a/test/0.8.9/oracle-report-sanity-checker.test.js +++ b/test/0.8.9/oracle-report-sanity-checker.test.js @@ -38,7 +38,7 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa churnValidatorsPerDayLimit: 55, oneOffCLBalanceDecreaseBPLimit: 5_00, // 5% annualBalanceIncreaseBPLimit: 10_00, // 10% - shareRateDeviationBPLimit: 2_50, // 2.5% + simulatedShareRateDeviationBPLimit: 2_50, // 2.5% maxValidatorExitRequestsPerReport: 2000, maxAccountingExtraDataListItemsCount: 15, maxNodeOperatorsPerExtraDataItemCount: 16, @@ -82,7 +82,7 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa churnValidatorsPerDayLimit: 50, oneOffCLBalanceDecreaseBPLimit: 10_00, annualBalanceIncreaseBPLimit: 15_00, - shareRateDeviationBPLimit: 1_50, // 1.5% + simulatedShareRateDeviationBPLimit: 1_50, // 1.5% maxValidatorExitRequestsPerReport: 3000, maxAccountingExtraDataListItemsCount: 15 + 1, maxNodeOperatorsPerExtraDataItemCount: 16 + 1, @@ -93,7 +93,7 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa assert.notEquals(limitsBefore.churnValidatorsPerDayLimit, newLimitsList.churnValidatorsPerDayLimit) assert.notEquals(limitsBefore.oneOffCLBalanceDecreaseBPLimit, newLimitsList.oneOffCLBalanceDecreaseBPLimit) assert.notEquals(limitsBefore.annualBalanceIncreaseBPLimit, newLimitsList.annualBalanceIncreaseBPLimit) - assert.notEquals(limitsBefore.shareRateDeviationBPLimit, newLimitsList.shareRateDeviationBPLimit) + assert.notEquals(limitsBefore.simulatedShareRateDeviationBPLimit, newLimitsList.simulatedShareRateDeviationBPLimit) assert.notEquals(limitsBefore.maxValidatorExitRequestsPerReport, newLimitsList.maxValidatorExitRequestsPerReport) assert.notEquals(limitsBefore.maxAccountingExtraDataListItemsCount, newLimitsList.maxAccountingExtraDataListItemsCount) assert.notEquals(limitsBefore.maxNodeOperatorsPerExtraDataItemCount, newLimitsList.maxNodeOperatorsPerExtraDataItemCount) @@ -108,7 +108,7 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa assert.equals(limitsAfter.churnValidatorsPerDayLimit, newLimitsList.churnValidatorsPerDayLimit) assert.equals(limitsAfter.oneOffCLBalanceDecreaseBPLimit, newLimitsList.oneOffCLBalanceDecreaseBPLimit) assert.equals(limitsAfter.annualBalanceIncreaseBPLimit, newLimitsList.annualBalanceIncreaseBPLimit) - assert.equals(limitsAfter.shareRateDeviationBPLimit, newLimitsList.shareRateDeviationBPLimit) + assert.equals(limitsAfter.simulatedShareRateDeviationBPLimit, newLimitsList.simulatedShareRateDeviationBPLimit) assert.equals(limitsAfter.maxValidatorExitRequestsPerReport, newLimitsList.maxValidatorExitRequestsPerReport) assert.equals(limitsAfter.maxAccountingExtraDataListItemsCount, newLimitsList.maxAccountingExtraDataListItemsCount) assert.equals(limitsAfter.maxNodeOperatorsPerExtraDataItemCount, newLimitsList.maxNodeOperatorsPerExtraDataItemCount) @@ -260,22 +260,22 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa simulatedShareRate: (BigInt(2) * 10n ** 27n).toString() } - it('reverts with error IncorrectFinalizationShareRate() when reported and onchain share rate differs', async () => { - const finalizationShareRate = BigInt(ETH(2.10)) * 10n ** 9n + it('reverts with error IncorrectSimulatedShareRate() when reported and onchain share rate differs', async () => { + const simulatedShareRate = BigInt(ETH(2.10)) * 10n ** 9n const actualShareRate = BigInt(2) * 10n ** 27n - const deviation = (100_00n * (finalizationShareRate - actualShareRate)) / actualShareRate + const deviation = (100_00n * (simulatedShareRate - actualShareRate)) / actualShareRate await assert.revertsWithCustomError( oracleReportSanityChecker.checkSimulatedShareRate( ...Object.values({ ...correctSimulatedShareRate, - simulatedShareRate: finalizationShareRate.toString() + simulatedShareRate: simulatedShareRate.toString() }) ), - `IncorrectFinalizationShareRate(${deviation.toString()})` + `IncorrectSimulatedShareRate(${deviation.toString()})` ) }) - it('reverts with error IncorrectFinalizationShareRate() when actual share rate is zero', async () => { + it('reverts with error IncorrectSimulatedShareRate() when actual share rate is zero', async () => { const deviation = 100_00n await assert.revertsWithCustomError( oracleReportSanityChecker.checkSimulatedShareRate( @@ -285,7 +285,7 @@ contract('OracleReportSanityChecker', ([deployer, admin, withdrawalVault, elRewa postTotalPooledEther: ETH(0) }) ), - `IncorrectFinalizationShareRate(${deviation.toString()})` + `IncorrectSimulatedShareRate(${deviation.toString()})` ) }) diff --git a/test/helpers/config.js b/test/helpers/config.js index a760a27ad..c13fa9692 100644 --- a/test/helpers/config.js +++ b/test/helpers/config.js @@ -23,7 +23,7 @@ const DEFAULT_DEPLOY_PARAMS = { churnValidatorsPerDayLimit: 255, oneOffCLBalanceDecreaseBPLimit: 10000, annualBalanceIncreaseBPLimit: 10000, - shareRateDeviationBPLimit: 10000, + simulatedShareRateDeviationBPLimit: 10000, maxValidatorExitRequestsPerReport: 10000, maxAccountingExtraDataListItemsCount: 100, maxNodeOperatorsPerExtraDataItemCount: 100, From f11eb9ae7b2f044daebdca23fc974159c3cf2e61 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sun, 19 Feb 2023 16:00:59 +0300 Subject: [PATCH 116/199] chore: DONT_FINALIZE_WITHDRAWALS comment --- contracts/0.4.24/Lido.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index c558b710b..229d06535 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -160,7 +160,8 @@ contract Lido is Versioned, StETHPermit, AragonApp { uint256 private constant DEPOSIT_SIZE = 32 ether; uint256 public constant TOTAL_BASIS_POINTS = 10000; - /// @dev special value for the last finalizable withdrawal request id + /// @dev special value to not finalize withdrawal requests + /// see the `_lastFinalizableRequestId` arg for `handleOracleReport()` uint256 private constant DONT_FINALIZE_WITHDRAWALS = 0; /// @dev storage slot position for the Lido protocol contracts locator From 55c2b09f2a9e263666bae04c9e82c210477f71c1 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sun, 19 Feb 2023 16:04:34 +0300 Subject: [PATCH 117/199] chore: improve doc for 'checkSimulatedShareRate' --- .../0.8.9/sanity_checks/OracleReportSanityChecker.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol b/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol index 624ed8e37..f15e06e5d 100644 --- a/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol +++ b/contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol @@ -472,9 +472,9 @@ contract OracleReportSanityChecker is AccessControlEnumerable { /// @notice Applies sanity checks to the simulated share rate for withdrawal requests finalization /// @param _postTotalPooledEther total pooled ether after report applied /// @param _postTotalShares total shares after report applied - /// @param _etherLockedOnWithdrawalQueue ether to lock on withdrawal queue - /// @param _sharesBurntFromWithdrawalQueue shares assigned to burn from withdrawal queue - /// @param _simulatedShareRate share rate provided with the oracle report (simulated via static call) + /// @param _etherLockedOnWithdrawalQueue ether locked on withdrawal queue for the current oracle report + /// @param _sharesBurntFromWithdrawalQueue shares burnt from withdrawal queue for the current oracle report + /// @param _simulatedShareRate share rate provided with the oracle report (simulated via off-chain "eth_call") function checkSimulatedShareRate( uint256 _postTotalPooledEther, uint256 _postTotalShares, @@ -485,8 +485,8 @@ contract OracleReportSanityChecker is AccessControlEnumerable { LimitsList memory limitsList = _limits.unpack(); // Pretending that withdrawals were not processed - // virtually return locked ether back to postTotalPooledEther - // virtually return burnt shares back to postTotalShares + // virtually return locked ether back to `_postTotalPooledEther` + // virtually return burnt just finalized withdrawals shares back to `_postTotalShares` _checkSimulatedShareRate( limitsList, _postTotalPooledEther + _etherLockedOnWithdrawalQueue, From 14503a5a9c7c46864704bb3561e22ae2f84a04ff Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Sun, 19 Feb 2023 18:56:11 +0400 Subject: [PATCH 118/199] Minor deposit methods changes --- contracts/0.4.24/Lido.sol | 32 +++++++------------ .../0.4.24/nos/NodeOperatorsRegistry.sol | 3 +- contracts/0.8.9/BeaconChainDepositor.sol | 27 ++++++++-------- contracts/0.8.9/StakingRouter.sol | 3 +- test/0.4.24/node-operators-registry.test.js | 12 +++---- 5 files changed, 34 insertions(+), 43 deletions(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index 1912486b1..1516d4ced 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -677,11 +677,10 @@ contract Lido is Versioned, StETHPermit, AragonApp { * @dev Returns depositable ether amount. * Takes into account unfinalized stETH required by WithdrawalQueue */ - function getDepositableEther() public view returns (uint256 depositableEther) { + function getDepositableEther() public view returns (uint256) { uint256 bufferedEther = _getBufferedEther(); uint256 withdrawalReserve = IWithdrawalQueue(getLidoLocator().withdrawalQueue()).unfinalizedStETH(); - - depositableEther = bufferedEther > withdrawalReserve ? bufferedEther - withdrawalReserve : 0; + return bufferedEther > withdrawalReserve ? bufferedEther - withdrawalReserve : 0; } /** @@ -702,20 +701,21 @@ contract Lido is Versioned, StETHPermit, AragonApp { stakingRouter.getStakingModuleMaxDepositsCount(_stakingModuleId, getDepositableEther()) ); if (depositsCount == 0) return; + uint256 depositsValue = depositsCount.mul(DEPOSIT_SIZE); + /// @dev firstly update the local state of the contract to prevent a reentrancy attack, + /// even if the StakingRouter is a trusted contract. + BUFFERED_ETHER_POSITION.setStorageUint256(_getBufferedEther().sub(depositsValue)); + emit Unbuffered(depositsValue); - /// @dev At first update the local state of the contract to reduce the chances of the - /// reentrancy attack, even though the StakingRouter is a trusted contract - _markAsUnbuffered(depositsValue); + uint256 newDepositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256().add(depositsCount); + DEPOSITED_VALIDATORS_POSITION.setStorageUint256(newDepositedValidators); + emit DepositedValidatorsChanged(newDepositedValidators); /// @dev transfer ether to StakingRouter and make a deposit at the same time. All the ether /// sent to StakingRouter is counted as deposited. If StakingRouter can't deposit all - /// passed ether it will revert the whole transaction + /// passed ether it MUST revert the whole transaction (never happens in normal circumstances) stakingRouter.deposit.value(depositsValue)(depositsCount, _stakingModuleId, _depositCalldata); - - uint256 newDepositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256().add(depositsCount); - DEPOSITED_VALIDATORS_POSITION.setStorageUint256(newDepositedValidators); - emit DepositedValidatorsChanged(newDepositedValidators); } /// DEPRECATED PUBLIC METHODS @@ -1077,16 +1077,6 @@ contract Lido is Versioned, StETHPermit, AragonApp { _emitTransferAfterMintingShares(treasury, treasuryReward); } - /** - * @dev Records a deposit to the deposit_contract.deposit function - * @param _amount Total amount deposited to the Consensus Layer side - */ - function _markAsUnbuffered(uint256 _amount) internal { - BUFFERED_ETHER_POSITION.setStorageUint256(_getBufferedEther().sub(_amount)); - - emit Unbuffered(_amount); - } - /** * @dev Gets the amount of Ether temporary buffered on this contract balance */ diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 3c8879d5a..890621a6b 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -635,7 +635,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256[] memory activeKeysCountAfterAllocation ) = _getSigningKeysAllocationData(_depositsCount); - require(allocatedKeysCount == _depositsCount, "INSUFFICIENT_KEYS_COUNT"); + require(allocatedKeysCount == _depositsCount, "INVALID_ALLOCATED_KEYS_COUNT"); (publicKeys, signatures) = _loadAllocatedSigningKeys( allocatedKeysCount, @@ -734,6 +734,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { allocatedKeysCount = MinFirstAllocationStrategy.allocate(activeKeyCountsAfterAllocation, activeKeysCapacities, uint64(_keysCount)); + /// @dev method NEVER allocates more keys than was requested assert(allocatedKeysCount <= _keysCount); } diff --git a/contracts/0.8.9/BeaconChainDepositor.sol b/contracts/0.8.9/BeaconChainDepositor.sol index 7ec67f755..4bcd2f5f3 100644 --- a/contracts/0.8.9/BeaconChainDepositor.sol +++ b/contracts/0.8.9/BeaconChainDepositor.sol @@ -44,10 +44,12 @@ contract BeaconChainDepositor { bytes memory _publicKeysBatch, bytes memory _signaturesBatch ) internal { - require(_publicKeysBatch.length == PUBLIC_KEY_LENGTH * _keysCount, "INVALID_PUBLIC_KEYS_BATCH_LENGTH"); - require(_signaturesBatch.length == SIGNATURE_LENGTH * _keysCount, "INVALID_SIGNATURES_BATCH_LENGTH"); - - uint256 targetBalance = address(this).balance - (_keysCount * DEPOSIT_SIZE); + if (_publicKeysBatch.length != PUBLIC_KEY_LENGTH * _keysCount) { + revert InvalidPublicKeysBatchLength(_publicKeysBatch.length, PUBLIC_KEY_LENGTH * _keysCount); + } + if (_signaturesBatch.length != SIGNATURE_LENGTH * _keysCount) { + revert InvalidSignaturesBatchLength(_signaturesBatch.length, SIGNATURE_LENGTH * _keysCount); + } bytes memory publicKey = MemUtils.unsafeAllocateBytes(PUBLIC_KEY_LENGTH); bytes memory signature = MemUtils.unsafeAllocateBytes(SIGNATURE_LENGTH); @@ -64,8 +66,6 @@ contract BeaconChainDepositor { ++i; } } - - if (address(this).balance != targetBalance) revert NotExpectedBalance(); } /// @dev computes the deposit_root_hash required by official Beacon Deposit contract @@ -80,19 +80,20 @@ contract BeaconChainDepositor { bytes memory sigPart1 = MemUtils.unsafeAllocateBytes(64); bytes memory sigPart2 = MemUtils.unsafeAllocateBytes(SIGNATURE_LENGTH - 64); MemUtils.copyBytes(_signature, sigPart1, 0, 0, 64); - MemUtils.copyBytes(_signature, sigPart2, 64, 0,SIGNATURE_LENGTH - 64); + MemUtils.copyBytes(_signature, sigPart2, 64, 0, SIGNATURE_LENGTH - 64); bytes32 publicKeyRoot = sha256(abi.encodePacked(_publicKey, bytes16(0))); bytes32 signatureRoot = sha256(abi.encodePacked(sha256(abi.encodePacked(sigPart1)), sha256(abi.encodePacked(sigPart2, bytes32(0))))); return sha256( - abi.encodePacked( - sha256(abi.encodePacked(publicKeyRoot, _withdrawalCredentials)), - sha256(abi.encodePacked(DEPOSIT_SIZE_IN_GWEI_LE64, bytes24(0), signatureRoot)) - ) - ); + abi.encodePacked( + sha256(abi.encodePacked(publicKeyRoot, _withdrawalCredentials)), + sha256(abi.encodePacked(DEPOSIT_SIZE_IN_GWEI_LE64, bytes24(0), signatureRoot)) + ) + ); } error DepositContractZeroAddress(); - error NotExpectedBalance(); + error InvalidPublicKeysBatchLength(uint256 actual, uint256 expected); + error InvalidSignaturesBatchLength(uint256 actual, uint256 expected); } diff --git a/contracts/0.8.9/StakingRouter.sol b/contracts/0.8.9/StakingRouter.sol index 40dfbfef6..b7a2b0ea6 100644 --- a/contracts/0.8.9/StakingRouter.sol +++ b/contracts/0.8.9/StakingRouter.sol @@ -50,7 +50,6 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version uint256 currentNodeOpStuckValidatorsCount ); error InvalidDepositsValue(uint256 etherValue); - error DepositsCountMismatch(uint256 desiredDepositsCount, uint256 actualDepositsCount); enum StakingModuleStatus { Active, // deposits and rewards allowed @@ -1018,7 +1017,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version ); uint256 etherBalanceAfterDeposits = address(this).balance; - /// @dev make sure that was deposited exactly sent amount of ETH + /// @dev all sent ETH must be deposited and self balance stay the same assert(etherBalanceBeforeDeposits - etherBalanceAfterDeposits == depositsValue); stakingModule.lastDepositAt = uint64(block.timestamp); diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index 61a136804..bb86a1186 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -1834,15 +1834,15 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await assert.reverts(app.obtainDepositData(10, '0x', { from: nobody }), 'APP_AUTH_FAILED') }) - it('reverts with error "INSUFFICIENT_KEYS_COUNT" when no validators to deposit to', async () => { + it('reverts with error "INVALID_ALLOCATED_KEYS_COUNT" when no validators to deposit to', async () => { await app.testing_resetRegistry() const nodeOperatorsCount = await app.getNodeOperatorsCount() assert.equals(nodeOperatorsCount, 0) const keysToAllocate = 10 - await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INSUFFICIENT_KEYS_COUNT') + await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INVALID_ALLOCATED_KEYS_COUNT') }) - it('reverts with error "INSUFFICIENT_KEYS_COUNT" when module has not enough keys', async () => { + it('reverts with error "INVALID_ALLOCATED_KEYS_COUNT" when module has not enough keys', async () => { await app.testing_resetRegistry() await app.addNodeOperator('fo o', ADDRESS_1, { from: voting }) @@ -1861,7 +1861,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals(stakingModuleSummary.depositableValidatorsCount, 6) const keysToAllocate = 7 - await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INSUFFICIENT_KEYS_COUNT') + await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INVALID_ALLOCATED_KEYS_COUNT') }) it('loads correct signing keys', async () => { @@ -1913,7 +1913,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals(stakingModuleSummary.depositableValidatorsCount, 3) keysToAllocate = 10 - await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INSUFFICIENT_KEYS_COUNT') + await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INVALID_ALLOCATED_KEYS_COUNT') keysToAllocate = 3 receipt = await app.testing_obtainDepositData(keysToAllocate) @@ -1934,7 +1934,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals(stakingModuleSummary.depositableValidatorsCount, 0) keysToAllocate = 1 - await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INSUFFICIENT_KEYS_COUNT') + await assert.reverts(app.testing_obtainDepositData(keysToAllocate), 'INVALID_ALLOCATED_KEYS_COUNT') }) it('increases keysOpIndex & changes nonce', async () => { From 5333cfe15e860e7513fbc51095221de6e94736dd Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Sun, 19 Feb 2023 18:58:19 +0400 Subject: [PATCH 119/199] Add GenericStub test contract --- contracts/0.8.9/test_helpers/GenericStub.sol | 179 +++++++++++++++++++ test/helpers/stubs/generic.stub.js | 123 +++++++++++++ 2 files changed, 302 insertions(+) create mode 100644 contracts/0.8.9/test_helpers/GenericStub.sol create mode 100644 test/helpers/stubs/generic.stub.js diff --git a/contracts/0.8.9/test_helpers/GenericStub.sol b/contracts/0.8.9/test_helpers/GenericStub.sol new file mode 100644 index 000000000..efe6ac186 --- /dev/null +++ b/contracts/0.8.9/test_helpers/GenericStub.sol @@ -0,0 +1,179 @@ +// SPDX-FileCopyrightText: 2023 Lido +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity 0.8.9; + +enum LogType { + LOG0, + LOG1, + LOG2, + LOG3, + LOG4 +} + +contract ETHForwarder { + constructor(address payable _recipient) payable { + selfdestruct(_recipient); + } +} + +contract GenericStub { + type MethodID is bytes4; + type InputHash is bytes32; + type Topic is bytes32; + + // InputHash private immutable WILDCARD_INPUT_HASH; + + struct Log { + LogType logType; + bytes data; + bytes32 t1; + bytes32 t2; + bytes32 t3; + bytes32 t4; + } + + struct ETHForward { + address payable recipient; + uint256 value; + } + + struct MethodStub { + /// @notice msg.data used for call + bytes input; + /// @notice abi encoded data to be returned from the method + bytes output; + /// @notice events to emit during method execution + Log[] logs; + /// @notice optional ETH send on method execution + ETHForward ethForward; + /// @notice shall method ends with revert instead of return + bool isRevert; + /// @notice index of the state to set as current after stub call + /// @dev this value is one based + uint256 nextStateIndexOneBased; + } + + struct StubState { + /// @notice list of all stubs (order is not guaranteed) + MethodStub[] stubs; + /// @notice indices of stubs increased to 1 + mapping(bytes32 => uint256) indicesByIdOneBased; + } + + StubState[] private _states; + uint256 private _currentStateIndexOneBased = 1; + + constructor() { + _states.push(); + } + + function GenericStub__addStub(MethodStub memory _stub) external { + StubState storage currentState = _getState(_currentStateIndexOneBased - 1); + currentState.stubs.push(); + bytes32 stubId = keccak256(_stub.input); + uint256 newStubIndex = currentState.stubs.length - 1; + currentState.stubs[newStubIndex].input = _stub.input; + currentState.stubs[newStubIndex].output = _stub.output; + currentState.stubs[newStubIndex].ethForward = _stub.ethForward; + currentState.stubs[newStubIndex].isRevert = _stub.isRevert; + currentState.stubs[newStubIndex].nextStateIndexOneBased = _stub.nextStateIndexOneBased; + + for(uint256 i = 0; i < _stub.logs.length; ++i) { + currentState.stubs[newStubIndex].logs.push(_stub.logs[i]); + } + currentState.indicesByIdOneBased[stubId] = newStubIndex + 1; + } + + function GenericStub__addState() external { + _states.push(); + _currentStateIndexOneBased = _states.length; + } + + function GenericStub__setState(uint256 _stateIndex) external { + require(_stateIndex != 0, "INVALID_INDEX"); + if (_stateIndex > _states.length) { + revert GenericStub__StateIndexOutOfBounds(_stateIndex, _states.length); + } + _currentStateIndexOneBased = _stateIndex; + } + + + // function GenericStub__cloneState(uint256 _clonedStateIndex) external { + // _states.push(_getState(_clonedStateIndex)); + // } + + + fallback() external payable { + MethodStub memory stub = _getMethodStub(); + _forwardETH(stub.ethForward); + _logEvents(stub.logs); + bytes memory output = stub.output; + uint256 outputLength = output.length; + if (stub.nextStateIndexOneBased != 0) { + _currentStateIndexOneBased = stub.nextStateIndexOneBased; + } + if (stub.isRevert) { + assembly { revert(add(output, 32), outputLength) } + } + assembly { return(add(output, 32), outputLength) } + } + + function _logEvents(Log[] memory _logs) internal { + for (uint256 i = 0; i < _logs.length; ++i) { + bytes32 t1 = _logs[i].t1; + bytes32 t2 = _logs[i].t2; + bytes32 t3 = _logs[i].t3; + bytes32 t4 = _logs[i].t4; + bytes memory data = _logs[i].data; + uint256 dataLength = data.length; + if (_logs[i].logType == LogType.LOG0) { + assembly { log0(data, dataLength) } + } else if (_logs[i].logType == LogType.LOG1) { + assembly { log1(data, dataLength, t1) } + } else if (_logs[i].logType == LogType.LOG2) { + assembly { log2(data, dataLength, t1, t2) } + } else if (_logs[i].logType == LogType.LOG3) { + assembly { log3(data, dataLength, t1, t2, t3) } + } else if (_logs[i].logType == LogType.LOG4) { + assembly { log4(data, dataLength, t1, t2, t3, t4) } + } + } + } + + function _forwardETH(ETHForward memory _ethForward) internal { + if (_ethForward.value == 0) return; + new ETHForwarder{value: _ethForward.value}(_ethForward.recipient); + emit GenericStub__ethSent(_ethForward.recipient, _ethForward.value); + } + + function _getMethodStub() internal view returns (MethodStub memory) { + StubState storage currentState = _getState(_currentStateIndexOneBased - 1); + bytes32 methodStubId = keccak256(msg.data); + bytes32 methodStubWildcardId = keccak256(msg.data[:4]); + + uint256 methodStubIndex = currentState.indicesByIdOneBased[methodStubId]; + uint256 methodStubWildcardIndex = currentState.indicesByIdOneBased[methodStubWildcardId]; + + if (methodStubIndex == 0 && methodStubWildcardIndex == 0) { + revert GenericStub__MethodStubIsNotDefined(msg.data); + } + + return methodStubIndex != 0 + ? currentState.stubs[methodStubIndex - 1] + : currentState.stubs[methodStubWildcardIndex - 1]; + } + + function _getState(uint256 _stateIndex) internal view returns (StubState storage) { + if (_stateIndex >= _states.length) { + revert GenericStub__StateIndexOutOfBounds(_stateIndex, _states.length); + } + return _states[_stateIndex]; + } + + event GenericStub__ethSent(address recipient, uint256 value); + + error GenericStub__StateIndexOutOfBounds(uint256 index, uint256 length); + error GenericStub__MethodStubIsNotDefined(bytes callData); + error GenericStub__ETHSendFailed(address recipient, uint256 value); +} \ No newline at end of file diff --git a/test/helpers/stubs/generic.stub.js b/test/helpers/stubs/generic.stub.js new file mode 100644 index 000000000..ee22e435f --- /dev/null +++ b/test/helpers/stubs/generic.stub.js @@ -0,0 +1,123 @@ +const hre = require('hardhat') +const { ZERO_ADDRESS } = require('../constants') + +class GenericStub { + static GenericStubContract = hre.artifacts.require('GenericStub') + + static async new(contractName) { + const stubInstance = await GenericStub.GenericStubContract.new() + const StubbedContractFactory = hre.artifacts.require(contractName) + return StubbedContractFactory.at(stubInstance.address) + } + + static async addState(stubbedContract) { + const stubInstance = await GenericStub.GenericStubContract.at(stubbedContract.address) + await stubInstance.GenericStub__addState() + } + + static async setState(stubbedContract, stateIndex) { + const stubInstance = await GenericStub.GenericStubContract.at(stubbedContract.address) + await stubInstance.GenericStub__setState(stateIndex) + } + + /** + * @typedef {object} TypedTuple - stores a info about tuple type & value + * @property {string[]} - tuple with type names + * @property {any[]} - tuple with values for types + * + * @param {object} stubbedContract instance of the GenericStub contract to add stub + * + * @param {string} methodName name of the method to stub + * + * @param {object} config stubbed method params + * @param {TypedTuple} [config.input] the input value to trigger the stub + * @param {TypedTuple} [config.return] the output value to return or revert from stub + * @param {object} [config.revert] the revert info when stub must finish with error + * @param {string} [config.revert.reason] the revert reason. Used when method reverts with string message + * @param {string} [config.revert.error] the custom error name when method must revert with custom error + * @param {TypedTuple} [config.revert.args] the arguments info for custom error + * @param {object} [config.forwardETH] amount and recipient where to send ETH + * @param {string} config.forwardETH.recipient recipient address of the ETH + * @param {object} config.forwardETH.value amount of ETH to send + * @param {number} [config.nextState] one based state index to set after stub call + */ + static async stub(stubbedContract, methodName, config = {}) { + const stubInstance = await GenericStub.GenericStubContract.at(stubbedContract.address) + + const { abi: abis } = stubbedContract + const methodAbis = abis.filter((abi) => abi.type === 'function' && abi.name === methodName) + if (methodAbis.length > 1) { + throw new Error('Support of methods overloading has not implemented yet') + } + const [methodAbi] = methodAbis + + const configParser = new GenericStubConfigParser() + const parsedConfig = configParser.parse(methodAbi.signature, config) + await stubInstance.GenericStub__addStub(Object.values(parsedConfig)) + } +} + +module.exports = { + GenericStub +} + +class GenericStubConfigParser { + parse(methodSignature, config) { + return { + input: this._parseInput(methodSignature, config), + output: this._parseOutput(config), + logs: this._parseLogs(config), + forwardETH: this._parseForwardETH(config), + isRevert: this._parseIsRevert(config), + nextState: this._parseNextState(config) + } + } + + _parseInput(methodSignature, config) { + return methodSignature + this._encode(config.input || { type: [], value: [] }).slice(2) + } + + _parseOutput(config) { + if (config.return) { + return this._encode(config.return) + } + if (config.revert) { + return config.revert.error + ? this._encodeError(config.revert.error) + : this._encodeError({ error: 'Error', args: { type: ['string'], value: [config.revert.reason || ''] } }) + } + return this._encode({ type: [], value: [] }) + } + + // TODO: implement + _parseLogs(config) { + return [] + } + + _parseForwardETH(config) { + const { forwardETH = { recipient: ZERO_ADDRESS, value: 0 } } = config + return [forwardETH.recipient, forwardETH.value] + } + + _parseIsRevert(config) { + return !!config.revert + } + + _parseNextState(config) { + return config.nextState || 0 + } + + _encode({ type, value }) { + return hre.ethers.utils.defaultAbiCoder.encode(type, value) + } + + _encodeError({ error, args }) { + const signature = this._signature(error, args.type) + return signature + this._encode(args).slice(2) + } + + _signature(name, argTypes) { + const fullName = `${name}(${argTypes.join(',')})` + return hre.ethers.utils.keccak256(hre.ethers.utils.toUtf8Bytes(fullName)).slice(0, 10) + } +} From 6be4dbb61764a58b8e4af0531445f306ef35c03f Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Sun, 19 Feb 2023 19:07:09 +0400 Subject: [PATCH 120/199] Add tests for different Lido deposit scenarios --- test/0.4.24/lido-deposit-scenarios.test.js | 247 +++++++++++++++++++++ test/helpers/assert.js | 4 +- test/helpers/blockchain.js | 23 +- test/helpers/stubs/staking-module.stub.js | 59 +++++ test/helpers/wei.js | 54 +++++ 5 files changed, 381 insertions(+), 6 deletions(-) create mode 100644 test/0.4.24/lido-deposit-scenarios.test.js create mode 100644 test/helpers/stubs/staking-module.stub.js create mode 100644 test/helpers/wei.js diff --git a/test/0.4.24/lido-deposit-scenarios.test.js b/test/0.4.24/lido-deposit-scenarios.test.js new file mode 100644 index 000000000..a8c79c9fa --- /dev/null +++ b/test/0.4.24/lido-deposit-scenarios.test.js @@ -0,0 +1,247 @@ +const hre = require('hardhat') +const { deployProtocol } = require('../helpers/protocol') +const { EvmSnapshot, setBalance, getBalance } = require('../helpers/blockchain') +const { ZERO_ADDRESS } = require('@aragon/contract-helpers-test') +const { assert } = require('../helpers/assert') +const { wei } = require('../helpers/wei') +const { StakingModuleStub } = require('../helpers/stubs/staking-module.stub') +const { PUBKEY_LENGTH, FakeValidatorKeys, SIGNATURE_LENGTH } = require('../helpers/signing-keys') +const { GenericStub } = require('../helpers/stubs/generic.stub') + +hre.contract('Lido deposit scenarios', ([staker, depositor]) => { + const CURATED_MODULE_ID = 1 + const DEPOSIT_CALLDATA = '0x0' + let lido, stakingRouter + let stakingModuleStub, depositContractStub + let snapshot + + before('prepare base Lido & StakingRouter setup', async () => { + stakingModuleStub = await StakingModuleStub.new() + depositContractStub = await GenericStub.new('contracts/0.6.11/deposit_contract.sol:IDepositContract') + // just accept all ether and do nothing + await GenericStub.stub(depositContractStub, 'deposit') + const protocol = await deployProtocol({ + stakingModulesFactory: async () => { + return [ + { + module: stakingModuleStub, + name: 'stubbed staking module', + targetShares: 100_00, + moduleFee: 5_00, + treasuryFee: 5_00 + } + ] + }, + depositSecurityModuleFactory: async () => ({ address: depositor }), + depositContractFactory: () => depositContractStub, + postSetup: async ({ pool, lidoLocator, eip712StETH, voting }) => { + await pool.initialize(lidoLocator.address, eip712StETH.address, { value: wei.str(wei`1 ether`) }) + await pool.resumeProtocolAndStaking({ from: voting.address }) + } + }) + lido = protocol.pool + stakingRouter = protocol.stakingRouter + snapshot = new EvmSnapshot(hre.ethers.provider) + await snapshot.make() + }) + + afterEach(() => snapshot.rollback()) + + it('StakingRouter has non zero ETH balance & lido has unaccounted ether', async () => { + // add extra ETH value to the StakingRouter + const initialStakingRouterBalance = wei`1 ether` + await setBalance(stakingRouter, initialStakingRouterBalance) + assert.equal(await getBalance(stakingRouter), initialStakingRouterBalance) + + // add unaccounted ETH to Lido + const unaccountedLidoETHBalance = wei`1 gwei` + const initialLidoETHBalance = await getBalance(lido) + await setBalance(lido, initialLidoETHBalance + unaccountedLidoETHBalance) + assert.equal(await getBalance(lido), initialLidoETHBalance + unaccountedLidoETHBalance) + + const availableValidatorsCount = 2 + await StakingModuleStub.stubGetStakingModuleSummary(stakingModuleStub, { + totalExitedValidators: 5, + totalDepositedValidators: 16, + availableValidatorsCount + }) + + const depositDataLength = availableValidatorsCount + await StakingModuleStub.stubObtainDepositData(stakingModuleStub, { + return: { depositDataLength } + }) + + const submitAmount = wei`320 ether` + await lido.submit(ZERO_ADDRESS, { from: staker, value: wei.str(submitAmount) }) + + assert.equal(await getBalance(lido), initialLidoETHBalance + unaccountedLidoETHBalance + submitAmount) + + const maxDepositsCount = 10 + await lido.deposit(maxDepositsCount, CURATED_MODULE_ID, DEPOSIT_CALLDATA, { from: depositor }) + + assert.equals(await getBalance(stakingRouter), initialStakingRouterBalance) + const depositedEther = wei`32 ether` * wei.min(maxDepositsCount, availableValidatorsCount) + assert.equals( + await getBalance(lido), + initialLidoETHBalance + unaccountedLidoETHBalance + submitAmount - depositedEther + ) + }) + + describe('StakingModule returns invalid data', () => { + it('obtainDepositData() returns more publicKeys and signatures than expected', async () => { + const initialStakingRouterBalance = wei`1 ether` + await setBalance(stakingRouter, initialStakingRouterBalance) + assert.equals(await getBalance(stakingRouter), initialStakingRouterBalance) + + const availableValidatorsCount = 2 + await StakingModuleStub.stubGetStakingModuleSummary(stakingModuleStub, { + totalExitedValidators: 5, + totalDepositedValidators: 16, + availableValidatorsCount + }) + + const depositDataLength = availableValidatorsCount + 2 + await StakingModuleStub.stubObtainDepositData(stakingModuleStub, { + return: { depositDataLength } + }) + + const initialLidETHBalance = await getBalance(lido) + + const submitAmount = wei`320 ether` + await lido.submit(ZERO_ADDRESS, { from: staker, value: wei.str(submitAmount) }) + + assert.equals(await getBalance(lido), initialLidETHBalance + submitAmount) + + const maxDepositsCount = 10 + await assert.reverts( + lido.deposit(maxDepositsCount, CURATED_MODULE_ID, DEPOSIT_CALLDATA, { from: depositor }), + 'InvalidPublicKeysBatchLength', + [PUBKEY_LENGTH * depositDataLength, PUBKEY_LENGTH * availableValidatorsCount] + ) + }) + + it('obtainDepositData() returns more publicKeys than expected', async () => { + const initialStakingRouterBalance = wei`1 ether` + await setBalance(stakingRouter, initialStakingRouterBalance) + assert.equals(await getBalance(stakingRouter), initialStakingRouterBalance) + + const availableValidatorsCount = 2 + await StakingModuleStub.stubGetStakingModuleSummary(stakingModuleStub, { + totalExitedValidators: 5, + totalDepositedValidators: 16, + availableValidatorsCount + }) + + const depositDataLength = availableValidatorsCount + 2 + const depositData = new FakeValidatorKeys(depositDataLength) + await StakingModuleStub.stubObtainDepositData(stakingModuleStub, { + return: { + publicKeysBatch: depositData.slice()[0], // two extra signatures returned + signaturesBatch: depositData.slice(0, availableValidatorsCount)[1] + } + }) + + const initialLidETHBalance = await getBalance(lido) + + const submitAmount = wei`320 ether` + await lido.submit(ZERO_ADDRESS, { from: staker, value: wei.str(submitAmount) }) + + assert.equals(await getBalance(lido), initialLidETHBalance + submitAmount) + + const maxDepositsCount = 10 + await assert.reverts( + lido.deposit(maxDepositsCount, CURATED_MODULE_ID, DEPOSIT_CALLDATA, { from: depositor }), + 'InvalidPublicKeysBatchLength', + [PUBKEY_LENGTH * depositDataLength, PUBKEY_LENGTH * availableValidatorsCount] + ) + }) + + it('obtainDepositData() returns more signatures than expected', async () => { + const initialStakingRouterBalance = wei`1 ether` + await setBalance(stakingRouter, initialStakingRouterBalance) + assert.equals(await getBalance(stakingRouter), initialStakingRouterBalance) + + const availableValidatorsCount = 2 + await StakingModuleStub.stubGetStakingModuleSummary(stakingModuleStub, { + totalExitedValidators: 5, + totalDepositedValidators: 16, + availableValidatorsCount + }) + + const depositDataLength = availableValidatorsCount + 2 + const depositData = new FakeValidatorKeys(depositDataLength) + await StakingModuleStub.stubObtainDepositData(stakingModuleStub, { + return: { + publicKeysBatch: depositData.slice(0, availableValidatorsCount)[0], + signaturesBatch: depositData.slice()[1] // two extra signatures returned + } + }) + + const initialLidETHBalance = await getBalance(lido) + + const submitAmount = wei`320 ether` + await lido.submit(ZERO_ADDRESS, { from: staker, value: wei.str(submitAmount) }) + + assert.equals(await getBalance(lido), initialLidETHBalance + submitAmount) + + const maxDepositsCount = 10 + await assert.reverts( + lido.deposit(maxDepositsCount, CURATED_MODULE_ID, DEPOSIT_CALLDATA, { from: depositor }), + 'InvalidSignaturesBatchLength', + [SIGNATURE_LENGTH * depositDataLength, SIGNATURE_LENGTH * availableValidatorsCount] + ) + }) + + it('invalid ETH value was used for deposits in StakingRouter', async () => { + // on each deposit call forward back 1 ether to the staking router + await GenericStub.stub(depositContractStub, 'deposit', { + forwardETH: { value: wei.str(wei`1 ether`), recipient: stakingRouter.address } + }) + + const submitAmount = wei`320 ether` + const initialLidoETHBalance = await getBalance(lido) + await lido.submit(ZERO_ADDRESS, { from: staker, value: wei.str(submitAmount) }) + + assert.equal(await getBalance(lido), initialLidoETHBalance + submitAmount) + + const availableValidatorsCount = 2 + await StakingModuleStub.stubGetStakingModuleSummary(stakingModuleStub, { + totalExitedValidators: 5, + totalDepositedValidators: 16, + availableValidatorsCount + }) + + const depositDataLength = availableValidatorsCount + await StakingModuleStub.stubObtainDepositData(stakingModuleStub, { + return: { depositDataLength } + }) + const maxDepositsCount = 10 + await assert.reverts(lido.deposit(maxDepositsCount, CURATED_MODULE_ID, DEPOSIT_CALLDATA, { from: depositor })) + }) + + it('StakingModule reverted on obtainData', async () => { + const submitAmount = wei`320 ether` + const initialLidoETHBalance = await getBalance(lido) + await lido.submit(ZERO_ADDRESS, { from: staker, value: wei.str(submitAmount) }) + + assert.equal(await getBalance(lido), initialLidoETHBalance + submitAmount) + + const availableValidatorsCount = 2 + await StakingModuleStub.stubGetStakingModuleSummary(stakingModuleStub, { + totalExitedValidators: 5, + totalDepositedValidators: 16, + availableValidatorsCount + }) + + await StakingModuleStub.stub(stakingModuleStub, 'obtainDepositData', { + revert: { reason: 'INVALID_ALLOCATED_KEYS_COUNT' } + }) + + const maxDepositsCount = 10 + await assert.reverts( + lido.deposit(maxDepositsCount, CURATED_MODULE_ID, DEPOSIT_CALLDATA, { from: depositor }), + 'INVALID_ALLOCATED_KEYS_COUNT' + ) + }) + }) +}) diff --git a/test/helpers/assert.js b/test/helpers/assert.js index 64f5bbabe..94c8bde35 100644 --- a/test/helpers/assert.js +++ b/test/helpers/assert.js @@ -44,8 +44,8 @@ chai.util.addMethod(chai.assert, 'notEmits', function (receipt, eventName, args this.isUndefined(event, `Expected that event "${eventName}" with args ${args} wouldn't be emitted, but it was.`) }) -chai.util.addMethod(chai.assert, 'reverts', async function (receipt, reason) { - await assertRevert(receipt, reason) +chai.util.addMethod(chai.assert, 'reverts', async function (receipt, reason, customErrorArgs) { + await assertRevert(receipt, customErrorArgs !== undefined ? `${reason}(${customErrorArgs.join(', ')})` : reason) }) chai.util.addMethod(chai.assert, 'equals', function (actual, expected, errorMsg) { diff --git a/test/helpers/blockchain.js b/test/helpers/blockchain.js index 7d7f8bb32..c6ce77081 100644 --- a/test/helpers/blockchain.js +++ b/test/helpers/blockchain.js @@ -1,7 +1,10 @@ +const hre = require('hardhat') +const { wei } = require('./wei') + async function waitBlocks(numBlocksToMine) { let block for (let i = 0; i < numBlocksToMine; ++i) { - await network.provider.send('evm_mine') + await hre.network.provider.send('evm_mine') block = await web3.eth.getBlock('latest') } return block @@ -13,9 +16,9 @@ async function advanceChainTime(seconds) { } async function getCurrentBlockTimestamp() { - const blockNum = await ethers.provider.getBlockNumber(); - const block = await ethers.provider.getBlock(blockNum); - return block.timestamp; + const blockNum = await hre.ethers.provider.getBlockNumber() + const block = await hre.ethers.provider.getBlock(blockNum) + return block.timestamp } /** @@ -49,6 +52,16 @@ function impersonate(provider, address) { return provider.send('hardhat_impersonateAccount', [address]) } +async function getBalance(addressOrContract) { + const address = addressOrContract.address || addressOrContract + return wei.int(await hre.ethers.provider.getBalance(address)) +} + +async function setBalance(addressOrContract, value) { + const address = addressOrContract.address || addressOrContract + const hexValue = hre.web3.utils.numberToHex(wei.str(value)) + await hre.network.provider.send('hardhat_setBalance', [address, hexValue]) +} module.exports = { EvmSnapshot, @@ -56,4 +69,6 @@ module.exports = { advanceChainTime, getCurrentBlockTimestamp, impersonate, + getBalance, + setBalance } diff --git a/test/helpers/stubs/staking-module.stub.js b/test/helpers/stubs/staking-module.stub.js new file mode 100644 index 000000000..224d5bc00 --- /dev/null +++ b/test/helpers/stubs/staking-module.stub.js @@ -0,0 +1,59 @@ +const { GenericStub } = require('./generic.stub') +const { FakeValidatorKeys } = require('../../helpers/signing-keys') + +class StakingModuleStub extends GenericStub { + static new() { + return GenericStub.new('IStakingModule') + } + + static async stubGetStakingModuleSummary( + stakingModuleStub, + { totalExitedValidators, totalDepositedValidators, availableValidatorsCount } + ) { + await GenericStub.stub(stakingModuleStub, 'getStakingModuleSummary', { + return: { + type: ['uint256', 'uint256', 'uint256'], + value: [totalExitedValidators, totalDepositedValidators, availableValidatorsCount] + } + }) + } + + /** + * @param {object} stakingModuleStub instance of GenericStub contract + * @param {object} config config for the method stub + * @param {object} config.input the input stub must return value for. When not set + * config.return value will be returned for any input + * @param {number} config.input.depositsCount the input value of the _depositsCount to trigger stub + * @param {string} config.input.calldata the input value of the _calldata to trigger stub + * @param {object} config.return the config for the return value + * @param {object} config.return.depositData the instance of the FakeValidatorKeys to return from the stub. + * If not set will be used FakeValidatorKeys instance of default length + * @param {number} config.return.depositDataLength the length of the FakeValidatorKeys instance + * to use for return value + * @param {string} config.return.publicKeysBatch the bytes batch of the public keys + * @param {string} config.return.signaturesBatch the bytes batch of the signatures + */ + static async stubObtainDepositData(stakingModuleStub, config) { + const input = config.input + ? { type: ['uint256', 'bytes'], value: [config.input.depositsCount, config.input.calldata] } + : undefined + const depositData = config.return.depositData + ? config.return.depositData + : new FakeValidatorKeys(config.return.depositDataLength) + const [defaultPublicKeysBatch, defaultSignaturesBatch] = depositData.slice() + await GenericStub.stub(stakingModuleStub, 'obtainDepositData', { + input, + return: { + type: ['bytes', 'bytes'], + value: [ + config.return.publicKeysBatch || defaultPublicKeysBatch, + config.return.signaturesBatch || defaultSignaturesBatch + ] + } + }) + } +} + +module.exports = { + StakingModuleStub +} diff --git a/test/helpers/wei.js b/test/helpers/wei.js new file mode 100644 index 000000000..30592c841 --- /dev/null +++ b/test/helpers/wei.js @@ -0,0 +1,54 @@ +const hre = require('hardhat') + +function wei(strings, ...values) { + // when wei used not like js tag but called like regular function + // the first argument will be string instead of array of strings + if (typeof strings === 'string') { + throw new Error("Invalid wei tag usage. Please, use it like JS tag: wei`1 ether` instead of: wei('1 ether')") + } + + // case when wei used without arguments + if (strings.length === 1 && strings[0] === '' && values.length === 0) { + throw new Error('Empty wei tag template. Please specify expression inside wei`` tag') + } + + // combine interpolations in one expression + let expression = strings[0] + for (let i = 1; i < strings.length; ++i) { + expression += values[i - 1] + strings[i] + } + + const [amount, unit = 'wei'] = expression + .replaceAll('_', '') // remove all _ from numbers written like '100_00' + .trim() // remove all leading and trealing spaces + .split(' ') // split amount and unit parts + .filter((v) => !!v) // remove all empty strings if value had redundant spaces between amount and unit parts + + if (!Number.isFinite(+amount)) { + throw new Error(`Amount ${amount} is not a number`) + } + + return BigInt(hre.web3.utils.toWei(amount, unit.toLowerCase())) +} + +wei.int = (value) => BigInt(value.toString()) + +wei.str = (value) => value.toString() + +wei.min = (...values) => { + if (values.length === 0) { + throw new Error(`No arguments provided to wei.min() call`) + } + return values.reduce((min, value) => (wei.int(value) < min ? wei.int(value) : min), wei.int(values[0])) +} + +wei.max = (...values) => { + if (values.length === 0) { + throw new Error(`No arguments provided to wei.min() call`) + } + return values.reduce((max, value) => (wei.int(value) > max ? wei.int(value) : max), wei.int(values[0])) +} + +module.exports = { + wei +} From f2adad14eb0244ff3cc49ee620fef4aaf4ff7243 Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Sun, 19 Feb 2023 19:36:59 +0400 Subject: [PATCH 121/199] Update ABIs --- lib/abi/BeaconChainDepositor.json | 2 +- lib/abi/Lido.json | 2 +- lib/abi/StakingRouter.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/abi/BeaconChainDepositor.json b/lib/abi/BeaconChainDepositor.json index 94e81c706..9d8f718cd 100644 --- a/lib/abi/BeaconChainDepositor.json +++ b/lib/abi/BeaconChainDepositor.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[],"name":"NotExpectedBalance","type":"error"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidPublicKeysBatchLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidSignaturesBatchLength","type":"error"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/lib/abi/Lido.json b/lib/abi/Lido.json index 6ca21f6d5..43d9f9d89 100644 --- a/lib/abi/Lido.json +++ b/lib/abi/Lido.json @@ -1 +1 @@ -[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getEIP712StETH","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_clValidators","type":"uint256"},{"name":"_clBalance","type":"uint256"},{"name":"_withdrawalVaultBalance","type":"uint256"},{"name":"_elRewardsVaultBalance","type":"uint256"},{"name":"_lastFinalizableRequestId","type":"uint256"},{"name":"_simulatedShareRate","type":"uint256"}],"name":"handleOracleReport","outputs":[{"name":"postTotalPooledEther","type":"uint256"},{"name":"postTotalShares","type":"uint256"},{"name":"withdrawals","type":"uint256"},{"name":"elRewards","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"totalFee","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getDepositableEther","outputs":[{"name":"depositableEther","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}] \ No newline at end of file +[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getEIP712StETH","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_clValidators","type":"uint256"},{"name":"_clBalance","type":"uint256"},{"name":"_withdrawalVaultBalance","type":"uint256"},{"name":"_elRewardsVaultBalance","type":"uint256"},{"name":"_lastFinalizableRequestId","type":"uint256"},{"name":"_simulatedShareRate","type":"uint256"}],"name":"handleOracleReport","outputs":[{"name":"postTotalPooledEther","type":"uint256"},{"name":"postTotalShares","type":"uint256"},{"name":"withdrawals","type":"uint256"},{"name":"elRewards","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"totalFee","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getDepositableEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}] \ No newline at end of file diff --git a/lib/abi/StakingRouter.json b/lib/abi/StakingRouter.json index 864da84bd..82cd069d9 100644 --- a/lib/abi/StakingRouter.json +++ b/lib/abi/StakingRouter.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"desiredDepositsCount","type":"uint256"},{"internalType":"uint256","name":"actualDepositsCount","type":"uint256"}],"name":"DepositsCountMismatch","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"EmptyWithdrawalsCredentials","type":"error"},{"inputs":[],"name":"ExitedValidatorsCountCannotDecrease","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"etherValue","type":"uint256"}],"name":"InvalidDepositsValue","type":"error"},{"inputs":[],"name":"InvalidReportData","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotExpectedBalance","type":"error"},{"inputs":[],"name":"StakingModuleIdTooLarge","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","type":"error"},{"inputs":[],"name":"StakingModuleNotPaused","type":"error"},{"inputs":[],"name":"StakingModuleStatusTheSame","type":"error"},{"inputs":[],"name":"StakingModuleUnregistered","type":"error"},{"inputs":[],"name":"StakingModuleWrongName","type":"error"},{"inputs":[],"name":"StakingModulesLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpStuckValidatorsCount","type":"uint256"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ValueOver100Percent","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","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":false,"internalType":"address","name":"stakingModule","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"createdBy","type":"address"}],"name":"StakingModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unreportedExitedValidatorsCount","type":"uint256"}],"name":"StakingModuleExitedValidatorsIncompleteReporting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingModuleFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"enum StakingRouter.StakingModuleStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleTargetShareSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingRouterETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalCredentials","type":"bytes32"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"WithdrawalCredentialsSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PRECISION_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_WITHDRAWAL_CREDENTIALS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_REWARDS_MINTED_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_MANAGE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_SET_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_stakingModuleAddress","type":"address"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getAllNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"}],"name":"getDepositsAllocation","outputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256[]","name":"_nodeOperatorIds","type":"uint256[]"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"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":"getStakingFeeAggregateDistribution","outputs":[{"internalType":"uint96","name":"modulesFee","type":"uint96"},{"internalType":"uint96","name":"treasuryFee","type":"uint96"},{"internalType":"uint256","name":"basePrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingFeeAggregateDistributionE4Precision","outputs":[{"internalType":"uint16","name":"modulesFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModule","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleActiveValidatorsCount","outputs":[{"internalType":"uint256","name":"activeValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"}],"name":"getStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleIds","outputs":[{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleLastDepositBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_maxDepositsValue","type":"uint256"}],"name":"getStakingModuleMaxDepositsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleStatus","outputs":[{"internalType":"enum StakingRouter.StakingModuleStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleSummary","outputs":[{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModules","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule[]","name":"res","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingRewardsDistribution","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"},{"internalType":"uint96[]","name":"stakingModuleFees","type":"uint96[]"},{"internalType":"uint96","name":"totalFee","type":"uint96"},{"internalType":"uint256","name":"precisionPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFeeE4Precision","outputs":[{"internalType":"uint16","name":"totalFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalCredentials","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"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"pauseStakingModule","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":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_totalShares","type":"uint256[]"}],"name":"reportRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"resumeStakingModule","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":"_stakingModuleId","type":"uint256"},{"internalType":"enum StakingRouter.StakingModuleStatus","name":"_status","type":"uint8"}],"name":"setStakingModuleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","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":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"_triggerUpdateFinish","type":"bool"},{"components":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorStuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorStuckValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.ValidatorsCountCorrection","name":"_correction","type":"tuple"}],"name":"unsafeSetExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"EmptyWithdrawalsCredentials","type":"error"},{"inputs":[],"name":"ExitedValidatorsCountCannotDecrease","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"etherValue","type":"uint256"}],"name":"InvalidDepositsValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidPublicKeysBatchLength","type":"error"},{"inputs":[],"name":"InvalidReportData","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidSignaturesBatchLength","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"StakingModuleIdTooLarge","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","type":"error"},{"inputs":[],"name":"StakingModuleNotPaused","type":"error"},{"inputs":[],"name":"StakingModuleStatusTheSame","type":"error"},{"inputs":[],"name":"StakingModuleUnregistered","type":"error"},{"inputs":[],"name":"StakingModuleWrongName","type":"error"},{"inputs":[],"name":"StakingModulesLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpStuckValidatorsCount","type":"uint256"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ValueOver100Percent","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","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":false,"internalType":"address","name":"stakingModule","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"createdBy","type":"address"}],"name":"StakingModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unreportedExitedValidatorsCount","type":"uint256"}],"name":"StakingModuleExitedValidatorsIncompleteReporting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingModuleFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"enum StakingRouter.StakingModuleStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleTargetShareSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingRouterETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalCredentials","type":"bytes32"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"WithdrawalCredentialsSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PRECISION_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_WITHDRAWAL_CREDENTIALS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_REWARDS_MINTED_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_MANAGE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_SET_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_stakingModuleAddress","type":"address"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getAllNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"}],"name":"getDepositsAllocation","outputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256[]","name":"_nodeOperatorIds","type":"uint256[]"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"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":"getStakingFeeAggregateDistribution","outputs":[{"internalType":"uint96","name":"modulesFee","type":"uint96"},{"internalType":"uint96","name":"treasuryFee","type":"uint96"},{"internalType":"uint256","name":"basePrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingFeeAggregateDistributionE4Precision","outputs":[{"internalType":"uint16","name":"modulesFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModule","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleActiveValidatorsCount","outputs":[{"internalType":"uint256","name":"activeValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"}],"name":"getStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleIds","outputs":[{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleLastDepositBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_maxDepositsValue","type":"uint256"}],"name":"getStakingModuleMaxDepositsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleStatus","outputs":[{"internalType":"enum StakingRouter.StakingModuleStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleSummary","outputs":[{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModules","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule[]","name":"res","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingRewardsDistribution","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"},{"internalType":"uint96[]","name":"stakingModuleFees","type":"uint96[]"},{"internalType":"uint96","name":"totalFee","type":"uint96"},{"internalType":"uint256","name":"precisionPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFeeE4Precision","outputs":[{"internalType":"uint16","name":"totalFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalCredentials","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"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"pauseStakingModule","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":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_totalShares","type":"uint256[]"}],"name":"reportRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"resumeStakingModule","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":"_stakingModuleId","type":"uint256"},{"internalType":"enum StakingRouter.StakingModuleStatus","name":"_status","type":"uint8"}],"name":"setStakingModuleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","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":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"_triggerUpdateFinish","type":"bool"},{"components":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorStuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorStuckValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.ValidatorsCountCorrection","name":"_correction","type":"tuple"}],"name":"unsafeSetExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file From 768fa19419af688814f45a109b5f7833cbaa6da2 Mon Sep 17 00:00:00 2001 From: Andrei Date: Mon, 20 Feb 2023 00:34:57 +0700 Subject: [PATCH 122/199] test: validatorsExitBus oracle: deploy: fix code style --- .../validators-exit-bus-oracle-deploy.test.js | 159 ++++++++++-------- 1 file changed, 87 insertions(+), 72 deletions(-) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js index afac6493f..d7d510c3c 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js @@ -1,32 +1,37 @@ -const { BN } = require('bn.js') -const { assert } = require('chai') -const { assertBn, assertEvent, assertAmountOfEvents } = require('@aragon/contract-helpers-test/src/asserts') -const { assertRevert } = require('../../helpers/assertThrow') -const { assertBnClose, e18, hex, strip0x } = require('../../helpers/utils') -const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') -const { updateLocatorImplementation, deployLocatorWithDummyAddressesImplementation } = require('../../helpers/locator-deploy') +const { assert } = require('../../helpers/assert') +const { assertEvent } = require('@aragon/contract-helpers-test/src/asserts') +const { hex, strip0x } = require('../../helpers/utils') +const { ZERO_ADDRESS } = require('@aragon/contract-helpers-test') +const { + updateLocatorImplementation, + deployLocatorWithDummyAddressesImplementation +} = require('../../helpers/locator-deploy') const { - SLOTS_PER_EPOCH, SECONDS_PER_SLOT, GENESIS_TIME, SECONDS_PER_EPOCH, - computeSlotAt, computeEpochAt, computeEpochFirstSlotAt, - computeEpochFirstSlot, computeTimestampAtSlot, computeTimestampAtEpoch, - ZERO_HASH, HASH_1, HASH_2, HASH_3, HASH_4, HASH_5, CONSENSUS_VERSION, - deployHashConsensus } = require('./hash-consensus-deploy.test') + SLOTS_PER_EPOCH, + SECONDS_PER_SLOT, + GENESIS_TIME, + SECONDS_PER_EPOCH, + computeSlotAt, + computeEpochAt, + computeEpochFirstSlotAt, + computeEpochFirstSlot, + computeTimestampAtSlot, + computeTimestampAtEpoch, + ZERO_HASH, + CONSENSUS_VERSION, + deployHashConsensus +} = require('./hash-consensus-deploy.test') const ValidatorsExitBusOracle = artifacts.require('ValidatorsExitBusTimeTravellable') const DATA_FORMAT_LIST = 1 - - function getReportDataItems(r) { return [r.consensusVersion, r.refSlot, r.requestsCount, r.dataFormat, r.data] } function calcReportDataHash(reportItems) { - const data = web3.eth.abi.encodeParameters( - ['(uint256,uint256,uint256,uint256,bytes)'], - [reportItems] - ) + const data = web3.eth.abi.encodeParameters(['(uint256,uint256,uint256,uint256,bytes)'], [reportItems]) // const toS = x => Array.isArray(x) ? `[${x.map(toS)}]` : `${x}` // console.log(toS(reportItems)) // console.log(data) @@ -50,21 +55,33 @@ const SECONDS_PER_FRAME = EPOCHS_PER_FRAME * SECONDS_PER_EPOCH const MAX_REQUESTS_PER_REPORT = 6 const MAX_REQUESTS_LIST_LENGTH = 5 const MAX_REQUESTS_PER_DAY = 5 - - module.exports = { - SLOTS_PER_EPOCH, SECONDS_PER_SLOT, GENESIS_TIME, SECONDS_PER_EPOCH, - EPOCHS_PER_FRAME, SLOTS_PER_FRAME, SECONDS_PER_FRAME, - MAX_REQUESTS_PER_REPORT, MAX_REQUESTS_LIST_LENGTH, + SLOTS_PER_EPOCH, + SECONDS_PER_SLOT, + GENESIS_TIME, + SECONDS_PER_EPOCH, + EPOCHS_PER_FRAME, + SLOTS_PER_FRAME, + SECONDS_PER_FRAME, + MAX_REQUESTS_PER_REPORT, + MAX_REQUESTS_LIST_LENGTH, MAX_REQUESTS_PER_DAY, - computeSlotAt, computeEpochAt, computeEpochFirstSlotAt, - computeEpochFirstSlot, computeTimestampAtSlot, computeTimestampAtEpoch, - ZERO_HASH, CONSENSUS_VERSION, DATA_FORMAT_LIST, - getReportDataItems, calcReportDataHash, encodeExitRequestHex, - encodeExitRequestsDataList, deployExitBusOracle, + computeSlotAt, + computeEpochAt, + computeEpochFirstSlotAt, + computeEpochFirstSlot, + computeTimestampAtSlot, + computeTimestampAtEpoch, + ZERO_HASH, + CONSENSUS_VERSION, + DATA_FORMAT_LIST, + getReportDataItems, + calcReportDataHash, + encodeExitRequestHex, + encodeExitRequestsDataList, + deployExitBusOracle, deployOracleReportSanityCheckerForExitBus } - async function deployOracleReportSanityCheckerForExitBus(lidoLocator, admin) { const maxValidatorExitRequestsPerReport = 2000 const limitsList = [0, 0, 0, 0, 0, 0, maxValidatorExitRequestsPerReport, 0] @@ -72,101 +89,99 @@ async function deployOracleReportSanityCheckerForExitBus(lidoLocator, admin) { const OracleReportSanityChecker = artifacts.require('OracleReportSanityChecker') - let oracleReportSanityChecker = await OracleReportSanityChecker.new( - lidoLocator, admin, limitsList, managersRoster, { from: admin }) + const oracleReportSanityChecker = await OracleReportSanityChecker.new( + lidoLocator, + admin, + limitsList, + managersRoster, + { + from: admin + } + ) return oracleReportSanityChecker.address } -async function deployExitBusOracle(admin, { - dataSubmitter = null, - lastProcessingRefSlot = 0, - resumeAfterDeploy = false, -} = {}) { +async function deployExitBusOracle( + admin, + { dataSubmitter = null, lastProcessingRefSlot = 0, resumeAfterDeploy = false } = {} +) { const locator = (await deployLocatorWithDummyAddressesImplementation(admin)).address - const oracle = await ValidatorsExitBusOracle.new( - SECONDS_PER_SLOT, GENESIS_TIME, locator, {from: admin}) + const oracle = await ValidatorsExitBusOracle.new(SECONDS_PER_SLOT, GENESIS_TIME, locator, { from: admin }) - const {consensus} = await deployHashConsensus(admin, { + const { consensus } = await deployHashConsensus(admin, { epochsPerFrame: EPOCHS_PER_FRAME, - reportProcessor: oracle, + reportProcessor: oracle }) const oracleReportSanityChecker = await deployOracleReportSanityCheckerForExitBus(locator, admin) await updateLocatorImplementation(locator, admin, { validatorsExitBusOracle: oracle.address, - oracleReportSanityChecker : oracleReportSanityChecker, + oracleReportSanityChecker: oracleReportSanityChecker }) - const tx = await oracle.initialize( - admin, - consensus.address, - CONSENSUS_VERSION, - lastProcessingRefSlot, - {from: admin} - ) + const tx = await oracle.initialize(admin, consensus.address, CONSENSUS_VERSION, lastProcessingRefSlot, { + from: admin + }) - assertEvent(tx, 'ContractVersionSet', {expectedArgs: {version: 1}}) + assert.emits(tx, 'ContractVersionSet', { version: 1 }) - assertEvent(tx, 'RoleGranted', {expectedArgs: { + assert.emits(tx, 'RoleGranted', { role: await consensus.DEFAULT_ADMIN_ROLE(), account: admin, sender: admin - }}) + }) - assertEvent(tx, 'ConsensusHashContractSet', {expectedArgs: { + assert.emits(tx, 'ConsensusHashContractSet', { addr: consensus.address, prevAddr: ZERO_ADDRESS - }}) + }) - assertEvent(tx, 'ConsensusVersionSet', {expectedArgs: {version: CONSENSUS_VERSION, prevVersion: 0}}) + assert.emits(tx, 'ConsensusVersionSet', { version: CONSENSUS_VERSION, prevVersion: 0 }) - await oracle.grantRole(await oracle.MANAGE_CONSENSUS_CONTRACT_ROLE(), admin, {from: admin}) - await oracle.grantRole(await oracle.MANAGE_CONSENSUS_VERSION_ROLE(), admin, {from: admin}) - await oracle.grantRole(await oracle.PAUSE_ROLE(), admin, {from: admin}) - await oracle.grantRole(await oracle.RESUME_ROLE(), admin, {from: admin}) + await oracle.grantRole(await oracle.MANAGE_CONSENSUS_CONTRACT_ROLE(), admin, { from: admin }) + await oracle.grantRole(await oracle.MANAGE_CONSENSUS_VERSION_ROLE(), admin, { from: admin }) + await oracle.grantRole(await oracle.PAUSE_ROLE(), admin, { from: admin }) + await oracle.grantRole(await oracle.RESUME_ROLE(), admin, { from: admin }) if (dataSubmitter != null) { - await oracle.grantRole(await oracle.SUBMIT_DATA_ROLE(), dataSubmitter, {from: admin}) + await oracle.grantRole(await oracle.SUBMIT_DATA_ROLE(), dataSubmitter, { from: admin }) } - assert.equal(+await oracle.DATA_FORMAT_LIST(), DATA_FORMAT_LIST) + assert.equal(+(await oracle.DATA_FORMAT_LIST()), DATA_FORMAT_LIST) if (resumeAfterDeploy) { - await oracle.resume({from: admin}) + await oracle.resume({ from: admin }) } - return {consensus, oracle, locator} + return { consensus, oracle, locator } } - - contract('ValidatorsExitBusOracle', ([admin, member1]) => { let consensus let oracle context('Deployment and initial configuration', () => { - it('deployment finishes successfully', async () => { - const deployed = await deployExitBusOracle(admin, {resumeAfterDeploy: false}) + const deployed = await deployExitBusOracle(admin, { resumeAfterDeploy: false }) consensus = deployed.consensus oracle = deployed.oracle }) it('mock time-travellable setup is correct', async () => { - const time1 = +await consensus.getTime() - assert.equal(+await oracle.getTime(), time1) + const time1 = +(await consensus.getTime()) + assert.equal(+(await oracle.getTime()), time1) await consensus.advanceTimeBy(SECONDS_PER_SLOT) - const time2 = +await consensus.getTime() + const time2 = +(await consensus.getTime()) assert.equal(time2, time1 + SECONDS_PER_SLOT) - assert.equal(+await oracle.getTime(), time2) + assert.equal(+(await oracle.getTime()), time2) }) it('initial configuration is correct', async () => { assert.equal(await oracle.getConsensusContract(), consensus.address) - assert.equal(+await oracle.getConsensusVersion(), CONSENSUS_VERSION) - assert.equal(+await oracle.SECONDS_PER_SLOT(), SECONDS_PER_SLOT) + assert.equal(+(await oracle.getConsensusVersion()), CONSENSUS_VERSION) + assert.equal(+(await oracle.SECONDS_PER_SLOT()), SECONDS_PER_SLOT) assert.equal(await oracle.isPaused(), true) }) }) From bc81d74f3a9c938e64458552dbff26ed2f8679d9 Mon Sep 17 00:00:00 2001 From: Andrei Date: Mon, 20 Feb 2023 02:18:11 +0700 Subject: [PATCH 123/199] test: validatorsExitBus oracle: acces control: add access control tests --- .../accounting-oracle-access-control.test.js | 11 +- ...ors-exit-bus-oracle-access-control.test.js | 169 ++++++++++++++++++ .../validators-exit-bus-oracle-deploy.test.js | 13 +- 3 files changed, 180 insertions(+), 13 deletions(-) create mode 100644 test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js diff --git a/test/0.8.9/oracle/accounting-oracle-access-control.test.js b/test/0.8.9/oracle/accounting-oracle-access-control.test.js index 379549713..d0cc6704c 100644 --- a/test/0.8.9/oracle/accounting-oracle-access-control.test.js +++ b/test/0.8.9/oracle/accounting-oracle-access-control.test.js @@ -1,5 +1,4 @@ const { assert } = require('../../helpers/assert') -const { assertEvent } = require('@aragon/contract-helpers-test/src/asserts') const { e9, e18, e27 } = require('../../helpers/utils') const { @@ -84,7 +83,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra beforeEach(deploy) context('submitReportData', () => { - it('should revert from not consensus member without SUBMIT_DATA_ROLE role ', async () => { + it('should revert from not consensus member without SUBMIT_DATA_ROLE role', async () => { await assert.reverts( oracle.submitReportData(reportItems, CONSENSUS_VERSION, { from: stranger }), 'SenderNotAllowed()' @@ -97,14 +96,14 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra await consensus.setTime(deadline) const tx = await oracle.submitReportData(reportItems, CONSENSUS_VERSION, { from: account2 }) - assertEvent(tx, 'ProcessingStarted', { expectedArgs: { refSlot: reportFields.refSlot } }) + assert.emits(tx, 'ProcessingStarted', { refSlot: reportFields.refSlot }) }) it('should allow calling from a member', async () => { await consensus.addMember(member2, 2) const tx = await oracle.submitReportData(reportItems, CONSENSUS_VERSION, { from: member2 }) - assertEvent(tx, 'ProcessingStarted', { expectedArgs: { refSlot: reportFields.refSlot } }) + assert.emits(tx, 'ProcessingStarted', { refSlot: reportFields.refSlot }) }) }) @@ -123,7 +122,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra await oracle.submitReportData(reportItems, CONSENSUS_VERSION, { from: account2 }) const tx = await oracle.submitReportExtraDataList(extraDataList, { from: account2 }) - assertEvent(tx, 'ExtraDataSubmitted', { expectedArgs: { refSlot: reportFields.refSlot } }) + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) }) it('should allow calling from a member', async () => { @@ -134,7 +133,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra await oracle.submitReportData(reportItems, CONSENSUS_VERSION, { from: member2 }) const tx = await oracle.submitReportExtraDataList(extraDataList, { from: member2 }) - assertEvent(tx, 'ExtraDataSubmitted', { expectedArgs: { refSlot: reportFields.refSlot } }) + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) }) }) }) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js new file mode 100644 index 000000000..1ac172c9d --- /dev/null +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js @@ -0,0 +1,169 @@ +const { assert } = require('chai') +const { ZERO_ADDRESS } = require('@aragon/contract-helpers-test') + +const { + CONSENSUS_VERSION, + DATA_FORMAT_LIST, + getReportDataItems, + calcReportDataHash, + encodeExitRequestsDataList, + deployExitBusOracle +} = require('./validators-exit-bus-oracle-deploy.test') +const PUBKEYS = [ + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', + '0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', + '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' +] + +contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, account1, stranger]) => { + let consensus + let oracle + let oracleVersion + let initTx + let exitRequests + let reportFields + let reportItems + let reportHash + + const submitDataRoleKeccak156 = web3.utils.keccak256('SUBMIT_DATA_ROLE') + const pauseRoleKeccak156 = web3.utils.keccak256('PAUSE_ROLE') + const resumeRoleKeccak156 = web3.utils.keccak256('RESUME_ROLE') + + const getReportFields = (override = {}) => ({ + consensusVersion: CONSENSUS_VERSION, + dataFormat: DATA_FORMAT_LIST, + ...override + }) + const deploy = async () => { + const deployed = await deployExitBusOracle(admin, { resumeAfterDeploy: true }) + consensus = deployed.consensus + oracle = deployed.oracle + initTx = deployed.initTx + + oracleVersion = +(await oracle.getContractVersion()) + + await consensus.addMember(member1, 1, { from: admin }) + await consensus.addMember(member2, 2, { from: admin }) + await consensus.addMember(member3, 2, { from: admin }) + + const { refSlot } = await deployed.consensus.getCurrentFrame() + exitRequests = [ + { moduleId: 1, nodeOpId: 0, valIndex: 0, valPubkey: PUBKEYS[0] }, + { moduleId: 1, nodeOpId: 0, valIndex: 2, valPubkey: PUBKEYS[1] }, + { moduleId: 2, nodeOpId: 0, valIndex: 1, valPubkey: PUBKEYS[2] } + ] + + reportFields = getReportFields({ + refSlot: +refSlot, + requestsCount: exitRequests.length, + data: encodeExitRequestsDataList(exitRequests) + }) + + reportItems = getReportDataItems(reportFields) + reportHash = calcReportDataHash(reportItems) + + await deployed.consensus.submitReport(refSlot, reportHash, CONSENSUS_VERSION, { from: member1 }) + await deployed.consensus.submitReport(refSlot, reportHash, CONSENSUS_VERSION, { from: member3 }) + } + + context('Access control', () => { + context('deploying', () => { + before(deploy) + + it('deploying accounting oracle', async () => { + assert.isDefined(oracle) + assert.isDefined(consensus) + assert.isDefined(oracleVersion) + assert.isDefined(initTx) + assert.isDefined(exitRequests) + assert.isDefined(reportFields) + assert.isDefined(reportItems) + assert.isDefined(reportHash) + }) + }) + context('DEFAULT_ADMIN_ROLE', () => { + beforeEach(deploy) + + context('Admin is set at initialise', () => { + it('should set admin at initialise', async () => { + const DEFAULT_ADMIN_ROLE = await oracle.DEFAULT_ADMIN_ROLE() + await assert.emits(initTx, 'RoleGranted', { role: DEFAULT_ADMIN_ROLE, account: admin, sender: admin }) + }) + + it('should revert without admin address', async () => { + await assert.reverts( + oracle.initialize(ZERO_ADDRESS, consensus.address, CONSENSUS_VERSION, 0, { + from: admin + }), + 'AdminCannotBeZero()' + ) + }) + }) + }) + + context('SUBMIT_DATA_ROLE', () => { + beforeEach(deploy) + + context('_checkMsgSenderIsAllowedToSubmitData', () => { + it('should revert from not consensus member without SUBMIT_DATA_ROLE role', async () => { + await assert.reverts( + oracle.submitReportData(reportItems, oracleVersion, { from: stranger }), + 'SenderNotAllowed()' + ) + }) + + it('should allow calling from a possessor of SUBMIT_DATA_ROLE role', async () => { + await oracle.grantRole(submitDataRoleKeccak156, account1) + const deadline = (await oracle.getConsensusReport()).processingDeadlineTime + await consensus.setTime(deadline) + + const tx = await oracle.submitReportData(reportItems, oracleVersion, { from: account1 }) + assert.emits(tx, 'ProcessingStarted', { refSlot: reportFields.refSlot }) + }) + it('should allow calling from a member', async () => { + const tx = await oracle.submitReportData(reportItems, CONSENSUS_VERSION, { from: member2 }) + assert.emits(tx, 'ProcessingStarted', { refSlot: reportFields.refSlot }) + }) + }) + }) + + context('PAUSE_ROLE', () => { + beforeEach(deploy) + + context('pause', () => { + it('should revert without PAUSE_ROLE role', async () => { + await assert.revertsOZAccessControl(oracle.pause(0, { from: stranger }), stranger, 'PAUSE_ROLE') + }) + + it('should allow calling from a possessor of PAUSE_ROLE role', async () => { + await oracle.grantRole(pauseRoleKeccak156, account1) + + const tx = await oracle.pause(9999, { from: account1 }) + assert.emits(tx, 'Paused', { duration: 9999 }) + }) + }) + }) + + context('RESUME_ROLE', () => { + beforeEach(deploy) + + context('resume', () => { + it('should revert without RESUME_ROLE role', async () => { + await oracle.pause(9999, { from: admin }) + + await assert.revertsOZAccessControl(oracle.resume({ from: stranger }), stranger, 'RESUME_ROLE') + }) + + it('should allow calling from a possessor of RESUME_ROLE role', async () => { + await oracle.pause(9999, { from: admin }) + await oracle.grantRole(resumeRoleKeccak156, account1) + + const tx = await oracle.resume({ from: account1 }) + assert.emits(tx, 'Resumed') + }) + }) + }) + }) +}) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js index d7d510c3c..39c004450 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js @@ -1,5 +1,4 @@ const { assert } = require('../../helpers/assert') -const { assertEvent } = require('@aragon/contract-helpers-test/src/asserts') const { hex, strip0x } = require('../../helpers/utils') const { ZERO_ADDRESS } = require('@aragon/contract-helpers-test') const { @@ -120,24 +119,24 @@ async function deployExitBusOracle( oracleReportSanityChecker: oracleReportSanityChecker }) - const tx = await oracle.initialize(admin, consensus.address, CONSENSUS_VERSION, lastProcessingRefSlot, { + const initTx = await oracle.initialize(admin, consensus.address, CONSENSUS_VERSION, lastProcessingRefSlot, { from: admin }) - assert.emits(tx, 'ContractVersionSet', { version: 1 }) + assert.emits(initTx, 'ContractVersionSet', { version: 1 }) - assert.emits(tx, 'RoleGranted', { + assert.emits(initTx, 'RoleGranted', { role: await consensus.DEFAULT_ADMIN_ROLE(), account: admin, sender: admin }) - assert.emits(tx, 'ConsensusHashContractSet', { + assert.emits(initTx, 'ConsensusHashContractSet', { addr: consensus.address, prevAddr: ZERO_ADDRESS }) - assert.emits(tx, 'ConsensusVersionSet', { version: CONSENSUS_VERSION, prevVersion: 0 }) + assert.emits(initTx, 'ConsensusVersionSet', { version: CONSENSUS_VERSION, prevVersion: 0 }) await oracle.grantRole(await oracle.MANAGE_CONSENSUS_CONTRACT_ROLE(), admin, { from: admin }) await oracle.grantRole(await oracle.MANAGE_CONSENSUS_VERSION_ROLE(), admin, { from: admin }) @@ -154,7 +153,7 @@ async function deployExitBusOracle( await oracle.resume({ from: admin }) } - return { consensus, oracle, locator } + return { consensus, oracle, locator, initTx } } contract('ValidatorsExitBusOracle', ([admin, member1]) => { let consensus From 3c6616ea8c50e5f2b3e3e58a1dd364fc173ce6d2 Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Sun, 19 Feb 2023 22:25:52 +0200 Subject: [PATCH 124/199] exit bus oracle: fix docs --- contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol index 16acdef2a..bf3255d51 100644 --- a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol +++ b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol @@ -149,9 +149,8 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil { /// @dev Total number of validator exit requests in this report. Must not be greater /// than limit checked in OracleReportSanityChecker.checkExitBusOracleReport. /// - /// Cannot be zero: in the case there's no newly exited or stuck validators at the moment - /// of the reference slot that staking module contracts are not aware of at the same moment, - /// oracles should skip submitting the report. + /// Cannot be zero: in the case there's no validator exit requests to submit, oracles + /// should skip submitting the report for the current reporting frame. uint256 requestsCount; /// @dev Format of the validator exit requests data. Currently, only the From f98d514fdf491eda7fd0cd7f7a067f3dd80790df Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Sun, 19 Feb 2023 22:19:35 +0200 Subject: [PATCH 125/199] exit bus oracle: require node operators' validator indices to increase --- .../0.8.9/oracle/ValidatorsExitBusOracle.sol | 30 +++- .../validators-exit-bus-oracle-gas.test.js | 52 +++--- ...exit-bus-oracle-submit-report-data.test.js | 168 ++++++++++++++++++ 3 files changed, 219 insertions(+), 31 deletions(-) create mode 100644 test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js diff --git a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol index 9ac99f019..969abdec3 100644 --- a/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol +++ b/contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol @@ -29,6 +29,12 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil { error UnexpectedRequestsDataLength(); error InvalidRequestsDataSortOrder(); error ArgumentOutOfBounds(); + error NodeOpValidatorIndexMustIncrease( + uint256 moduleId, + uint256 nodeOpId, + uint256 prevRequestedValidatorIndex, + uint256 requestedValidatorIndex + ); event ValidatorExitRequest( uint256 indexed stakingModuleId, @@ -354,12 +360,9 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil { offsetPastEnd := add(offset, data.length) } - mapping(uint256 => RequestedValidator) storage _lastReqValidatorIndices = - _storageLastRequestedValidatorIndices(); - uint256 lastDataWithoutPubkey = 0; uint256 lastNodeOpKey = 0; - uint256 lastValIndex; + RequestedValidator memory lastRequestedVal; bytes calldata pubkey; assembly { @@ -386,7 +389,7 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil { revert InvalidRequestsDataSortOrder(); } - uint256 valIndex = uint64(dataWithoutPubkey); + uint64 valIndex = uint64(dataWithoutPubkey); uint256 nodeOpId = uint40(dataWithoutPubkey >> 64); uint256 moduleId = uint24(dataWithoutPubkey >> (64 + 40)); @@ -397,20 +400,29 @@ contract ValidatorsExitBusOracle is BaseOracle, PausableUntil { uint256 nodeOpKey = _computeNodeOpKey(moduleId, nodeOpId); if (nodeOpKey != lastNodeOpKey) { if (lastNodeOpKey != 0) { - _lastReqValidatorIndices[lastNodeOpKey] = - RequestedValidator(true, uint64(lastValIndex)); + _storageLastRequestedValidatorIndices()[lastNodeOpKey] = lastRequestedVal; } + lastRequestedVal = _storageLastRequestedValidatorIndices()[nodeOpKey]; lastNodeOpKey = nodeOpKey; } - lastValIndex = valIndex; + if (lastRequestedVal.requested && valIndex <= lastRequestedVal.index) { + revert NodeOpValidatorIndexMustIncrease( + moduleId, + nodeOpId, + lastRequestedVal.index, + valIndex + ); + } + + lastRequestedVal = RequestedValidator(true, valIndex); lastDataWithoutPubkey = dataWithoutPubkey; emit ValidatorExitRequest(moduleId, nodeOpId, valIndex, pubkey, timestamp); } if (lastNodeOpKey != 0) { - _lastReqValidatorIndices[lastNodeOpKey] = RequestedValidator(true, uint64(lastValIndex)); + _storageLastRequestedValidatorIndices()[lastNodeOpKey] = lastRequestedVal; } return lastDataWithoutPubkey; diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-gas.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-gas.test.js index 9f803ed66..9478f9008 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-gas.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-gas.test.js @@ -53,34 +53,41 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger assert.equal((await consensus.getConsensusState()).consensusReport, hash) } + const NUM_MODULES = 5 + const NODE_OPS_PER_MODULE = 100 + + let nextValIndex = 1 + function generateExitRequests(totalRequests) { - const requestsByModule = Math.max(3, Math.floor(totalRequests / 3)) - const requestsByNodeOp = Math.max(1, Math.floor(requestsByModule / 3)) + const requestsPerModule = Math.max(1, Math.floor(totalRequests / NUM_MODULES)) + const requestsPerNodeOp = Math.max(1, Math.floor(requestsPerModule / NODE_OPS_PER_MODULE)) const requests = [] for (let i = 0; i < totalRequests; ++i) { - const moduleId = Math.floor(i / requestsByModule) - const nodeOpId = Math.floor((i - moduleId * requestsByModule) / requestsByNodeOp) - const valIndex = i - moduleId * requestsByModule - nodeOpId * requestsByNodeOp + const moduleId = Math.floor(i / requestsPerModule) + const nodeOpId = Math.floor((i - moduleId * requestsPerModule) / requestsPerNodeOp) + const valIndex = nextValIndex++ const valPubkey = PUBKEYS[valIndex % PUBKEYS.length] - requests.push({moduleId: moduleId + 1, nodeOpId, valIndex, valPubkey }) + requests.push({moduleId: moduleId + 1, nodeOpId, valIndex, valPubkey}) } - return requests + return {requests, requestsPerModule, requestsPerNodeOp} } // pre-heating - testGas(10, () => {}) + testGas(NUM_MODULES * NODE_OPS_PER_MODULE, () => {}) const gasUsages = []; [10, 50, 100, 1000, 2000].forEach(n => testGas(n, r => gasUsages.push(r))) after(async () => { - gasUsages.forEach(({totalRequests, gasUsed}) => console.log( - `${totalRequests} requests: total gas ${ gasUsed }, ` + - `gas per request: ${ Math.round(gasUsed / totalRequests )}` - )) + gasUsages.forEach(({totalRequests, requestsPerModule, requestsPerNodeOp, gasUsed}) => + console.log( + `${totalRequests} requests (per module ${requestsPerModule}, ` + + `per node op ${requestsPerNodeOp}): total gas ${gasUsed}, ` + + `gas per request: ${Math.round(gasUsed / totalRequests)}` + )) }) function testGas(totalRequests, reportGas) { @@ -110,9 +117,9 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger reportFields = { consensusVersion: CONSENSUS_VERSION, refSlot: +refSlot, - requestsCount: exitRequests.length, + requestsCount: exitRequests.requests.length, dataFormat: DATA_FORMAT_LIST, - data: encodeExitRequestsDataList(exitRequests), + data: encodeExitRequestsDataList(exitRequests.requests), } reportItems = getReportDataItems(reportFields) @@ -149,19 +156,20 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger assert.isTrue((await oracle.getConsensusReport()).processingStarted) const timestamp = await oracle.getTime() + const {requests, requestsPerModule, requestsPerNodeOp} = exitRequests - for (let i = 0; i < exitRequests.length; ++i) { + for (let i = 0; i < requests.length; ++i) { assertEvent(tx, 'ValidatorExitRequest', {index: i, expectedArgs: { - stakingModuleId: exitRequests[i].moduleId, - nodeOperatorId: exitRequests[i].nodeOpId, - validatorIndex: exitRequests[i].valIndex, - validatorPubkey: exitRequests[i].valPubkey, + stakingModuleId: requests[i].moduleId, + nodeOperatorId: requests[i].nodeOpId, + validatorIndex: requests[i].valIndex, + validatorPubkey: requests[i].valPubkey, timestamp }}) } const {gasUsed} = tx.receipt - reportGas({totalRequests, gasUsed}) + reportGas({totalRequests, requestsPerModule, requestsPerNodeOp, gasUsed}) }) it(`reports are marked as processed`, async () => { @@ -169,8 +177,8 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger assert.equal(procState.dataHash, reportHash) assert.isTrue(procState.dataSubmitted) assert.equal(+procState.dataFormat, DATA_FORMAT_LIST) - assert.equal(+procState.requestsCount, exitRequests.length) - assert.equal(+procState.requestsSubmitted, exitRequests.length) + assert.equal(+procState.requestsCount, exitRequests.requests.length) + assert.equal(+procState.requestsSubmitted, exitRequests.requests.length) }) it('some time passes', async () => { diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js new file mode 100644 index 000000000..facf9dfc8 --- /dev/null +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -0,0 +1,168 @@ +const { assert } = require('chai') + +const { + CONSENSUS_VERSION, + DATA_FORMAT_LIST, + getReportDataItems, + calcReportDataHash, + encodeExitRequestsDataList, + deployExitBusOracle +} = require('./validators-exit-bus-oracle-deploy.test') + + +const PUBKEYS = [ + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', + '0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', + '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', +] + +contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger]) => { + + context('submitReportData', () => { + const LAST_PROCESSING_REF_SLOT = 1 + + let consensus + let oracle + let oracleVersion + + async function setup() { + const deployed = await deployExitBusOracle(admin, { + lastProcessingRefSlot: LAST_PROCESSING_REF_SLOT, + resumeAfterDeploy: true + }) + + consensus = deployed.consensus + oracle = deployed.oracle + + oracleVersion = +await oracle.getContractVersion() + + await consensus.addMember(member1, 1, {from: admin}) + await consensus.addMember(member2, 2, {from: admin}) + await consensus.addMember(member3, 2, {from: admin}) + } + + async function triggerConsensusOnHash(hash) { + const {refSlot} = await consensus.getCurrentFrame() + await consensus.submitReport(refSlot, hash, CONSENSUS_VERSION, { from: member1 }) + await consensus.submitReport(refSlot, hash, CONSENSUS_VERSION, { from: member3 }) + assert.equal((await consensus.getConsensusState()).consensusReport, hash) + } + + async function prepareReportAndSubmitHash(exitRequests) { + const {refSlot} = await consensus.getCurrentFrame() + + const reportFields = { + consensusVersion: CONSENSUS_VERSION, + refSlot: +refSlot, + requestsCount: exitRequests.length, + dataFormat: DATA_FORMAT_LIST, + data: encodeExitRequestsDataList(exitRequests), + } + + const reportItems = getReportDataItems(reportFields) + const reportHash = calcReportDataHash(reportItems) + + await triggerConsensusOnHash(reportHash) + + return reportItems + } + + async function getLastRequestedValidatorIndex(moduleId, nodeOpId) { + return +(await oracle.getLastRequestedValidatorIndices(moduleId, [nodeOpId]))[0] + } + + context(`requires validator indices for the same node operator to increase`, () => { + before(setup) + + it(`requesting NO 5-3 to exit validator 0`, async () => { + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash([ + {moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }, + ]) + await oracle.submitReportData(report, oracleVersion, {from: member1}) + assert.equal(await getLastRequestedValidatorIndex(5, 3), 0) + }) + + it(`cannot request NO 5-3 to exit validator 0 again`, async () => { + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash([ + {moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }, + ]) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, {from: member1}), + 'NodeOpValidatorIndexMustIncrease(5, 3, 0, 0)' + ) + }) + + it(`requesting NO 5-3 to exit validator 1`, async () => { + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash([ + {moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[1] }, + ]) + await oracle.submitReportData(report, oracleVersion, {from: member1}) + assert.equal(await getLastRequestedValidatorIndex(5, 3), 1) + }) + + it(`cannot request NO 5-3 to exit validator 1 again`, async () => { + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash([ + {moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[1] }, + ]) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, {from: member1}), + 'NodeOpValidatorIndexMustIncrease(5, 3, 1, 1)' + ) + }) + + it(`cannot request NO 5-3 to exit validator 0 again`, async () => { + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash([ + {moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }, + ]) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, {from: member1}), + 'NodeOpValidatorIndexMustIncrease(5, 3, 1, 0)' + ) + }) + + it(`cannot request NO 5-3 to exit validator 1 again (multiple requests)`, async () => { + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash([ + {moduleId: 5, nodeOpId: 1, valIndex: 10, valPubkey: PUBKEYS[0] }, + {moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[0] }, + ]) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, {from: member1}), + 'NodeOpValidatorIndexMustIncrease(5, 3, 1, 1)' + ) + }) + + it(`cannot request NO 5-3 to exit validator 1 again (multiple requests, case 2)`, async () => { + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash([ + {moduleId: 5, nodeOpId: 1, valIndex: 10, valPubkey: PUBKEYS[2] }, + {moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[3] }, + {moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[4] }, + ]) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, {from: member1}), + 'NodeOpValidatorIndexMustIncrease(5, 3, 1, 1)' + ) + }) + + it(`cannot request NO 5-3 to exit validator 2 two times per request`, async () => { + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash([ + {moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[2] }, + {moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[3] }, + ]) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, {from: member1}), + 'InvalidRequestsDataSortOrder()' + ) + }) + }) + }) +}) From cdb94ddff55adca91eb48b11384396a5646bee7a Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Mon, 20 Feb 2023 02:03:21 +0400 Subject: [PATCH 126/199] Implement events emitting configuration for GenericStub --- contracts/0.8.9/test_helpers/GenericStub.sol | 10 +-- test/helpers/stubs/generic.stub.js | 65 ++++++++++++++++++-- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/contracts/0.8.9/test_helpers/GenericStub.sol b/contracts/0.8.9/test_helpers/GenericStub.sol index efe6ac186..e965ad09d 100644 --- a/contracts/0.8.9/test_helpers/GenericStub.sol +++ b/contracts/0.8.9/test_helpers/GenericStub.sol @@ -128,15 +128,15 @@ contract GenericStub { bytes memory data = _logs[i].data; uint256 dataLength = data.length; if (_logs[i].logType == LogType.LOG0) { - assembly { log0(data, dataLength) } + assembly { log0(add(data, 32), dataLength) } } else if (_logs[i].logType == LogType.LOG1) { - assembly { log1(data, dataLength, t1) } + assembly { log1(add(data, 32), dataLength, t1) } } else if (_logs[i].logType == LogType.LOG2) { - assembly { log2(data, dataLength, t1, t2) } + assembly { log2(add(data, 32), dataLength, t1, t2) } } else if (_logs[i].logType == LogType.LOG3) { - assembly { log3(data, dataLength, t1, t2, t3) } + assembly { log3(add(data, 32), dataLength, t1, t2, t3) } } else if (_logs[i].logType == LogType.LOG4) { - assembly { log4(data, dataLength, t1, t2, t3, t4) } + assembly { log4(add(data, 32), dataLength, t1, t2, t3, t4) } } } } diff --git a/test/helpers/stubs/generic.stub.js b/test/helpers/stubs/generic.stub.js index ee22e435f..b74a44b8c 100644 --- a/test/helpers/stubs/generic.stub.js +++ b/test/helpers/stubs/generic.stub.js @@ -2,6 +2,14 @@ const hre = require('hardhat') const { ZERO_ADDRESS } = require('../constants') class GenericStub { + static LOG_TYPE = Object.freeze({ + LOG0: 0, + LOG1: 1, + LOG2: 2, + LOG3: 3, + LOG4: 4 + }) + static GenericStubContract = hre.artifacts.require('GenericStub') static async new(contractName) { @@ -40,12 +48,19 @@ class GenericStub { * @param {string} config.forwardETH.recipient recipient address of the ETH * @param {object} config.forwardETH.value amount of ETH to send * @param {number} [config.nextState] one based state index to set after stub call + * @param {object[]} [config.emit] events to emit when stub called + * @param {string} config.emit.name name of the event to emit + * @param {object} [config.emit.args] arguments of the event + * @param {string[]} [config.emit.args.type] tuple with type names + * @param {any[]} [config.emit.args.value] tuple with values for types + * @param {bool[]} [config.emit.args.indexed] is value indexed or not */ static async stub(stubbedContract, methodName, config = {}) { const stubInstance = await GenericStub.GenericStubContract.at(stubbedContract.address) const { abi: abis } = stubbedContract const methodAbis = abis.filter((abi) => abi.type === 'function' && abi.name === methodName) + if (methodAbis.length > 1) { throw new Error('Support of methods overloading has not implemented yet') } @@ -62,9 +77,9 @@ module.exports = { } class GenericStubConfigParser { - parse(methodSignature, config) { + parse(methodAbi, config) { return { - input: this._parseInput(methodSignature, config), + input: this._parseInput(methodAbi, config), output: this._parseOutput(config), logs: this._parseLogs(config), forwardETH: this._parseForwardETH(config), @@ -89,9 +104,42 @@ class GenericStubConfigParser { return this._encode({ type: [], value: [] }) } - // TODO: implement _parseLogs(config) { - return [] + if (!config.emit || config.emit.length === 0) return [] + return config.emit.map((event) => { + // required field so just read it + const name = event.name + // if not passed event considered as without arguments + const args = event.args ? { type: event.args.type, value: event.args.value } : { type: [], value: [] } + // when indexed is passed take its values or consider all fields as non-indexed in other cases + const indexed = event.args && event.args.indexed ? event.args.indexed : args.value.map(() => false) + // filter all indexed args indices to pass them as topics + const indexedIndices = indexed.map((indexed, index) => (indexed ? index : -1)).filter((i) => i >= 0) + // filter all non-indexed args indices to pass them as data + const nonIndexedIndices = indexed.map((indexed, index) => (indexed ? -1 : index)).filter((i) => i >= 0) + + // signature of the event always goes as topic1 + const signature = this._eventSignature(name, args.type) + // collect argument into topics via ABI encoding + const topics = indexedIndices.map((i) => this._encode({ type: [args.type[i]], value: [args.value[i]] })) + // collect non-indexed args to encode them via ABI encoder and use it as data + const nonIndexedArgs = nonIndexedIndices + .map((i) => [args.type[i], args.value[i]]) + .reduce((args, [type, value]) => ({ type: [...args.type, type], value: [...args.value, value] }), { + type: [], + value: [] + }) + + const logType = topics.length + 1 // first topic is event signature + return [ + logType, + this._encode(nonIndexedArgs), + signature, + logType >= 2 ? topics[0] : '0x0', + logType >= 3 ? topics[1] : '0x0', + logType === 4 ? topics[2] : '0x0' + ] + }) } _parseForwardETH(config) { @@ -112,12 +160,17 @@ class GenericStubConfigParser { } _encodeError({ error, args }) { - const signature = this._signature(error, args.type) + const signature = this._errorSignature(error, args.type) return signature + this._encode(args).slice(2) } - _signature(name, argTypes) { + _errorSignature(name, argTypes) { const fullName = `${name}(${argTypes.join(',')})` return hre.ethers.utils.keccak256(hre.ethers.utils.toUtf8Bytes(fullName)).slice(0, 10) } + + _eventSignature(name, argTypes) { + const fullName = `${name}(${argTypes.join(',')})` + return hre.ethers.utils.keccak256(hre.ethers.utils.toUtf8Bytes(fullName)) + } } From 354f0814753e536c3c951362fe07a8b3cff457fb Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Mon, 20 Feb 2023 02:51:18 +0400 Subject: [PATCH 127/199] update wei to use wei.int and wei.str as JS tags --- test/0.4.24/lido-deposit-scenarios.test.js | 4 +- test/helpers/wei.js | 86 ++++++++++++++++------ 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/test/0.4.24/lido-deposit-scenarios.test.js b/test/0.4.24/lido-deposit-scenarios.test.js index a8c79c9fa..9950d6f0b 100644 --- a/test/0.4.24/lido-deposit-scenarios.test.js +++ b/test/0.4.24/lido-deposit-scenarios.test.js @@ -35,7 +35,7 @@ hre.contract('Lido deposit scenarios', ([staker, depositor]) => { depositSecurityModuleFactory: async () => ({ address: depositor }), depositContractFactory: () => depositContractStub, postSetup: async ({ pool, lidoLocator, eip712StETH, voting }) => { - await pool.initialize(lidoLocator.address, eip712StETH.address, { value: wei.str(wei`1 ether`) }) + await pool.initialize(lidoLocator.address, eip712StETH.address, { value: wei.str`1 ether` }) await pool.resumeProtocolAndStaking({ from: voting.address }) } }) @@ -195,7 +195,7 @@ hre.contract('Lido deposit scenarios', ([staker, depositor]) => { it('invalid ETH value was used for deposits in StakingRouter', async () => { // on each deposit call forward back 1 ether to the staking router await GenericStub.stub(depositContractStub, 'deposit', { - forwardETH: { value: wei.str(wei`1 ether`), recipient: stakingRouter.address } + forwardETH: { value: wei.str`1 ether`, recipient: stakingRouter.address } }) const submitAmount = wei`320 ether` diff --git a/test/helpers/wei.js b/test/helpers/wei.js index 30592c841..f15da3916 100644 --- a/test/helpers/wei.js +++ b/test/helpers/wei.js @@ -1,10 +1,69 @@ const hre = require('hardhat') -function wei(strings, ...values) { +function wei(...args) { + return parseWeiExpression(weiExpressionTag(...args)) +} + +wei.int = (...args) => { + if (args.length === 0) { + throw new Error('No arguments provided to wei.int() call') + } + + // when str is used as JS tag it first argument will be array of strings + if (Array.isArray(args[0]) && args[0].every((e) => typeof e === 'string')) { + return wei(...args) + } + + // when first argument is string, consider it as wei expression + if (typeof args[0] === 'string') { + return wei(...args) + } + + // in all other cases just cast first item to string and convert it to BigInt + return BigInt(args[0].toString()) +} + +wei.str = (...args) => { + if (args.length === 0) { + throw new Error('No arguments provided to wei.str() call') + } + + // when str is used as JS tag it first argument will be array of strings + if (Array.isArray(args[0]) && args[0].every((e) => typeof e === 'string')) { + return wei(...args).toString() + } + + // when first argument is string, consider it as wei expression + if (typeof args[0] === 'string') { + return wei(...args).toString() + } + + // in all other cases just cast first item to string + return args[0].toString() +} + +wei.min = (...values) => { + if (values.length === 0) { + throw new Error(`No arguments provided to wei.min() call`) + } + return values.reduce((min, value) => (wei.int(value) < min ? wei.int(value) : min), wei.int(values[0])) +} + +wei.max = (...values) => { + if (values.length === 0) { + throw new Error(`No arguments provided to wei.min() call`) + } + return values.reduce((max, value) => (wei.int(value) > max ? wei.int(value) : max), wei.int(values[0])) +} + +function weiExpressionTag(strings, ...values) { + if (!Array.isArray(strings) && typeof strings !== 'string') { + throw new Error(`wei was used with invalid arg type. Make sure that was passed valid JS template string`) + } // when wei used not like js tag but called like regular function // the first argument will be string instead of array of strings if (typeof strings === 'string') { - throw new Error("Invalid wei tag usage. Please, use it like JS tag: wei`1 ether` instead of: wei('1 ether')") + strings = [strings] } // case when wei used without arguments @@ -15,9 +74,12 @@ function wei(strings, ...values) { // combine interpolations in one expression let expression = strings[0] for (let i = 1; i < strings.length; ++i) { - expression += values[i - 1] + strings[i] + expression += values[i - 1].toString() + strings[i] } + return expression +} +function parseWeiExpression(expression) { const [amount, unit = 'wei'] = expression .replaceAll('_', '') // remove all _ from numbers written like '100_00' .trim() // remove all leading and trealing spaces @@ -31,24 +93,6 @@ function wei(strings, ...values) { return BigInt(hre.web3.utils.toWei(amount, unit.toLowerCase())) } -wei.int = (value) => BigInt(value.toString()) - -wei.str = (value) => value.toString() - -wei.min = (...values) => { - if (values.length === 0) { - throw new Error(`No arguments provided to wei.min() call`) - } - return values.reduce((min, value) => (wei.int(value) < min ? wei.int(value) : min), wei.int(values[0])) -} - -wei.max = (...values) => { - if (values.length === 0) { - throw new Error(`No arguments provided to wei.min() call`) - } - return values.reduce((max, value) => (wei.int(value) > max ? wei.int(value) : max), wei.int(values[0])) -} - module.exports = { wei } From e2462c75048496bdb2a3c99878cb3e80f1b0448f Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Mon, 20 Feb 2023 02:55:43 +0400 Subject: [PATCH 128/199] Remove dead code and rename props in GenericStub --- contracts/0.8.9/test_helpers/GenericStub.sol | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/contracts/0.8.9/test_helpers/GenericStub.sol b/contracts/0.8.9/test_helpers/GenericStub.sol index e965ad09d..85d1957c3 100644 --- a/contracts/0.8.9/test_helpers/GenericStub.sol +++ b/contracts/0.8.9/test_helpers/GenericStub.sol @@ -33,7 +33,7 @@ contract GenericStub { bytes32 t4; } - struct ETHForward { + struct ForwardETH { address payable recipient; uint256 value; } @@ -46,7 +46,7 @@ contract GenericStub { /// @notice events to emit during method execution Log[] logs; /// @notice optional ETH send on method execution - ETHForward ethForward; + ForwardETH forwardETH; /// @notice shall method ends with revert instead of return bool isRevert; /// @notice index of the state to set as current after stub call @@ -75,7 +75,7 @@ contract GenericStub { uint256 newStubIndex = currentState.stubs.length - 1; currentState.stubs[newStubIndex].input = _stub.input; currentState.stubs[newStubIndex].output = _stub.output; - currentState.stubs[newStubIndex].ethForward = _stub.ethForward; + currentState.stubs[newStubIndex].forwardETH = _stub.forwardETH; currentState.stubs[newStubIndex].isRevert = _stub.isRevert; currentState.stubs[newStubIndex].nextStateIndexOneBased = _stub.nextStateIndexOneBased; @@ -98,15 +98,9 @@ contract GenericStub { _currentStateIndexOneBased = _stateIndex; } - - // function GenericStub__cloneState(uint256 _clonedStateIndex) external { - // _states.push(_getState(_clonedStateIndex)); - // } - - fallback() external payable { MethodStub memory stub = _getMethodStub(); - _forwardETH(stub.ethForward); + _forwardETH(stub.forwardETH); _logEvents(stub.logs); bytes memory output = stub.output; uint256 outputLength = output.length; @@ -141,7 +135,7 @@ contract GenericStub { } } - function _forwardETH(ETHForward memory _ethForward) internal { + function _forwardETH(ForwardETH memory _ethForward) internal { if (_ethForward.value == 0) return; new ETHForwarder{value: _ethForward.value}(_ethForward.recipient); emit GenericStub__ethSent(_ethForward.recipient, _ethForward.value); From 23fbc1b0e8a315b3258178042a05fae0fcba59cd Mon Sep 17 00:00:00 2001 From: Logachev Nikita Date: Mon, 20 Feb 2023 13:15:10 +0700 Subject: [PATCH 129/199] fix bytes --- test/0.4.24/lido.test.js | 10 +++-- .../node-operators-registry-penalty.test.js | 38 +++++++++---------- test/0.4.24/node-operators-registry.test.js | 11 +----- test/deposit.test.js | 8 ++-- test/helpers/utils.js | 12 +++++- test/scenario/lido_penalties_slashing.js | 5 ++- 6 files changed, 46 insertions(+), 38 deletions(-) diff --git a/test/0.4.24/lido.test.js b/test/0.4.24/lido.test.js index 1ddb37ef9..9a54a2c17 100644 --- a/test/0.4.24/lido.test.js +++ b/test/0.4.24/lido.test.js @@ -10,6 +10,7 @@ const { assertRevert } = require('../helpers/assertThrow') const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') const { formatEther } = require('ethers/lib/utils') const { waitBlocks, EvmSnapshot } = require('../helpers/blockchain') + const { getEthBalance, formatStEth, @@ -21,7 +22,8 @@ const { div15, assertNoEvent, StETH, - setBalance + setBalance, + prepIdsCountsPayload } = require('../helpers/utils') const { assert } = require('../helpers/assert') const nodeOperators = require('../helpers/node-operators') @@ -1348,7 +1350,8 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody assertBn(await operators.getUnusedSigningKeyCount(3, { from: nobody }), 0) // #1 goes below the limit - await operators.updateExitedValidatorsCount(1, 1, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(1, 1) + await operators.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(1) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 3, beaconValidators: 0, beaconBalance: ETH(0) }) @@ -1474,7 +1477,8 @@ contract('Lido', ([appManager, , , , , , , , , , , , user1, user2, user3, nobody assertBn(await operators.getUnusedSigningKeyCount(3, { from: nobody }), 0) // #1 goes below the limit (doesn't change situation. validator stop decreases limit) - await operators.updateExitedValidatorsCount(1, 1, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(1, 1) + await operators.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(1) }) await app.methods['deposit(uint256,uint256,bytes)'](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) await checkStat({ depositedValidators: 3, beaconValidators: 0, beaconBalance: ETH(0) }) diff --git a/test/0.4.24/node-operators-registry-penalty.test.js b/test/0.4.24/node-operators-registry-penalty.test.js index cfb05752b..5868b4c8b 100644 --- a/test/0.4.24/node-operators-registry-penalty.test.js +++ b/test/0.4.24/node-operators-registry-penalty.test.js @@ -1,15 +1,12 @@ const hre = require('hardhat') -const { assert } = require('../helpers/assert') -const { assertRevert } = require('../helpers/assertThrow') -const { toBN, padRight, printEvents } = require('../helpers/utils') +const { web3 } = require('hardhat') +const { bn } = require('@aragon/contract-helpers-test') const { BN } = require('bn.js') + +const { assert } = require('../helpers/assert') +const { padRight, prepIdsCountsPayload } = require('../helpers/utils') const { AragonDAO } = require('./helpers/dao') const { EvmSnapshot } = require('../helpers/blockchain') -const { ZERO_ADDRESS, getEventAt, bn } = require('@aragon/contract-helpers-test') -const nodeOperators = require('../helpers/node-operators') -const signingKeys = require('../helpers/signing-keys') -const { web3 } = require('hardhat') -const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') const { getRandomLocatorConfig } = require('../helpers/locator') const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistryMock') @@ -135,7 +132,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use // Implementation initializer reverts because initialization block was set to max(uint256) // in the Autopetrified base contract // await assert.reverts(appBase.initialize(steth.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') - await assertRevert(appBase.initialize(locator.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') + await assert.reverts(appBase.initialize(locator.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') const moduleType = await app.getType() assert.emits(tx, 'ContractVersionSet', { version: 2 }) @@ -431,7 +428,8 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use //increase _newActiveValidatorsCount by add new depositedKeys await app.increaseNodeOperatorDepositedSigningKeysCount(3, 2) - await app.updateExitedValidatorsCount(3, 1, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(3, 1) + await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) }) @@ -465,18 +463,18 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use await app.updateTargetValidatorsLimits(0, true, 10, { from: voting }) let keysStatTotal = await app.getStakingModuleSummary() - assert.equal(keysStatTotal.totalExitedValidators, 2) - assert.equal(keysStatTotal.totalDepositedValidators, 25) - assert.equal(keysStatTotal.depositableValidatorsCount, 17) + assert.equal(+keysStatTotal.totalExitedValidators, 2) + assert.equal(+keysStatTotal.totalDepositedValidators, 25) + assert.equal(+keysStatTotal.depositableValidatorsCount, 17) let limitStatOp = await app.getNodeOperatorSummary(0) assert.equal(limitStatOp.isTargetLimitActive, true) - assert.equal(limitStatOp.targetValidatorsCount, 10) + assert.equal(+limitStatOp.targetValidatorsCount, 10) let keysStatOp = await app.getNodeOperatorSummary(0) - assert.equal(keysStatOp.totalExitedValidators, 2) + assert.equal(+keysStatOp.totalExitedValidators, 2) assert.equal(keysStatOp.totalDepositedValidators.toNumber()-keysStatOp.totalExitedValidators.toNumber(), 8) - assert.equal(keysStatOp.depositableValidatorsCount, 2) + assert.equal(+keysStatOp.depositableValidatorsCount, 2) await app.updateTargetValidatorsLimits(0, false, 10, { from: voting }) @@ -526,8 +524,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use assert.equal(keysStatOp.depositableValidatorsCount, 0) // console.log(o2n(limitStatOp)) - await app.updateExitedValidatorsCount(0, 3, { from: voting }) - await app.updateExitedValidatorsCount(1, 1, { from: voting }) + const { operatorIds: operatorIds1, keysCounts: keysCounts1 } = prepIdsCountsPayload(0, 3) + const { operatorIds: operatorIds2, keysCounts: keysCounts2 } = prepIdsCountsPayload(1, 1) + await app.updateExitedValidatorsCount(operatorIds1, keysCounts1, { from: voting }) + await app.updateExitedValidatorsCount(operatorIds2, keysCounts2, { from: voting }) keysStatTotal = await app.getStakingModuleSummary() // console.log(o2n(keysStatTotal)) @@ -594,7 +594,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use function o2n(o = {}) { for (const k of Object.keys(o)) { - if (BN.isBN(o[k])) { + if (bn.isBN(o[k])) { o[k] = o[k].toString() } } diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index f0b7b9a03..c9706deb9 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -7,7 +7,7 @@ const { EvmSnapshot } = require('../helpers/blockchain') const { ZERO_ADDRESS, getEventAt } = require('@aragon/contract-helpers-test') const nodeOperators = require('../helpers/node-operators') const signingKeys = require('../helpers/signing-keys') -const { hex } = require('../helpers/utils') +const { prepIdsCountsPayload } = require('../helpers/utils') const { web3, artifacts } = require('hardhat') const { getRandomLocatorConfig } = require('../helpers/locator') const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') @@ -79,15 +79,6 @@ const hexConcat = (first, ...rest) => { const ETH = (value) => web3.utils.toWei(value + '', 'ether') const StETH = artifacts.require('StETHMock') -function prepIdsCountsPayload(ids, counts) { - if (!Array.isArray(ids)) ids = [ids] - if (!Array.isArray(counts)) counts = [counts] - return { - operatorIds: '0x' + ids.map((id) => hex(id, 8)).join(''), - keysCounts: '0x' + counts.map((count) => hex(count, 16)).join('') - } -} - contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nobody]) => { let appBase, app, locator, steth, dao const snapshot = new EvmSnapshot(hre.ethers.provider) diff --git a/test/deposit.test.js b/test/deposit.test.js index c5bbbc078..5bf72007c 100644 --- a/test/deposit.test.js +++ b/test/deposit.test.js @@ -6,7 +6,7 @@ const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') const { EvmSnapshot } = require('./helpers/blockchain') const { setupNodeOperatorsRegistry } = require('./helpers/staking-modules') const { deployProtocol } = require('./helpers/protocol') -const { ETH, pad, hexConcat, changeEndianness } = require('./helpers/utils') +const { ETH, pad, hexConcat, changeEndianness, prepIdsCountsPayload } = require('./helpers/utils') const nodeOperators = require('./helpers/node-operators') const { assert } = require('./helpers/assert') const { depositContractFactory } = require('./helpers/factories') @@ -260,7 +260,8 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d assertBn(await operators.getUnusedSigningKeyCount(3, { from: nobody }), 0) // #1 goes below the limit (nothing changed cause staking limit decreases) - await operators.updateExitedValidatorsCount(1, 1, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(1, 1) + await operators.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(1) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) @@ -391,7 +392,8 @@ contract('Lido with official deposit contract', ([user1, user2, user3, nobody, d assertBn(await operators.getUnusedSigningKeyCount(3, { from: nobody }), 0) // #1 goes below the limit (nothing changed cause staking limit decreases) - await operators.updateExitedValidatorsCount(1, 1, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(1, 1) + await operators.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) await web3.eth.sendTransaction({ to: app.address, from: user3, value: ETH(1) }) await app.methods[`deposit(uint256,uint256,bytes)`](MAX_DEPOSITS, CURATED_MODULE_ID, CALLDATA, { from: depositor }) diff --git a/test/helpers/utils.js b/test/helpers/utils.js index 27bcd91b9..bdaa8e559 100644 --- a/test/helpers/utils.js +++ b/test/helpers/utils.js @@ -145,6 +145,15 @@ const setBalance = async (address, value) => { await hre.network.provider.send('hardhat_setBalance', [address, web3.utils.numberToHex(value)]) } +const prepIdsCountsPayload = (ids, counts) => { + if (!Array.isArray(ids)) ids = [ids] + if (!Array.isArray(counts)) counts = [counts] + return { + operatorIds: '0x' + ids.map((id) => hex(id, 8)).join(''), + keysCounts: '0x' + counts.map((count) => hex(count, 16)).join('') + } +} + module.exports = { ZERO_HASH, pad, @@ -178,5 +187,6 @@ module.exports = { padRight, toNum, toStr, - setBalance + setBalance, + prepIdsCountsPayload } diff --git a/test/scenario/lido_penalties_slashing.js b/test/scenario/lido_penalties_slashing.js index ffb5b6b0b..438e24321 100644 --- a/test/scenario/lido_penalties_slashing.js +++ b/test/scenario/lido_penalties_slashing.js @@ -4,7 +4,7 @@ const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') const { getEventArgument } = require('@aragon/contract-helpers-test') const { assert } = require('../helpers/assert') -const { pad, ETH, tokens, toBN } = require('../helpers/utils') +const { pad, ETH, tokens, prepIdsCountsPayload } = require('../helpers/utils') const { waitBlocks } = require('../helpers/blockchain') const { deployProtocol } = require('../helpers/protocol') const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') @@ -641,7 +641,8 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { await pushReport(2, ETH(96)) // kicks rewards distribution - await nodeOperatorsRegistry.updateExitedValidatorsCount(0, 1, { from: voting }) + const { operatorIds, keysCounts } = prepIdsCountsPayload(0, 1) + await nodeOperatorsRegistry.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) const nodeOperator1TokenSharesAfter = await token.sharesOf(nodeOperator1.address) const nodeOperator2TokenSharesAfter = await token.sharesOf(nodeOperator2.address) From 320e6aa87e6d06c15344e33cd71b043ab982a2c0 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Mon, 20 Feb 2023 15:10:44 +0700 Subject: [PATCH 130/199] chore: format submit report data test --- ...exit-bus-oracle-submit-report-data.test.js | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index facf9dfc8..220b2fef3 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -9,17 +9,15 @@ const { deployExitBusOracle } = require('./validators-exit-bus-oracle-deploy.test') - const PUBKEYS = [ '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', '0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', - '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ] contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger]) => { - context('submitReportData', () => { const LAST_PROCESSING_REF_SLOT = 1 @@ -36,29 +34,29 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger consensus = deployed.consensus oracle = deployed.oracle - oracleVersion = +await oracle.getContractVersion() + oracleVersion = +(await oracle.getContractVersion()) - await consensus.addMember(member1, 1, {from: admin}) - await consensus.addMember(member2, 2, {from: admin}) - await consensus.addMember(member3, 2, {from: admin}) + await consensus.addMember(member1, 1, { from: admin }) + await consensus.addMember(member2, 2, { from: admin }) + await consensus.addMember(member3, 2, { from: admin }) } async function triggerConsensusOnHash(hash) { - const {refSlot} = await consensus.getCurrentFrame() + const { refSlot } = await consensus.getCurrentFrame() await consensus.submitReport(refSlot, hash, CONSENSUS_VERSION, { from: member1 }) await consensus.submitReport(refSlot, hash, CONSENSUS_VERSION, { from: member3 }) assert.equal((await consensus.getConsensusState()).consensusReport, hash) } async function prepareReportAndSubmitHash(exitRequests) { - const {refSlot} = await consensus.getCurrentFrame() + const { refSlot } = await consensus.getCurrentFrame() const reportFields = { consensusVersion: CONSENSUS_VERSION, refSlot: +refSlot, requestsCount: exitRequests.length, dataFormat: DATA_FORMAT_LIST, - data: encodeExitRequestsDataList(exitRequests), + data: encodeExitRequestsDataList(exitRequests) } const reportItems = getReportDataItems(reportFields) @@ -79,19 +77,19 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger it(`requesting NO 5-3 to exit validator 0`, async () => { await consensus.advanceTimeToNextFrameStart() const report = await prepareReportAndSubmitHash([ - {moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }, + { moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] } ]) - await oracle.submitReportData(report, oracleVersion, {from: member1}) + await oracle.submitReportData(report, oracleVersion, { from: member1 }) assert.equal(await getLastRequestedValidatorIndex(5, 3), 0) }) it(`cannot request NO 5-3 to exit validator 0 again`, async () => { await consensus.advanceTimeToNextFrameStart() const report = await prepareReportAndSubmitHash([ - {moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }, + { moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] } ]) await assert.reverts( - oracle.submitReportData(report, oracleVersion, {from: member1}), + oracle.submitReportData(report, oracleVersion, { from: member1 }), 'NodeOpValidatorIndexMustIncrease(5, 3, 0, 0)' ) }) @@ -99,19 +97,19 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger it(`requesting NO 5-3 to exit validator 1`, async () => { await consensus.advanceTimeToNextFrameStart() const report = await prepareReportAndSubmitHash([ - {moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[1] }, + { moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[1] } ]) - await oracle.submitReportData(report, oracleVersion, {from: member1}) + await oracle.submitReportData(report, oracleVersion, { from: member1 }) assert.equal(await getLastRequestedValidatorIndex(5, 3), 1) }) it(`cannot request NO 5-3 to exit validator 1 again`, async () => { await consensus.advanceTimeToNextFrameStart() const report = await prepareReportAndSubmitHash([ - {moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[1] }, + { moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[1] } ]) await assert.reverts( - oracle.submitReportData(report, oracleVersion, {from: member1}), + oracle.submitReportData(report, oracleVersion, { from: member1 }), 'NodeOpValidatorIndexMustIncrease(5, 3, 1, 1)' ) }) @@ -119,10 +117,10 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger it(`cannot request NO 5-3 to exit validator 0 again`, async () => { await consensus.advanceTimeToNextFrameStart() const report = await prepareReportAndSubmitHash([ - {moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }, + { moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] } ]) await assert.reverts( - oracle.submitReportData(report, oracleVersion, {from: member1}), + oracle.submitReportData(report, oracleVersion, { from: member1 }), 'NodeOpValidatorIndexMustIncrease(5, 3, 1, 0)' ) }) @@ -130,11 +128,11 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger it(`cannot request NO 5-3 to exit validator 1 again (multiple requests)`, async () => { await consensus.advanceTimeToNextFrameStart() const report = await prepareReportAndSubmitHash([ - {moduleId: 5, nodeOpId: 1, valIndex: 10, valPubkey: PUBKEYS[0] }, - {moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[0] }, + { moduleId: 5, nodeOpId: 1, valIndex: 10, valPubkey: PUBKEYS[0] }, + { moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[0] } ]) await assert.reverts( - oracle.submitReportData(report, oracleVersion, {from: member1}), + oracle.submitReportData(report, oracleVersion, { from: member1 }), 'NodeOpValidatorIndexMustIncrease(5, 3, 1, 1)' ) }) @@ -142,12 +140,12 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger it(`cannot request NO 5-3 to exit validator 1 again (multiple requests, case 2)`, async () => { await consensus.advanceTimeToNextFrameStart() const report = await prepareReportAndSubmitHash([ - {moduleId: 5, nodeOpId: 1, valIndex: 10, valPubkey: PUBKEYS[2] }, - {moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[3] }, - {moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[4] }, + { moduleId: 5, nodeOpId: 1, valIndex: 10, valPubkey: PUBKEYS[2] }, + { moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[3] }, + { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[4] } ]) await assert.reverts( - oracle.submitReportData(report, oracleVersion, {from: member1}), + oracle.submitReportData(report, oracleVersion, { from: member1 }), 'NodeOpValidatorIndexMustIncrease(5, 3, 1, 1)' ) }) @@ -155,11 +153,11 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger it(`cannot request NO 5-3 to exit validator 2 two times per request`, async () => { await consensus.advanceTimeToNextFrameStart() const report = await prepareReportAndSubmitHash([ - {moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[2] }, - {moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[3] }, + { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[2] }, + { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[3] } ]) await assert.reverts( - oracle.submitReportData(report, oracleVersion, {from: member1}), + oracle.submitReportData(report, oracleVersion, { from: member1 }), 'InvalidRequestsDataSortOrder()' ) }) From 0fc22a8dbca142d40bf98d44bcb212d449be8942 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Mon, 20 Feb 2023 11:48:43 +0300 Subject: [PATCH 131/199] fix: initialization fixes to match the upstream --- lib/abi/ValidatorsExitBusOracle.json | 2 +- .../validators-exit-bus-oracle-access-control.test.js | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/abi/ValidatorsExitBusOracle.json b/lib/abi/ValidatorsExitBusOracle.json index 2ec19a6fe..d8dfe9d41 100644 --- a/lib/abi/ValidatorsExitBusOracle.json +++ b/lib/abi/ValidatorsExitBusOracle.json @@ -1 +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":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidRequestsData","type":"error"},{"inputs":[],"name":"InvalidRequestsDataLength","type":"error"},{"inputs":[],"name":"InvalidRequestsDataSortOrder","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","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":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"ResumedExpected","type":"error"},{"inputs":[],"name":"SenderNotAllowed","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":[],"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":"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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"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":"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":[],"name":"getLastProcessingRefSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256[]","name":"nodeOpIds","type":"uint256[]"}],"name":"getLastRequestedValidatorIndices","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"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":"pauser","type":"address"},{"internalType":"address","name":"resumer","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"lastProcessingRefSlot","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":"pause","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":"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":"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"}] \ No newline at end of file +[{"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":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidRequestsData","type":"error"},{"inputs":[],"name":"InvalidRequestsDataLength","type":"error"},{"inputs":[],"name":"InvalidRequestsDataSortOrder","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256","name":"nodeOpId","type":"uint256"},{"internalType":"uint256","name":"prevRequestedValidatorIndex","type":"uint256"},{"internalType":"uint256","name":"requestedValidatorIndex","type":"uint256"}],"name":"NodeOpValidatorIndexMustIncrease","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","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":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"ResumedExpected","type":"error"},{"inputs":[],"name":"SenderNotAllowed","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":[],"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":"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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"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":"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":[],"name":"getLastProcessingRefSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256[]","name":"nodeOpIds","type":"uint256[]"}],"name":"getLastRequestedValidatorIndices","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"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":"pauser","type":"address"},{"internalType":"address","name":"resumer","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"lastProcessingRefSlot","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":"pause","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":"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":"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"}] \ No newline at end of file diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js index 1ac172c9d..3d837048e 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js @@ -86,15 +86,17 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, account1 context('DEFAULT_ADMIN_ROLE', () => { beforeEach(deploy) - context('Admin is set at initialise', () => { - it('should set admin at initialise', async () => { + context('Admin is set at initialize', () => { + it('should set admin at initialize', async () => { const DEFAULT_ADMIN_ROLE = await oracle.DEFAULT_ADMIN_ROLE() await assert.emits(initTx, 'RoleGranted', { role: DEFAULT_ADMIN_ROLE, account: admin, sender: admin }) }) it('should revert without admin address', async () => { + const pauser = ZERO_ADDRESS + const resumer = ZERO_ADDRESS await assert.reverts( - oracle.initialize(ZERO_ADDRESS, consensus.address, CONSENSUS_VERSION, 0, { + oracle.initialize(ZERO_ADDRESS, pauser, resumer, consensus.address, CONSENSUS_VERSION, 0, { from: admin }), 'AdminCannotBeZero()' From b57fbb233783d528c655e91c2da966a3d7eacead Mon Sep 17 00:00:00 2001 From: Andrei Date: Mon, 20 Feb 2023 16:17:58 +0700 Subject: [PATCH 132/199] test: validatorsExitBus oracle: access control: minor fix --- .../oracle/validators-exit-bus-oracle-access-control.test.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js index 3d837048e..684e59a81 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-access-control.test.js @@ -12,9 +12,7 @@ const { const PUBKEYS = [ '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', - '0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', - '0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', - '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' ] contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, account1, stranger]) => { From 22f0430d58d2b20c5fcd64205d9a7e2d72007f84 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Mon, 20 Feb 2023 16:34:43 +0700 Subject: [PATCH 133/199] test: ValidatorsExitBusOracle._handleConsensusReportData enforces data format --- ...exit-bus-oracle-submit-report-data.test.js | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index 220b2fef3..b4f3007bb 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -48,7 +48,8 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger assert.equal((await consensus.getConsensusState()).consensusReport, hash) } - async function prepareReportAndSubmitHash(exitRequests) { + async function prepareReportAndSubmitHash(exitRequests, options = {}) { + const { reportFields: reportFieldsArg = {} } = options const { refSlot } = await consensus.getCurrentFrame() const reportFields = { @@ -56,7 +57,8 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger refSlot: +refSlot, requestsCount: exitRequests.length, dataFormat: DATA_FORMAT_LIST, - data: encodeExitRequestsDataList(exitRequests) + data: encodeExitRequestsDataList(exitRequests), + ...reportFieldsArg } const reportItems = getReportDataItems(reportFields) @@ -71,6 +73,46 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger return +(await oracle.getLastRequestedValidatorIndices(moduleId, [nodeOpId]))[0] } + context('_handleConsensusReportData', () => { + beforeEach(async () => { + await setup() + await consensus.advanceTimeToNextFrameStart() + }) + + context('enforces data format', () => { + it('dataFormat = 0 reverts', async () => { + const dataFormatUnsupported = 0 + const report = await prepareReportAndSubmitHash( + [{ moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }], + { reportFields: { dataFormat: dataFormatUnsupported } } + ) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, { from: member1 }), + `UnsupportedRequestsDataFormat(${dataFormatUnsupported})` + ) + }) + + it('dataFormat = 2 reverts', async () => { + const dataFormatUnsupported = 2 + const report = await prepareReportAndSubmitHash( + [{ moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }], + { reportFields: { dataFormat: dataFormatUnsupported } } + ) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, { from: member1 }), + `UnsupportedRequestsDataFormat(${dataFormatUnsupported})` + ) + }) + + it('dataFormat = 1 pass', async () => { + const report = await prepareReportAndSubmitHash([ + { moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] } + ]) + await oracle.submitReportData(report, oracleVersion, { from: member1 }) + }) + }) + }) + context(`requires validator indices for the same node operator to increase`, () => { before(setup) From c5d3a4f214999e4f8ef7fed5f988ba29412e48b4 Mon Sep 17 00:00:00 2001 From: Alexandr Tarelkin Date: Mon, 20 Feb 2023 12:51:43 +0300 Subject: [PATCH 134/199] update handle report test --- test/0.4.24/lido-handle-oracle-report.test.js | 515 ++++++++++++++++-- 1 file changed, 483 insertions(+), 32 deletions(-) diff --git a/test/0.4.24/lido-handle-oracle-report.test.js b/test/0.4.24/lido-handle-oracle-report.test.js index fb9cd8faf..c23ddb927 100644 --- a/test/0.4.24/lido-handle-oracle-report.test.js +++ b/test/0.4.24/lido-handle-oracle-report.test.js @@ -5,6 +5,7 @@ const { deployProtocol } = require('../helpers/protocol') const { EvmSnapshot } = require('../helpers/blockchain') const { ZERO_ADDRESS, INITIAL_HOLDER } = require('../helpers/constants') const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') +const Lido = artifacts.require('Lido') const ONE_YEAR = 3600 * 24 * 365 const ONE_DAY = 3600 * 24 @@ -20,6 +21,79 @@ const ORACLE_REPORT_LIMITS_BOILERPLATE = { maxPositiveTokenRebase: 1000000000, } +const checkEvents = async ({ + tx, + reportTimestamp = 0, + preCLValidators, + postCLValidators, + preCLBalance, + postCLBalance, + withdrawalsWithdrawn, + executionLayerRewardsWithdrawn, + postBufferedEther, + timeElapsed, + preTotalShares, + preTotalEther, + postTotalShares, + postTotalEther, + sharesMintedAsFees +}) => { + assert.emits( + tx, + 'CLValidatorsUpdated', + { + reportTimestamp: 0, + preCLValidators, + postCLValidators + }, + { + abi: Lido.abi + } + ) + assert.emits( + tx, + 'ETHDistributed', + { + reportTimestamp, + preCLBalance, + postCLBalance, + withdrawalsWithdrawn, + executionLayerRewardsWithdrawn, + postBufferedEther + }, + { + abi: Lido.abi + } + ) + assert.emits( + tx, + 'TokenRebased', + { + reportTimestamp, + timeElapsed, + preTotalShares, + preTotalEther, + postTotalShares, + postTotalEther, + sharesMintedAsFees + }, + { + abi: Lido.abi + } + ) +} + +const calcSharesMintedAsFees = (rewards, fee, feePoints, prevTotalShares, newTotalEther) => { + return toBN(rewards) + .mul(toBN(fee)) + .mul(toBN(prevTotalShares)) + .div( + toBN(newTotalEther) + .mul(toBN(feePoints)) + .sub(toBN(rewards).mul(toBN(fee))) + ) +} + contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, anotherStranger, depositor, operator]) => { let deployed, snapshot, lido, treasury, voting, oracle let curatedModule, oracleReportSanityChecker, elRewardsVault @@ -28,7 +102,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another anotherStrangerBalanceBefore, totalPooledEtherBefore, curatedModuleBalanceBefore, - treasuryBalanceBefore + treasuryBalanceBefore, + initialHolderBalanceBefore before('deploy base app', async () => { deployed = await deployProtocol({ @@ -97,6 +172,7 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another anotherStrangerBalanceBefore = await lido.balanceOf(anotherStranger) treasuryBalanceBefore = await lido.balanceOf(treasury) curatedModuleBalanceBefore = await lido.balanceOf(curatedModule.address) + initialHolderBalanceBefore = await lido.balanceOf(INITIAL_HOLDER) } const checkBalanceDeltas = async ({ @@ -104,7 +180,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff, strangerBalanceDiff, anotherStrangerBalanceDiff, - curatedModuleBalanceDiff + curatedModuleBalanceDiff, + initialHolderBalanceDiff }) => { assert.equals( await lido.getTotalPooledEther(), @@ -135,6 +212,12 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another 1, 'another stranger balance check' ) + assert.equalsDelta( + await lido.balanceOf(INITIAL_HOLDER), + toBN(initialHolderBalanceBefore).add(toBN(initialHolderBalanceDiff)), + 1, + 'another stranger balance check' + ) } it('handleOracleReport access control', async () => { @@ -147,14 +230,32 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another }) it('zero report should do nothing', async () => { - await lido.handleOracleReport(0, 0, 0, 0, 0, 0, 0, 0, { from: oracle }) + const tx = await lido.handleOracleReport(0, 0, 0, 0, 0, 0, 0, 0, { from: oracle }) + await checkEvents({ + tx, + preCLValidators: 0, + postCLValidators: 0, + preCLBalance: ETH(0), + postCLBalance: ETH(0), + withdrawalsWithdrawn: 0, + executionLayerRewardsWithdrawn: 0, + postBufferedEther: ETH(100), + timeElapsed: 0, + preTotalShares: ETH(100), + preTotalEther: ETH(100), + postTotalShares: ETH(100), + postTotalEther: ETH(100), + sharesMintedAsFees: 0 + }) + await checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: 0 }) await checkBalanceDeltas({ totalPooledEtherDiff: 0, treasuryBalanceDiff: 0, strangerBalanceDiff: 0, anotherStrangerBalanceDiff: 0, - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 }) }) @@ -167,25 +268,61 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: 0, strangerBalanceDiff: 0, anotherStrangerBalanceDiff: 0, - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 }) }) it('first report after deposit without rewards', async () => { - await lido.handleOracleReport(0, 0, 1, ETH(32), 0, 0, 0, 0, { from: oracle }) + const tx = await lido.handleOracleReport(0, 0, 1, ETH(32), 0, 0, 0, 0, { from: oracle }) + await checkEvents({ + tx, + preCLValidators: 0, + postCLValidators: 1, + preCLBalance: ETH(32), + postCLBalance: ETH(32), + withdrawalsWithdrawn: 0, + executionLayerRewardsWithdrawn: 0, + postBufferedEther: ETH(4), + timeElapsed: 0, + preTotalShares: ETH(100), + preTotalEther: ETH(100), + postTotalShares: ETH(100), + postTotalEther: ETH(100), + sharesMintedAsFees: 0 + }) + await checkStat({ depositedValidators: 3, beaconValidators: 1, beaconBalance: ETH(32) }) await checkBalanceDeltas({ totalPooledEtherDiff: 0, treasuryBalanceDiff: 0, strangerBalanceDiff: 0, anotherStrangerBalanceDiff: 0, - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 }) }) it('first report after deposit with rewards', async () => { - // elapsed time set to 1000000 because of annualBalanceIncrease limited by 10000 - await lido.handleOracleReport(0, 1000000, 1, ETH(33), 0, 0, 0, 0, { from: oracle }) + const tx = await lido.handleOracleReport(0, ONE_YEAR, 1, ETH(33), 0, 0, 0, 0, { from: oracle }) + const sharesMintedAsFees = calcSharesMintedAsFees(ETH(1), 10, 100, ETH(100), ETH(101)) + await checkEvents({ + tx, + preCLValidators: 0, + postCLValidators: 1, + preCLBalance: ETH(32), + postCLBalance: ETH(33), + withdrawalsWithdrawn: 0, + executionLayerRewardsWithdrawn: 0, + postBufferedEther: ETH(4), + timeElapsed: ONE_YEAR, + preTotalShares: ETH(100), + preTotalEther: ETH(100), + postTotalShares: toBN(ETH(100)).add(sharesMintedAsFees).toString(), + postTotalEther: ETH(101), + sharesMintedAsFees: sharesMintedAsFees + }) + await checkStat({ depositedValidators: 3, beaconValidators: 1, beaconBalance: ETH(33) }) await checkBalanceDeltas({ @@ -193,7 +330,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: ETH(0.05), strangerBalanceDiff: ETH(0.3 * 0.9), anotherStrangerBalanceDiff: ETH(0.69 * 0.9), - curatedModuleBalanceDiff: ETH(0.05) + curatedModuleBalanceDiff: ETH(0.05), + initialHolderBalanceDiff: ETH(0.01 * 0.9) }) }) }) @@ -231,23 +369,57 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another }) it('does not revert on new total balance stay the same', async () => { - await lido.handleOracleReport(0, 0, 3, ETH(96), 0, 0, 0, 0, { from: oracle }) + let tx = await lido.handleOracleReport(0, 0, 3, ETH(96), 0, 0, 0, 0, { from: oracle }) + await checkEvents({ + tx, + preCLValidators: 0, + postCLValidators: 3, + preCLBalance: ETH(96), + postCLBalance: ETH(96), + withdrawalsWithdrawn: 0, + executionLayerRewardsWithdrawn: 0, + postBufferedEther: ETH(4), + timeElapsed: 0, + preTotalShares: ETH(100), + preTotalEther: ETH(100), + postTotalShares: ETH(100), + postTotalEther: ETH(100), + sharesMintedAsFees: 0 + }) await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96) }) await checkBalanceDeltas({ totalPooledEtherDiff: 0, treasuryBalanceDiff: 0, strangerBalanceDiff: 0, anotherStrangerBalanceDiff: 0, - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 + }) + tx = await lido.handleOracleReport(0, 0, 3, ETH(96), 0, 0, 0, 0, { from: oracle }) + await checkEvents({ + tx, + preCLValidators: 3, + postCLValidators: 3, + preCLBalance: ETH(96), + postCLBalance: ETH(96), + withdrawalsWithdrawn: 0, + executionLayerRewardsWithdrawn: 0, + postBufferedEther: ETH(4), + timeElapsed: 0, + preTotalShares: ETH(100), + preTotalEther: ETH(100), + postTotalShares: ETH(100), + postTotalEther: ETH(100), + sharesMintedAsFees: 0 }) - await lido.handleOracleReport(0, 0, 3, ETH(96), 0, 0, 0, 0, { from: oracle }) await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96) }) await checkBalanceDeltas({ totalPooledEtherDiff: 0, treasuryBalanceDiff: 0, strangerBalanceDiff: 0, anotherStrangerBalanceDiff: 0, - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 }) }) @@ -258,16 +430,49 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another { from: voting } ) - await lido.handleOracleReport(0, 0, 3, ETH(96), 0, 0, 0, 0, { from: oracle }) + let tx = await lido.handleOracleReport(0, 0, 3, ETH(96), 0, 0, 0, 0, { from: oracle }) + await checkEvents({ + tx, + preCLValidators: 0, + postCLValidators: 3, + preCLBalance: ETH(96), + postCLBalance: ETH(96), + withdrawalsWithdrawn: 0, + executionLayerRewardsWithdrawn: 0, + postBufferedEther: ETH(4), + timeElapsed: 0, + preTotalShares: ETH(100), + preTotalEther: ETH(100), + postTotalShares: ETH(100), + postTotalEther: ETH(100), + sharesMintedAsFees: 0 + }) await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96) }) await checkBalanceDeltas({ totalPooledEtherDiff: 0, treasuryBalanceDiff: 0, strangerBalanceDiff: 0, anotherStrangerBalanceDiff: 0, - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 + }) + tx = await lido.handleOracleReport(0, 0, 3, ETH(95.04), 0, 0, 0, 0, { from: oracle }) + await checkEvents({ + tx, + preCLValidators: 3, + postCLValidators: 3, + preCLBalance: ETH(96), + postCLBalance: ETH(95.04), + withdrawalsWithdrawn: 0, + executionLayerRewardsWithdrawn: 0, + postBufferedEther: ETH(4), + timeElapsed: 0, + preTotalShares: ETH(100), + preTotalEther: ETH(100), + postTotalShares: ETH(100), + postTotalEther: ETH(99.04), + sharesMintedAsFees: 0 }) - await lido.handleOracleReport(0, 0, 3, ETH(95.04), 0, 0, 0, 0, { from: oracle }) await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(95.04) }) await checkBalanceDeltas({ @@ -275,7 +480,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: ETH(0), strangerBalanceDiff: ETH(-30 * 0.0096), anotherStrangerBalanceDiff: toBN(ETH(0.0096)).mul(toBN(-69)).toString(), - curatedModuleBalanceDiff: ETH(0) + curatedModuleBalanceDiff: ETH(0), + initialHolderBalanceDiff: ETH(-1 * 0.0096) }) }) @@ -293,7 +499,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: 0, strangerBalanceDiff: 0, anotherStrangerBalanceDiff: 0, - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 }) await assert.reverts( lido.handleOracleReport(0, 0, 3, ETH(95.03), 0, 0, 0, 0, { from: oracle }), @@ -317,9 +524,27 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: 0, strangerBalanceDiff: 0, anotherStrangerBalanceDiff: 0, - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 + }) + const tx = await lido.handleOracleReport(0, ONE_YEAR, 3, ETH(96.96), 0, 0, 0, 0, { from: oracle }) + const sharesMintedAsFees = calcSharesMintedAsFees(ETH(0.96), 10, 100, ETH(100), ETH(100.96)) + await checkEvents({ + tx, + preCLValidators: 3, + postCLValidators: 3, + preCLBalance: ETH(96), + postCLBalance: ETH(96.96), + withdrawalsWithdrawn: 0, + executionLayerRewardsWithdrawn: 0, + postBufferedEther: ETH(4), + timeElapsed: ONE_YEAR, + preTotalShares: ETH(100), + preTotalEther: ETH(100), + postTotalShares: toBN(ETH(100)).add(sharesMintedAsFees).toString(), + postTotalEther: ETH(100.96), + sharesMintedAsFees: sharesMintedAsFees.toString() }) - await lido.handleOracleReport(0, ONE_YEAR, 3, ETH(96.96), 0, 0, 0, 0, { from: oracle }) await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96.96) }) await checkBalanceDeltas({ @@ -327,7 +552,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: ETH(0.96 * 0.05), strangerBalanceDiff: ETH(30 * 0.0096 * 0.9), anotherStrangerBalanceDiff: ETH(69 * 0.0096 * 0.9), - curatedModuleBalanceDiff: ETH(0.96 * 0.05) + curatedModuleBalanceDiff: ETH(0.96 * 0.05), + initialHolderBalanceDiff: ETH(0.96 * 0.01 * 0.9) }) }) @@ -347,7 +573,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: 0, strangerBalanceDiff: 0, anotherStrangerBalanceDiff: 0, - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 }) await assert.reverts( lido.handleOracleReport(0, ONE_YEAR, 3, ETH(96.97), 0, 0, 0, 0, { from: oracle }), @@ -396,7 +623,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: 0, strangerBalanceDiff: 0, anotherStrangerBalanceDiff: 0, - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 }) }) @@ -425,7 +653,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: ETH(4 * 0.05), strangerBalanceDiff: ETH(4 * 0.3 * 0.9), anotherStrangerBalanceDiff: ETH(4 * 0.69 * 0.9), - curatedModuleBalanceDiff: ETH(4 * 0.05) + curatedModuleBalanceDiff: ETH(4 * 0.05), + initialHolderBalanceDiff: ETH(0.036) }) }) @@ -446,7 +675,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: ETH(0.05), strangerBalanceDiff: ETH(0.3 * 0.9), anotherStrangerBalanceDiff: ETH(0.69 * 0.9), - curatedModuleBalanceDiff: ETH(0.05) + curatedModuleBalanceDiff: ETH(0.05), + initialHolderBalanceDiff: ETH(0.01 * 0.9) }) assert.equals(await ethers.provider.getBalance(withdrawalVault), 0) }) @@ -468,7 +698,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: ETH(0.05), strangerBalanceDiff: ETH(0.3 * 0.9), anotherStrangerBalanceDiff: ETH(0.69 * 0.9), - curatedModuleBalanceDiff: ETH(0.05) + curatedModuleBalanceDiff: ETH(0.05), + initialHolderBalanceDiff: ETH(0.01 * 0.9) }) assert.equals(await ethers.provider.getBalance(withdrawalVault), ETH(0.1)) @@ -492,7 +723,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: 0, strangerBalanceDiff: ETH(0.3), anotherStrangerBalanceDiff: ETH(0.69), - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: ETH(0.01) }) assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0)) @@ -515,7 +747,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: 0, strangerBalanceDiff: ETH(0.3), anotherStrangerBalanceDiff: ETH(0.69), - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: ETH(0.01) }) assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0)) @@ -538,7 +771,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: 0, strangerBalanceDiff: ETH(0.3), anotherStrangerBalanceDiff: ETH(0.69), - curatedModuleBalanceDiff: 0 + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: ETH(0.01) }) assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0.1)) @@ -561,7 +795,8 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: ETH(0.05), strangerBalanceDiff: ETH(0.3 * 0.9), anotherStrangerBalanceDiff: ETH(0.69 * 0.9), - curatedModuleBalanceDiff: ETH(0.05) + curatedModuleBalanceDiff: ETH(0.05), + initialHolderBalanceDiff: ETH(0.01 * 0.9) }) assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0.1)) @@ -584,10 +819,226 @@ contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, another treasuryBalanceDiff: ETH(0.05), strangerBalanceDiff: ETH(0.3 * 0.9), anotherStrangerBalanceDiff: ETH(0.69 * 0.9), - curatedModuleBalanceDiff: ETH(0.05) + curatedModuleBalanceDiff: ETH(0.05), + initialHolderBalanceDiff: ETH(0.01 * 0.9) + }) + + assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0.2)) + }) + }) + describe('daily reports', () => { + beforeEach(async () => { + await await lido.deposit(3, 1, '0x', { from: depositor }) + await checkStat({ depositedValidators: 3, beaconValidators: 0, beaconBalance: 0 }) + await checkBalanceDeltas({ + totalPooledEtherDiff: 0, + treasuryBalanceDiff: 0, + strangerBalanceDiff: 0, + anotherStrangerBalanceDiff: 0, + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: 0 + }) + }) + it('smooths el rewards if report out of limit', async () => { + await setBalance(elRewardsVault, ETH(1.1)) + + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, + churnValidatorsPerDayLimit: 100, + maxPositiveTokenRebase: 10000000, + }, + { from: voting, gasPrice: 1 } + ) + await lido.handleOracleReport(0, ONE_DAY, 3, ETH(96.1), 0, ETH(1.1), 0, 0, { from: oracle, gasPrice: 1 }) + await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96.1) }) + await checkBalanceDeltas({ + totalPooledEtherDiff: ETH(1), + treasuryBalanceDiff: ETH(0.05), + strangerBalanceDiff: ETH(0.3 * 0.9), + anotherStrangerBalanceDiff: ETH(0.69 * 0.9), + curatedModuleBalanceDiff: ETH(0.05), + initialHolderBalanceDiff: ETH(0.01 * 0.9) }) assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0.2)) }) + it('does not smooth if report in limits', async () => { + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, + churnValidatorsPerDayLimit: 100, + }, + { from: voting, gasPrice: 1 } + ) + await lido.handleOracleReport(0, ONE_DAY, 3, ETH(96.0027), 0, 0, 0, 0, { from: oracle, gasPrice: 1 }) + await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96.0027) }) + }) + + it('does not smooth if cl balance report over limit', async () => { + const clIncrease = 0.0028 + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, + churnValidatorsPerDayLimit: 100, + }, + { from: voting, gasPrice: 1 } + ) + await lido.handleOracleReport(0, ONE_DAY, 3, ETH(96 + 0.0028), 0, 0, 0, 0, { from: oracle, gasPrice: 1 }) + await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96 + clIncrease) }) + assert( + 0.00014 + 0.0028 * 0.9 * 0.3 + 0.0028 * 0.9 * 0.69 + 0.0028 * 0.01 * 0.9 + 0.00014 === clIncrease, + 'cl balance increase' + ) + await checkBalanceDeltas({ + totalPooledEtherDiff: ETH(clIncrease), + treasuryBalanceDiff: ETH(0.00014), + strangerBalanceDiff: ETH(0.0028 * 0.9 * 0.3), + anotherStrangerBalanceDiff: ETH(0.0028 * 0.9 * 0.69), + curatedModuleBalanceDiff: ETH(0.00014), + initialHolderBalanceDiff: ETH(0.0028 * 0.01 * 0.9) + }) + }) + + it('does not smooth withdrawals if report in limits', async () => { + await setBalance(withdrawalVault, ETH(1)) + + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, + churnValidatorsPerDayLimit: 100, + annualBalanceIncreaseBPLimit: 100, + }, + { from: voting, gasPrice: 1 } + ) + await lido.handleOracleReport(0, ONE_DAY, 3, ETH(96), ETH(1), 0, 0, 0, { from: oracle, gasPrice: 1 }) + await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96) }) + await checkBalanceDeltas({ + totalPooledEtherDiff: ETH(1), + treasuryBalanceDiff: ETH(0.05), + strangerBalanceDiff: ETH(0.3 * 0.9), + anotherStrangerBalanceDiff: ETH(0.69 * 0.9), + curatedModuleBalanceDiff: ETH(0.05), + initialHolderBalanceDiff: ETH(0.01 * 0.9) + }) + assert.equals(await ethers.provider.getBalance(withdrawalVault), 0) + }) + + it('smooths withdrawals if report out of limit', async () => { + await setBalance(withdrawalVault, ETH(1.1)) + + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, + churnValidatorsPerDayLimit: 100, + maxPositiveTokenRebase: 10000000, + }, + { from: voting, gasPrice: 1 } + ) + await lido.handleOracleReport(0, ONE_DAY, 3, ETH(96), ETH(1.1), 0, 0, 0, { from: oracle, gasPrice: 1 }) + await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96) }) + await checkBalanceDeltas({ + totalPooledEtherDiff: ETH(1), + treasuryBalanceDiff: ETH(0.05), + strangerBalanceDiff: ETH(0.3 * 0.9), + anotherStrangerBalanceDiff: ETH(0.69 * 0.9), + curatedModuleBalanceDiff: ETH(0.05), + initialHolderBalanceDiff: ETH(0.01 * 0.9) + }) + + assert.equals(await ethers.provider.getBalance(withdrawalVault), ETH(0.1)) + }) + + it('does not smooth el rewards if report in limit without lido fee', async () => { + await setBalance(elRewardsVault, ETH(1)) + + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, + churnValidatorsPerDayLimit: 100, + maxPositiveTokenRebase: 10000000, + }, + { from: voting, gasPrice: 1 } + ) + await lido.handleOracleReport(0, ONE_DAY, 3, ETH(96), 0, ETH(1), 0, 0, { from: oracle, gasPrice: 1 }) + await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96) }) + + await checkBalanceDeltas({ + totalPooledEtherDiff: ETH(1), + treasuryBalanceDiff: 0, + strangerBalanceDiff: ETH(0.3), + anotherStrangerBalanceDiff: ETH(0.69), + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: ETH(0.01) + }) + + assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0)) + }) + + it('does not smooth el rewards if report in limit without lido fee 2', async () => { + await setBalance(elRewardsVault, ETH(1.5)) + + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, + churnValidatorsPerDayLimit: 100, + maxPositiveTokenRebase: 10000000, + }, + { from: voting, gasPrice: 1 } + ) + await lido.handleOracleReport(0, ONE_DAY, 3, ETH(95.5), 0, ETH(1.5), 0, 0, { from: oracle, gasPrice: 1 }) + await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(95.5) }) + await checkBalanceDeltas({ + totalPooledEtherDiff: ETH(1), + treasuryBalanceDiff: 0, + strangerBalanceDiff: ETH(0.3), + anotherStrangerBalanceDiff: ETH(0.69), + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: ETH(0.01) + }) + + assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0)) + }) + + it('smooths el rewards if report out of limit without lido fee', async () => { + await setBalance(elRewardsVault, ETH(1.1)) + + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, + churnValidatorsPerDayLimit: 100, + maxPositiveTokenRebase: 10000000, + }, + { from: voting, gasPrice: 1 } + ) + await lido.handleOracleReport(0, ONE_DAY, 3, ETH(96), 0, ETH(1.1), 0, 0, { from: oracle, gasPrice: 1 }) + await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96) }) + await checkBalanceDeltas({ + totalPooledEtherDiff: ETH(1), + treasuryBalanceDiff: 0, + strangerBalanceDiff: ETH(0.3), + anotherStrangerBalanceDiff: ETH(0.69), + curatedModuleBalanceDiff: 0, + initialHolderBalanceDiff: ETH(0.01) + }) + + assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0.1)) + }) + + it('does not smooth el rewards if report in limit', async () => { + await setBalance(elRewardsVault, ETH(1)) + + await oracleReportSanityChecker.setOracleReportLimits({ + ...ORACLE_REPORT_LIMITS_BOILERPLATE, + churnValidatorsPerDayLimit: 100, + }, + { from: voting, gasPrice: 1 } + ) + await lido.handleOracleReport(0, ONE_DAY, 3, ETH(96.1), 0, ETH(0.9), 0, 0, { from: oracle, gasPrice: 1 }) + await checkStat({ depositedValidators: 3, beaconValidators: 3, beaconBalance: ETH(96.1) }) + + await checkBalanceDeltas({ + totalPooledEtherDiff: ETH(1), + treasuryBalanceDiff: ETH(0.05), + strangerBalanceDiff: ETH(0.3 * 0.9), + anotherStrangerBalanceDiff: ETH(0.69 * 0.9), + curatedModuleBalanceDiff: ETH(0.05), + initialHolderBalanceDiff: ETH(0.01 * 0.9) + }) + + assert.equals(await ethers.provider.getBalance(elRewardsVault), ETH(0.1)) + }) }) }) From d213e0e57e84c2d7110a3b778e2159025f49eff7 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Mon, 20 Feb 2023 16:53:54 +0700 Subject: [PATCH 135/199] test: ValidatorsExitBusOracle._handleConsensusReportData enforces data length --- ...exit-bus-oracle-submit-report-data.test.js | 64 +++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index b4f3007bb..b6c1df729 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -48,18 +48,25 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger assert.equal((await consensus.getConsensusState()).consensusReport, hash) } + const getDefaultReportFields = (overrides) => ({ + consensusVersion: CONSENSUS_VERSION, + dataFormat: DATA_FORMAT_LIST, + // required override: refSlot + // required override: requestsCount + // required override: data + ...overrides + }) + async function prepareReportAndSubmitHash(exitRequests, options = {}) { const { reportFields: reportFieldsArg = {} } = options const { refSlot } = await consensus.getCurrentFrame() - const reportFields = { - consensusVersion: CONSENSUS_VERSION, + const reportFields = getDefaultReportFields({ refSlot: +refSlot, requestsCount: exitRequests.length, - dataFormat: DATA_FORMAT_LIST, data: encodeExitRequestsDataList(exitRequests), ...reportFieldsArg - } + }) const reportItems = getReportDataItems(reportFields) const reportHash = calcReportDataHash(reportItems) @@ -111,6 +118,55 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger await oracle.submitReportData(report, oracleVersion, { from: member1 }) }) }) + + context('enforces data length', () => { + it('reverts if there is more data than expected', async () => { + const { refSlot } = await consensus.getCurrentFrame() + const exitRequests = [{ moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }] + const reportFields = getDefaultReportFields({ + refSlot: +refSlot, + requestsCount: exitRequests.length, + data: encodeExitRequestsDataList(exitRequests) + }) + + reportFields.data += 'aaaaaaaaaaaaaaaaaa' + const reportItems = getReportDataItems(reportFields) + const reportHash = calcReportDataHash(reportItems) + await triggerConsensusOnHash(reportHash) + + await assert.reverts( + oracle.submitReportData(reportItems, oracleVersion, { from: member1 }), + 'InvalidRequestsDataLength()' + ) + }) + + it('reverts if there is less data than expected', async () => { + const { refSlot } = await consensus.getCurrentFrame() + const exitRequests = [{ moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }] + const reportFields = getDefaultReportFields({ + refSlot: +refSlot, + requestsCount: exitRequests.length, + data: encodeExitRequestsDataList(exitRequests) + }) + + reportFields.data = reportFields.data.slice(0, reportFields.data.length - 18) + const reportItems = getReportDataItems(reportFields) + const reportHash = calcReportDataHash(reportItems) + await triggerConsensusOnHash(reportHash) + + await assert.reverts( + oracle.submitReportData(reportItems, oracleVersion, { from: member1 }), + 'InvalidRequestsDataLength()' + ) + }) + + it('pass if there is exact amount of data', async () => { + const report = await prepareReportAndSubmitHash([ + { moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] } + ]) + await oracle.submitReportData(report, oracleVersion, { from: member1 }) + }) + }) }) context(`requires validator indices for the same node operator to increase`, () => { From 8872c37c8a1b03e19d6ffc49367c6303e6535d7e Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Mon, 20 Feb 2023 17:13:02 +0700 Subject: [PATCH 136/199] test: ValidatorsExitBusOracle._handleConsensusReportData invokes sanity check --- .../validators-exit-bus-oracle-deploy.test.js | 8 +++--- ...exit-bus-oracle-submit-report-data.test.js | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js index 43c163c75..4579f9a9d 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js @@ -84,7 +84,7 @@ module.exports = { async function deployOracleReportSanityCheckerForExitBus(lidoLocator, admin) { const maxValidatorExitRequestsPerReport = 2000 const limitsList = [0, 0, 0, 0, maxValidatorExitRequestsPerReport, 0, 0, 0, 0] - const managersRoster = [[admin], [], [], [], [], [], [], [], [], []] + const managersRoster = [[admin], [admin], [admin], [admin], [admin], [admin], [admin], [admin], [admin], [admin]] const OracleReportSanityChecker = artifacts.require('OracleReportSanityChecker') @@ -97,7 +97,7 @@ async function deployOracleReportSanityCheckerForExitBus(lidoLocator, admin) { from: admin } ) - return oracleReportSanityChecker.address + return oracleReportSanityChecker } async function deployExitBusOracle(admin, { @@ -119,7 +119,7 @@ async function deployExitBusOracle(admin, { const oracleReportSanityChecker = await deployOracleReportSanityCheckerForExitBus(locator, admin) await updateLocatorImplementation(locator, admin, { validatorsExitBusOracle: oracle.address, - oracleReportSanityChecker: oracleReportSanityChecker + oracleReportSanityChecker: oracleReportSanityChecker.address }) const initTx = await oracle.initialize( @@ -162,7 +162,7 @@ async function deployExitBusOracle(admin, { await oracle.resume({ from: admin }) } - return { consensus, oracle, locator, initTx } + return { consensus, oracle, oracleReportSanityChecker, locator, initTx } } contract('ValidatorsExitBusOracle', ([admin, member1]) => { let consensus diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index b6c1df729..87ce2bca9 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -23,6 +23,7 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger let consensus let oracle + let oracleReportSanityChecker let oracleVersion async function setup() { @@ -33,6 +34,7 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger consensus = deployed.consensus oracle = deployed.oracle + oracleReportSanityChecker = deployed.oracleReportSanityChecker oracleVersion = +(await oracle.getContractVersion()) @@ -167,6 +169,30 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger await oracle.submitReportData(report, oracleVersion, { from: member1 }) }) }) + + context('invokes sanity check', () => { + it('reverts if request limit is reached', async () => { + const exitRequestsLimit = 1 + await oracleReportSanityChecker.setMaxExitRequestsPerOracleReport(exitRequestsLimit) + const report = await prepareReportAndSubmitHash([ + { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[2] }, + { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[3] } + ]) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, { from: member1 }), + `IncorrectNumberOfExitRequestsPerReport(${exitRequestsLimit})` + ) + }) + + it('pass if requests amount equals to limit', async () => { + const exitRequestsLimit = 1 + await oracleReportSanityChecker.setMaxExitRequestsPerOracleReport(exitRequestsLimit) + const report = await prepareReportAndSubmitHash([ + { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[2] } + ]) + await oracle.submitReportData(report, oracleVersion, { from: member1 }) + }) + }) }) context(`requires validator indices for the same node operator to increase`, () => { From c44e0f74393cfe09f625999d03c65b0efcec8453 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Mon, 20 Feb 2023 17:14:19 +0700 Subject: [PATCH 137/199] feat: parent contract internal checks test --- ...exit-bus-oracle-submit-report-data.test.js | 63 ++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index 220b2fef3..22f6298df 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -1,4 +1,4 @@ -const { assert } = require('chai') +const { assert } = require('../../helpers/assert') const { CONSENSUS_VERSION, @@ -48,7 +48,9 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger assert.equal((await consensus.getConsensusState()).consensusReport, hash) } - async function prepareReportAndSubmitHash(exitRequests) { + async function prepareReportAndSubmitHash( + exitRequests = [{ moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }] // default + ) { const { refSlot } = await consensus.getCurrentFrame() const reportFields = { @@ -162,5 +164,62 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger ) }) }) + + context(`only consensus member or SUBMIT_DATA_ROLE can submit report`, () => { + beforeEach(setup) + + it('reverts on stranger', async () => { + const report = await prepareReportAndSubmitHash() + await assert.reverts(oracle.submitReportData(report, oracleVersion, { from: stranger }), 'SenderNotAllowed()') + }) + + it('SUBMIT_DATA_ROLE is allowed', async () => { + oracle.grantRole(await oracle.SUBMIT_DATA_ROLE(), stranger, { from: admin }) + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash() + await oracle.submitReportData(report, oracleVersion, { from: stranger }) + }) + + it('consensus member is allowed', async () => { + assert(await consensus.getIsMember(member1)) + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash() + await oracle.submitReportData(report, oracleVersion, { from: member1 }) + }) + }) + + context('invokes internal baseOracle checks', () => { + beforeEach(setup) + + it(`reverts on contract version mismatch`, async () => { + const report = await prepareReportAndSubmitHash() + await assert.reverts( + oracle.submitReportData(report, oracleVersion + 1, { from: member1 }), + `UnexpectedContractVersion(${oracleVersion}, ${oracleVersion + 1})` + ) + }) + + it('reverts on hash mismatch', async () => { + const report = await prepareReportAndSubmitHash() + const actualReportHash = calcReportDataHash(report) + // mess with data field to change hash + report[report.length - 1] = report[report.length - 1] + 'ff' + const changedReportHash = calcReportDataHash(report) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, { from: member1 }), + `UnexpectedDataHash("${actualReportHash}", "${changedReportHash}")` + ) + }) + + it('reverts on processing deadline miss', async () => { + const report = await prepareReportAndSubmitHash() + const deadline = (await oracle.getConsensusReport()).processingDeadlineTime.toString(10) + await consensus.advanceTimeToNextFrameStart() + await assert.reverts( + oracle.submitReportData(report, oracleVersion, { from: member1 }), + `ProcessingDeadlineMissed(${deadline})` + ) + }) + }) }) }) From 4e69de759f148aedadf74aba2f8b0f37831dc0f0 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Mon, 20 Feb 2023 17:17:18 +0700 Subject: [PATCH 138/199] chore: abi --- lib/abi/ValidatorsExitBusOracle.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/abi/ValidatorsExitBusOracle.json b/lib/abi/ValidatorsExitBusOracle.json index 40656d47b..f264555e1 100644 --- a/lib/abi/ValidatorsExitBusOracle.json +++ b/lib/abi/ValidatorsExitBusOracle.json @@ -1 +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":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidRequestsData","type":"error"},{"inputs":[],"name":"InvalidRequestsDataLength","type":"error"},{"inputs":[],"name":"InvalidRequestsDataSortOrder","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ProcessingDeadlineMissed","type":"error"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"ResumedExpected","type":"error"},{"inputs":[],"name":"SenderNotAllowed","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":[],"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":"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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"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":"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":[],"name":"getLastProcessingRefSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256[]","name":"nodeOpIds","type":"uint256[]"}],"name":"getLastRequestedValidatorIndices","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"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":[{"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"}],"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":"pause","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":"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":"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"}] \ No newline at end of file +[{"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":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidRequestsData","type":"error"},{"inputs":[],"name":"InvalidRequestsDataLength","type":"error"},{"inputs":[],"name":"InvalidRequestsDataSortOrder","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256","name":"nodeOpId","type":"uint256"},{"internalType":"uint256","name":"prevRequestedValidatorIndex","type":"uint256"},{"internalType":"uint256","name":"requestedValidatorIndex","type":"uint256"}],"name":"NodeOpValidatorIndexMustIncrease","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ProcessingDeadlineMissed","type":"error"},{"inputs":[{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"ResumedExpected","type":"error"},{"inputs":[],"name":"SenderNotAllowed","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":[],"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":"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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"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":"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":[],"name":"getLastProcessingRefSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256[]","name":"nodeOpIds","type":"uint256[]"}],"name":"getLastRequestedValidatorIndices","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"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":[{"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"}],"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":"pause","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":"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":"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"}] \ No newline at end of file From 6c129c6eaebc25f0c196add56e1cb594bae17e5a Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Mon, 20 Feb 2023 17:42:08 +0700 Subject: [PATCH 139/199] feat: getTotalRequestsProcessed tests --- ...exit-bus-oracle-submit-report-data.test.js | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index ae9b970d4..c6b2896a5 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -346,5 +346,43 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger ) }) }) + + context('getTotalRequestsProcessed reflects report history', () => { + before(setup) + + let requestCount + + it('should be zero at init', async () => { + requestCount = 0 + assert.equals(await oracle.getTotalRequestsProcessed(), requestCount) + }) + + it('should increase after report', async () => { + const report = await prepareReportAndSubmitHash([ + { moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] } + ]) + await oracle.submitReportData(report, oracleVersion, { from: member1 }) + requestCount += 1 + assert.equals(await oracle.getTotalRequestsProcessed(), requestCount) + }) + + it('should double increase for two exits', async () => { + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash([ + { moduleId: 5, nodeOpId: 1, valIndex: 10, valPubkey: PUBKEYS[0] }, + { moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[0] } + ]) + await oracle.submitReportData(report, oracleVersion, { from: member1 }) + requestCount += 2 + assert.equals(await oracle.getTotalRequestsProcessed(), requestCount) + }) + + it('should not change on empty report', async () => { + await consensus.advanceTimeToNextFrameStart() + const report = await prepareReportAndSubmitHash([]) + await oracle.submitReportData(report, oracleVersion, { from: member1 }) + assert.equals(await oracle.getTotalRequestsProcessed(), requestCount) + }) + }) }) }) From bd1793372fc9de658b47a641b3f6a0e14ff8e23d Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Mon, 20 Feb 2023 17:47:42 +0700 Subject: [PATCH 140/199] test: ValidatorsExitBusOracle._handleConsensusReportData validates requestsCount field with given data --- ...ators-exit-bus-oracle-submit-report-data.test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index 87ce2bca9..f06ccf45d 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -193,6 +193,19 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger await oracle.submitReportData(report, oracleVersion, { from: member1 }) }) }) + + context('validates data.requestsCount field with given data', () => { + it('reverts if requestsCount does not match with encoded data size', async () => { + const report = await prepareReportAndSubmitHash( + [{ moduleId: 5, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] }], + { reportFields: { requestsCount: 2 } } + ) + await assert.reverts( + oracle.submitReportData(report, oracleVersion, { from: member1 }), + 'UnexpectedRequestsDataLength()' + ) + }) + }) }) context(`requires validator indices for the same node operator to increase`, () => { From 67ea946ef9af50817a58211081f81f441a580c8a Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Mon, 20 Feb 2023 12:59:49 +0200 Subject: [PATCH 141/199] feat: improve WithdrawalQueue interface - remove WithdrawalClaimInput struct, because it's more convenient to operate on arrays for external consumer - remove singular claimTo method, because all methods are plural now. - slight improvement for the docs --- contracts/0.8.9/WithdrawalQueue.sol | 89 +++++++++++++++---------- contracts/0.8.9/WithdrawalQueueBase.sol | 12 +--- lib/abi/WithdrawalQueue.json | 2 +- lib/abi/WithdrawalQueueERC721.json | 2 +- test/0.8.9/withdrawal-queue.test.js | 48 ++++++------- 5 files changed, 76 insertions(+), 77 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index 68fdd04e5..c5cecf5d3 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -69,6 +69,7 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit error RequestAmountTooLarge(uint256 _amountOfStETH); error InvalidReportTimestamp(); error RequestIdsNotSorted(); + error ZeroRecipient(); /// @param _wstETH address of WstETH contract constructor(IWstETH _wstETH) { @@ -184,8 +185,8 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit return requestWithdrawalsWstETH(_amounts, _owner); } - /// @notice return statuses for the bunch of requests - /// @param _requestIds list of withdrawal request ids and hints to claim + /// @notice Returns statuses for the array of request ids + /// @param _requestIds array of withdrawal request ids function getWithdrawalRequestStatuses(uint256[] calldata _requestIds) external view @@ -197,57 +198,71 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit } } - struct ClaimWithdrawalInput { - /// @notice id of the finalized requests to claim - uint256 requestId; - /// @notice rate index that should be used for claiming - uint256 hint; - } - - /// @notice Return batch of claimable eth amounts that is locked for each request - /// @param _claimWithdrawalInputs list of withdrawal request ids and hints to claim - function getClaimableEther(ClaimWithdrawalInput[] calldata _claimWithdrawalInputs) + /// @notice Returns array of claimable eth amounts that is locked for each request + /// @param _requestIds array of request ids to find claimable ether for + /// @param _hints checkpoint hint for each id. + /// Can be retrieved with `findCheckpointHints()` or `findCheckpointHintsUnbounded()` + function getClaimableEther(uint256[] calldata _requestIds, uint256[] calldata _hints) external view - returns (uint256[] memory finalEthValues) + returns (uint256[] memory claimableEthValues) { - finalEthValues = new uint256[](_claimWithdrawalInputs.length); - for (uint256 i = 0; i < _claimWithdrawalInputs.length; ++i) { - (, finalEthValues[i]) = - _calculateClaimableEth(_claimWithdrawalInputs[i].requestId, _claimWithdrawalInputs[i].hint); + claimableEthValues = new uint256[](_requestIds.length); + for (uint256 i = 0; i < _requestIds.length; ++i) { + (, claimableEthValues[i]) = _calculateClaimableEth(_requestIds[i], _hints[i]); } } - /// @notice Claim withdrawals batch once finalized (claimable) and send claimable ether to `msg.sender` - /// @param _claimWithdrawalInputs list of withdrawal request ids and hints to claim - function claimWithdrawals(ClaimWithdrawalInput[] calldata _claimWithdrawalInputs) external { - for (uint256 i = 0; i < _claimWithdrawalInputs.length; ++i) { - _claimWithdrawalTo(_claimWithdrawalInputs[i].requestId, _claimWithdrawalInputs[i].hint, msg.sender); - _emitTransfer(msg.sender, address(0), _claimWithdrawalInputs[i].requestId); + /// @notice Claim a batch of withdrawal requests once finalized (claimable) sending ether to `_recipient` + /// @param _requestIds array of request ids to claim + /// @param _hints checkpoint hint for each id. + /// Can be retrieved with `findCheckpointHints()` or `findCheckpointHintsUnbounded()` + /// @param _recipient address where claimed ether will be sent to + /// @dev + /// Reverts if recipient is equal to zero + /// Reverts if any requestId or hint in arguments are not valid + /// Reverts if any request is not finalized or already claimed + /// Reverts if msg sender is not an owner of the requests + function claimWithdrawalsTo(uint256[] calldata _requestIds, uint256[] calldata _hints, address _recipient) + external + { + if (_recipient == address(0)) revert ZeroRecipient(); + + for (uint256 i = 0; i < _requestIds.length; ++i) { + _claim(_requestIds[i], _hints[i], _recipient); + _emitTransfer(msg.sender, address(0), _requestIds[i]); } } - /// @notice Claim `_requestId` request and transfer locked ether to the owner - /// @param _requestId request id to claim - /// @param _hint hint for checkpoint index to avoid extensive search over the checkpointHistory. - /// Can be retrieved with `findCheckpointHint()` or `findCheckpointHintUnbounded()` - /// @param _recipient address where claimed ether will be sent to - function claimWithdrawalTo(uint256 _requestId, uint256 _hint, address _recipient) external { - _claimWithdrawalTo(_requestId, _hint, _recipient); - _emitTransfer(msg.sender, address(0), _requestId); + /// @notice Claim a batch of withdrawal requests once finalized (claimable) sending locked ether to the owner + /// @param _requestIds array of request ids to claim + /// @param _hints checkpoint hint for each id. + /// Can be retrieved with `findCheckpointHints()` or `findCheckpointHintsUnbounded()` + /// @dev + /// Reverts if any requestId or hint in arguments are not valid + /// Reverts if any request is not finalized or already claimed + /// Reverts if msg sender is not an owner of the requests + function claimWithdrawals(uint256[] calldata _requestIds, uint256[] calldata _hints) external { + for (uint256 i = 0; i < _requestIds.length; ++i) { + _claim(_requestIds[i], _hints[i], msg.sender); + _emitTransfer(msg.sender, address(0), _requestIds[i]); + } } - /// @notice Claim `_requestId` request and transfer locked ether to the owner + /// @notice Claim one`_requestId` request once finalized sending locked ether to the owner /// @param _requestId request id to claim - /// @dev will use `findCheckpointHintUnbounded()` to find a hint, what can lead to OOG - /// Prefer `claimWithdrawal(uint256 _requestId, uint256 _hint)` to save gas + /// @dev will use `findCheckpointHintUnbounded()` to find a hint, which can lead to OOG + /// @dev + /// Reverts if requestId or hint are not valid + /// Reverts if request is not finalized or already claimed + /// Reverts if msg sender is not an owner of request function claimWithdrawal(uint256 _requestId) external { - _claimWithdrawalTo(_requestId, findCheckpointHintUnbounded(_requestId), msg.sender); + _claim(_requestId, findCheckpointHintUnbounded(_requestId), msg.sender); _emitTransfer(msg.sender, address(0), _requestId); } /// @notice Finds the list of hints for the given `_requestIds` searching among the checkpoints with indices - /// in the range `[_firstIndex, _lastIndex]` + /// in the range `[_firstIndex, _lastIndex]`. NB! Array of request ids should be sorted /// @param _requestIds ids of the requests sorted in the ascending order to get hints for /// @param _firstIndex left boundary of the search range /// @param _lastIndex right boundary of the search range @@ -268,7 +283,7 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit } /// @notice Finds the list of hints for the given `_requestIds` searching among the checkpoints with indices - /// in the range `[1, lastCheckpointIndex]` + /// in the range `[1, lastCheckpointIndex]`. NB! Array of request ids should be sorted /// @dev WARNING! OOG is possible if used onchain. /// See `findCheckpointHints(uint256[] calldata _requestIds, uint256 _firstIndex, uint256 _lastIndex)` for onchain use /// @param _requestIds ids of the requests sorted in the ascending order to get hints for diff --git a/contracts/0.8.9/WithdrawalQueueBase.sol b/contracts/0.8.9/WithdrawalQueueBase.sol index 9a4afc027..57514456e 100644 --- a/contracts/0.8.9/WithdrawalQueueBase.sol +++ b/contracts/0.8.9/WithdrawalQueueBase.sol @@ -423,14 +423,11 @@ abstract contract WithdrawalQueueBase { emit WithdrawalRequested(requestId, msg.sender, _owner, _amountOfStETH, _amountOfShares); } - /// @notice Claim `_requestId` request and transfer related ether to the `_recipient`. Emits WithdrawalClaimed event - /// @dev Reverts if request is not finalized - /// Reverts if request is claimed + /// @notice Claim `_requestId` request and transfer locked ether to `_recipient`. Emits WithdrawalClaimed event /// @param _requestId request id to claim /// @param _hint hint for discount checkpoint index to avoid extensive search over the checkpoints. - /// Can be found with `findCheckpointHint()` or `findCheckpointHintUnbounded()` - /// @param _recipient address to send ether to. If `==address(0)` then will send to the owner. - function _claimWithdrawalTo(uint256 _requestId, uint256 _hint, address _recipient) internal { + /// @param _recipient address to send ether to + function _claim(uint256 _requestId, uint256 _hint, address _recipient) internal { if (_requestId > getLastFinalizedRequestId()) revert RequestNotFinalized(_requestId); (WithdrawalRequest storage request, uint256 ethWithDiscount) = _calculateClaimableEth(_requestId, _hint); @@ -438,13 +435,10 @@ abstract contract WithdrawalQueueBase { if (request.claimed) revert RequestAlreadyClaimed(_requestId); if (msg.sender != request.owner) revert NotOwner(msg.sender, request.owner); - if (_recipient == address(0)) _recipient = request.owner; - request.claimed = true; assert(_getRequestsByOwner()[request.owner].remove(_requestId)); _setLockedEtherAmount(getLockedEtherAmount() - ethWithDiscount); - _sendValue(payable(_recipient), ethWithDiscount); emit WithdrawalClaimed(_requestId, msg.sender, _recipient, ethWithDiscount); diff --git a/lib/abi/WithdrawalQueue.json b/lib/abi/WithdrawalQueue.json index f51861b43..3066a957a 100644 --- a/lib/abi/WithdrawalQueue.json +++ b/lib/abi/WithdrawalQueue.json @@ -1 +1 @@ -[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"finalEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueueERC721.json b/lib/abi/WithdrawalQueueERC721.json index 93d156754..6c6f75d72 100644 --- a/lib/abi/WithdrawalQueueERC721.json +++ b/lib/abi/WithdrawalQueueERC721.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"internalType":"struct WithdrawalQueue.ClaimWithdrawalInput[]","name":"_claimWithdrawalInputs","type":"tuple[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"finalEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/test/0.8.9/withdrawal-queue.test.js b/test/0.8.9/withdrawal-queue.test.js index cda146b6a..fa8667ad2 100644 --- a/test/0.8.9/withdrawal-queue.test.js +++ b/test/0.8.9/withdrawal-queue.test.js @@ -258,39 +258,37 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { await withdrawalQueue.requestWithdrawals([ETH(1)], owner, { from: user }) await withdrawalQueue.finalize(1, { from: steth.address, value: ETH(1) }) - assert.equals(await withdrawalQueue.getClaimableEther([[1, 1]]), ETH(1)) + assert.equals(await withdrawalQueue.getClaimableEther([1], [1]), ETH(1)) }) it('return 0 for non-finalized request', async () => { - assert.equals(await withdrawalQueue.getClaimableEther([[1, 1]]), ETH(0)) + assert.equals(await withdrawalQueue.getClaimableEther([1], [1]), ETH(0)) }) it('return 0 for claimed request', async () => { await withdrawalQueue.finalize(1, { from: steth.address, value: ETH(1) }) - await withdrawalQueue.claimWithdrawalTo(1, 1, user, { from: owner }) + await withdrawalQueue.claimWithdrawals([1], [1], { from: owner }) - assert.equals(await withdrawalQueue.getClaimableEther([[1, 1]]), ETH(0)) + assert.equals(await withdrawalQueue.getClaimableEther([1], [1]), ETH(0)) }) it('reverts on invalid params', async () => { - await assert.reverts(withdrawalQueue.getClaimableEther([[0, 1]]), 'InvalidRequestId(0)') - await assert.reverts(withdrawalQueue.getClaimableEther([[2, 1]]), 'InvalidRequestId(2)') - await assert.reverts(withdrawalQueue.getClaimableEther([[1, 0]]), 'InvalidHint(0)') + await assert.reverts(withdrawalQueue.getClaimableEther([0], [1]), 'InvalidRequestId(0)') + await assert.reverts(withdrawalQueue.getClaimableEther([2], [1]), 'InvalidRequestId(2)') + await assert.reverts(withdrawalQueue.getClaimableEther([1], [0]), 'InvalidHint(0)') await withdrawalQueue.finalize(1, { from: steth.address, value: ETH(1) }) - await assert.reverts(withdrawalQueue.getClaimableEther([[1, 2]]), 'InvalidHint(2)') + await assert.reverts(withdrawalQueue.getClaimableEther([1], [2]), 'InvalidHint(2)') await withdrawalQueue.requestWithdrawals([ETH(1)], owner, { from: user }) - await assert.reverts(withdrawalQueue.getClaimableEther([[1, 2]]), 'InvalidHint(2)') + await assert.reverts(withdrawalQueue.getClaimableEther([1], [2]), 'InvalidHint(2)') }) }) context('claimWithdrawal()', async () => { - let requestId const amount = ETH(300) beforeEach('Enqueue a request', async () => { - const receipt = await withdrawalQueue.requestWithdrawals([amount], owner, { from: user }) - requestId = getEventArgument(receipt, "WithdrawalRequested", "requestId") + await withdrawalQueue.requestWithdrawals([amount], owner, { from: user }) }) it('Owner can claim a finalized request to recipient address', async () => { @@ -298,7 +296,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { const balanceBefore = bn(await ethers.provider.getBalance(user)) - await withdrawalQueue.claimWithdrawalTo(requestId, 1, user, { from: owner }) + await withdrawalQueue.claimWithdrawalsTo([1], [1], user, { from: owner }) assert.equals(await ethers.provider.getBalance(user), balanceBefore.add(bn(amount))) }) @@ -308,14 +306,13 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { const balanceBefore = bn(await ethers.provider.getBalance(owner)) - await withdrawalQueue.claimWithdrawal(requestId, { from: owner }) + await withdrawalQueue.claimWithdrawal(1, { from: owner }) assert.equals(await ethers.provider.getBalance(owner), balanceBefore.add(bn(amount))) }) it('One cant claim not finalized request', async () => { - await assert.reverts(withdrawalQueue.claimWithdrawalTo(requestId, 1, owner, { from: owner }), - `RequestNotFinalized(${requestId})`) + await assert.reverts(withdrawalQueue.claimWithdrawals([1], [1], { from: owner }), `RequestNotFinalized(1)`) }) it('Cant claim request with a wrong hint', async () => { @@ -326,26 +323,25 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { await withdrawalQueue.requestWithdrawals([amount], owner, { from: user }) await withdrawalQueue.finalize(2, { from: steth.address, value: amount }) - await assert.reverts(withdrawalQueue.claimWithdrawalTo(requestId, 0, owner, { from: owner }), 'InvalidHint(0)') - await assert.reverts(withdrawalQueue.claimWithdrawalTo(requestId, 2, owner, { from: owner }), 'InvalidHint(2)') + await assert.reverts(withdrawalQueue.claimWithdrawals([1], [0], { from: owner }), 'InvalidHint(0)') + await assert.reverts(withdrawalQueue.claimWithdrawals([1], [2], { from: owner }), 'InvalidHint(2)') }) it('Cant withdraw token two times', async () => { await withdrawalQueue.finalize(1, { from: steth.address, value: amount }) - await withdrawalQueue.claimWithdrawal(requestId, { from: owner }) + await withdrawalQueue.claimWithdrawal(1, { from: owner }) - await assert.reverts(withdrawalQueue.claimWithdrawalTo(requestId, 1, owner, { from: owner }), + await assert.reverts(withdrawalQueue.claimWithdrawal(1, { from: owner }), 'RequestAlreadyClaimed(1)') }) it('Discounted withdrawals produce less eth', async () => { await withdrawalQueue.finalize(1, { from: steth.address, value: ETH(150) }) - const hint = await withdrawalQueue.findCheckpointHintUnbounded(requestId) const balanceBefore = bn(await ethers.provider.getBalance(owner)) assert.equals(await withdrawalQueue.getLockedEtherAmount(), ETH(150)) - await withdrawalQueue.claimWithdrawalTo(requestId, hint, owner, { from: owner }) + await withdrawalQueue.claimWithdrawal(1, { from: owner }) assert.equals(await withdrawalQueue.getLockedEtherAmount(), ETH(0)) assert.equals(bn(await ethers.provider.getBalance(owner)).sub(balanceBefore), ETH(150)) @@ -690,13 +686,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { await withdrawalQueue.finalize(secondRequestId, { from: steth.address, value: ETH(30) }) const balanceBefore = bn(await ethers.provider.getBalance(owner)) - await withdrawalQueue.claimWithdrawals( - [ - [requestId, 1], - [secondRequestId, 1] - ], - { from: owner } - ) + await withdrawalQueue.claimWithdrawals([1, 2], [1, 1], { from: owner }) assert.equals(await ethers.provider.getBalance(owner), balanceBefore.add(bn(ETH(30)))) }) }) From 2e9d69cbefd8309741ac04e6283747d041b8db40 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Mon, 20 Feb 2023 18:03:15 +0700 Subject: [PATCH 142/199] test: ValidatorsExitBusOracle._handleConsensusReportData updates processing state --- .../ValidatorsExitBusTimeTravellable.sol | 4 ++++ ...exit-bus-oracle-submit-report-data.test.js | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/contracts/0.8.9/test_helpers/oracle/ValidatorsExitBusTimeTravellable.sol b/contracts/0.8.9/test_helpers/oracle/ValidatorsExitBusTimeTravellable.sol index 28552ee23..a32fd4e55 100644 --- a/contracts/0.8.9/test_helpers/oracle/ValidatorsExitBusTimeTravellable.sol +++ b/contracts/0.8.9/test_helpers/oracle/ValidatorsExitBusTimeTravellable.sol @@ -30,4 +30,8 @@ contract ValidatorsExitBusTimeTravellable is ValidatorsExitBusOracle, ITimeProvi address consensus = CONSENSUS_CONTRACT_POSITION.getStorageAddress(); return ITimeProvider(consensus).getTime(); } + + function getDataProcessingState() external view returns (DataProcessingState memory) { + return _storageDataProcessingState().value; + } } diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index f06ccf45d..d5afd9e92 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -206,6 +206,28 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger ) }) }) + + it('updates processing state', async () => { + const storageBefore = await oracle.getDataProcessingState() + assert.equals(+storageBefore.refSlot, 0) + assert.equals(+storageBefore.requestsCount, 0) + assert.equals(+storageBefore.requestsProcessed, 0) + assert.equals(+storageBefore.dataFormat, 0) + + const { refSlot } = await consensus.getCurrentFrame() + const requests = [ + { moduleId: 4, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[2] }, + { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[3] } + ] + const report = await prepareReportAndSubmitHash(requests) + await oracle.submitReportData(report, oracleVersion, { from: member1 }) + + const storageAfter = await oracle.getDataProcessingState() + assert.equals(+storageAfter.refSlot, +refSlot) + assert.equals(+storageAfter.requestsCount, requests.length) + assert.equals(+storageAfter.requestsProcessed, requests.length) + assert.equals(+storageAfter.dataFormat, DATA_FORMAT_LIST) + }) }) context(`requires validator indices for the same node operator to increase`, () => { From 8a42e432916c81ff2f9d01b6eeaef0a8ff37dd6d Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Mon, 20 Feb 2023 18:16:12 +0700 Subject: [PATCH 143/199] feat: getProcessingState tests --- ...exit-bus-oracle-submit-report-data.test.js | 82 ++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index c6b2896a5..d8d3c8437 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -6,7 +6,9 @@ const { getReportDataItems, calcReportDataHash, encodeExitRequestsDataList, - deployExitBusOracle + deployExitBusOracle, + computeTimestampAtSlot, + ZERO_HASH } = require('./validators-exit-bus-oracle-deploy.test') const PUBKEYS = [ @@ -17,6 +19,14 @@ const PUBKEYS = [ '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ] +function assertEqualsObject(state, desired) { + for (const key in desired) { + if (Object.hasOwnProperty.call(desired, key)) { + assert.equals(state[key], desired[key], key) + } + } +} + contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger]) => { context('submitReportData', () => { const LAST_PROCESSING_REF_SLOT = 1 @@ -384,5 +394,75 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger assert.equals(await oracle.getTotalRequestsProcessed(), requestCount) }) }) + + context('getProcessingState reflects state change', () => { + before(setup) + + let report + let hash + + it('has correct defaults on init', async () => { + const state = await oracle.getProcessingState() + assertEqualsObject(state, { + currentFrameRefSlot: (await consensus.getCurrentFrame()).refSlot, + processingDeadlineTime: 0, + dataHash: ZERO_HASH, + dataSubmitted: false, + dataFormat: 0, + requestsCount: 0, + requestsSubmitted: 0 + }) + }) + + it('consensus report submitted', async () => { + report = await prepareReportAndSubmitHash([ + { moduleId: 5, nodeOpId: 1, valIndex: 10, valPubkey: PUBKEYS[2] }, + { moduleId: 5, nodeOpId: 3, valIndex: 1, valPubkey: PUBKEYS[3] } + ]) + hash = calcReportDataHash(report) + const state = await oracle.getProcessingState() + assertEqualsObject(state, { + currentFrameRefSlot: (await consensus.getCurrentFrame()).refSlot, + processingDeadlineTime: computeTimestampAtSlot( + (await consensus.getCurrentFrame()).reportProcessingDeadlineSlot + ), + dataHash: hash, + dataSubmitted: false, + dataFormat: 0, + requestsCount: 0, + requestsSubmitted: 0 + }) + }) + + it('report is processed', async () => { + await oracle.submitReportData(report, oracleVersion, { from: member1 }) + const state = await oracle.getProcessingState() + assertEqualsObject(state, { + currentFrameRefSlot: (await consensus.getCurrentFrame()).refSlot, + processingDeadlineTime: computeTimestampAtSlot( + (await consensus.getCurrentFrame()).reportProcessingDeadlineSlot + ), + dataHash: hash, + dataSubmitted: true, + dataFormat: DATA_FORMAT_LIST, + requestsCount: 2, + requestsSubmitted: 2 + }) + }) + + it('at next frame state resets', async () => { + await consensus.advanceTimeToNextFrameStart() + const state = await oracle.getProcessingState() + assertEqualsObject(state, { + currentFrameRefSlot: (await consensus.getCurrentFrame()).refSlot, + processingDeadlineTime: 0, + dataHash: ZERO_HASH, + dataSubmitted: false, + dataFormat: 0, + requestsCount: 0, + requestsSubmitted: 0 + }) + }) + }) }) }) From aeca08c89c42c4bc4a560c038bba3baa6ed3af7e Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Mon, 20 Feb 2023 14:17:22 +0300 Subject: [PATCH 144/199] feat: use embedded EIP712 for StETH The idea is to provide the signature for the proper StETH token address. --- contracts/0.4.24/StETHPermit.sol | 4 +- contracts/0.8.9/EIP712StETH.sol | 83 +++++++++++++++++++++---- contracts/common/interfaces/IEIP712.sol | 4 +- lib/abi/EIP712StETH.json | 2 +- test/0.4.24/stethpermit.test.js | 68 +++++++++++--------- 5 files changed, 114 insertions(+), 47 deletions(-) diff --git a/contracts/0.4.24/StETHPermit.sol b/contracts/0.4.24/StETHPermit.sol index 1c2ef1f40..fe05c818c 100644 --- a/contracts/0.4.24/StETHPermit.sol +++ b/contracts/0.4.24/StETHPermit.sol @@ -100,7 +100,7 @@ contract StETHPermit is IERC2612, StETH { abi.encode(PERMIT_TYPEHASH, _owner, _spender, _value, _useNonce(_owner), _deadline) ); - bytes32 hash = IEIP712(getEIP712StETH()).hashTypedDataV4(structHash); + bytes32 hash = IEIP712(getEIP712StETH()).hashTypedDataV4(address(this), structHash); address signer = ECDSA.recover(hash, _v, _r, _s); require(signer == _owner, "ERC20Permit: invalid signature"); @@ -124,7 +124,7 @@ contract StETHPermit is IERC2612, StETH { */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32) { - return IEIP712(getEIP712StETH()).domainSeparatorV4(); + return IEIP712(getEIP712StETH()).domainSeparatorV4(address(this)); } /** diff --git a/contracts/0.8.9/EIP712StETH.sol b/contracts/0.8.9/EIP712StETH.sol index 5686fd57c..f761047a2 100644 --- a/contracts/0.8.9/EIP712StETH.sol +++ b/contracts/0.8.9/EIP712StETH.sol @@ -1,27 +1,88 @@ -// SPDX-FileCopyrightText: 2023 Lido -// SPDX-License-Identifier: GPL-3.0 +// SPDX-FileCopyrightText: 2023 OpenZeppelin, Lido +// SPDX-License-Identifier: MIT /* See contracts/COMPILERS.md */ pragma solidity 0.8.9; -import {EIP712} from "@openzeppelin/contracts-v4.4/utils/cryptography/draft-EIP712.sol"; +import {ECDSA} from "@openzeppelin/contracts-v4.4/utils/cryptography/ECDSA.sol"; import {IEIP712} from "../common/interfaces/IEIP712.sol"; /** - * Helper contract exposes OpenZeppelin's EIP712 message utils implementation. + * NOTE: The code below is taken from "@openzeppelin/contracts-v4.4/utils/cryptography/draft-EIP712.sol" + * With a main difference to store the stETH contract address internally and use it for signing. */ -contract EIP712StETH is IEIP712, EIP712 { + +/** + * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. + * + * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, + * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding + * they need in their contracts using a combination of `abi.encode` and `keccak256`. + * + * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding + * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA + * ({_hashTypedDataV4}). + * + * The implementation of the domain separator was designed to be as efficient as possible while still properly updating + * the chain id to protect against replay attacks on an eventual fork of the chain. + * + * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method + * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. + * + */ +contract EIP712StETH is IEIP712 { + /* solhint-disable var-name-mixedcase */ + // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to + // invalidate the cached domain separator if the chain id changes. + bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; + uint256 private immutable _CACHED_CHAIN_ID; + address private immutable _CACHED_STETH; + + bytes32 private immutable _HASHED_NAME; + bytes32 private immutable _HASHED_VERSION; + bytes32 private immutable _TYPE_HASH; + + error ZeroStETHAddress(); + /** * @dev Constructs specialized EIP712 instance for StETH token, version "2". */ - constructor() EIP712("Liquid staked Ether 2.0", "2") {} + constructor(address _stETH) { + if (_stETH == address(0)) { revert ZeroStETHAddress(); } + + bytes32 hashedName = keccak256(bytes("Liquid staked Ether 2.0")); + bytes32 hashedVersion = keccak256(bytes("2")); + bytes32 typeHash = keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + ); + + _HASHED_NAME = hashedName; + _HASHED_VERSION = hashedVersion; + _CACHED_CHAIN_ID = block.chainid; + _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion, _stETH); + _CACHED_STETH = _stETH; + _TYPE_HASH = typeHash; + } /** * @dev Returns the domain separator for the current chain. */ - function domainSeparatorV4() external view override returns (bytes32) { - return _domainSeparatorV4(); + function domainSeparatorV4(address _stETH) public view override returns (bytes32) { + if (_stETH == _CACHED_STETH && block.chainid == _CACHED_CHAIN_ID) { + return _CACHED_DOMAIN_SEPARATOR; + } else { + return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, _stETH); + } + } + + function _buildDomainSeparator( + bytes32 _typeHash, + bytes32 _nameHash, + bytes32 _versionHash, + address _stETH + ) private view returns (bytes32) { + return keccak256(abi.encode(_typeHash, _nameHash, _versionHash, block.chainid, _stETH)); } /** @@ -31,7 +92,7 @@ contract EIP712StETH is IEIP712, EIP712 { * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity - * bytes32 digest = hashTypedDataV4(keccak256(abi.encode( + * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) @@ -39,7 +100,7 @@ contract EIP712StETH is IEIP712, EIP712 { * address signer = ECDSA.recover(digest, signature); * ``` */ - function hashTypedDataV4(bytes32 _structHash) external view override returns (bytes32) { - return _hashTypedDataV4(_structHash); + function hashTypedDataV4(address _stETH, bytes32 _structHash) external view override returns (bytes32) { + return ECDSA.toTypedDataHash(domainSeparatorV4(_stETH), _structHash); } } diff --git a/contracts/common/interfaces/IEIP712.sol b/contracts/common/interfaces/IEIP712.sol index 2916c245d..1636432bc 100644 --- a/contracts/common/interfaces/IEIP712.sol +++ b/contracts/common/interfaces/IEIP712.sol @@ -15,7 +15,7 @@ interface IEIP712 { /** * @dev Returns the domain separator for the current chain. */ - function domainSeparatorV4() external view returns (bytes32); + function domainSeparatorV4(address _stETH) external view returns (bytes32); /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this @@ -32,5 +32,5 @@ interface IEIP712 { * address signer = ECDSA.recover(digest, signature); * ``` */ - function hashTypedDataV4(bytes32 _structHash) external view returns (bytes32); + function hashTypedDataV4(address _stETH, bytes32 _structHash) external view returns (bytes32); } diff --git a/lib/abi/EIP712StETH.json b/lib/abi/EIP712StETH.json index b5fcf2fb2..bb6f561c4 100644 --- a/lib/abi/EIP712StETH.json +++ b/lib/abi/EIP712StETH.json @@ -1 +1 @@ -[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_structHash","type":"bytes32"}],"name":"hashTypedDataV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_stETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ZeroStETHAddress","type":"error"},{"inputs":[{"internalType":"address","name":"_stETH","type":"address"}],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stETH","type":"address"},{"internalType":"bytes32","name":"_structHash","type":"bytes32"}],"name":"hashTypedDataV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/test/0.4.24/stethpermit.test.js b/test/0.4.24/stethpermit.test.js index 53f7b0d86..acab0e364 100644 --- a/test/0.4.24/stethpermit.test.js +++ b/test/0.4.24/stethpermit.test.js @@ -1,8 +1,7 @@ const crypto = require('crypto') const { ACCOUNTS_AND_KEYS, MAX_UINT256, ZERO_ADDRESS } = require('./helpers/constants') const { bn } = require('@aragon/contract-helpers-test') -const { assertBn, assertEvent } = require('@aragon/contract-helpers-test/src/asserts') -const { assertRevert } = require('../helpers/assertThrow') +const { assert } = require('../helpers/assert') const { signPermit, signTransferAuthorization, makeDomainSeparator } = require('./helpers/permit_helpers') const { hexStringFromBuffer } = require('./helpers/sign_utils') const { ETH } = require('../helpers/utils') @@ -16,13 +15,13 @@ contract('StETHPermit', ([deployer, ...accounts]) => { const snapshot = new EvmSnapshot(hre.ethers.provider) before('deploy mock token', async () => { - eip712StETH = await EIP712StETH.new({ from: deployer }) stEthPermit = await StETHPermit.new({ from: deployer, value: ETH(1) }) + eip712StETH = await EIP712StETH.new(stEthPermit.address, { from: deployer }) await stEthPermit.initializeEIP712StETH(eip712StETH.address) chainId = await web3.eth.net.getId(); - domainSeparator = makeDomainSeparator('Liquid staked Ether 2.0', '2', chainId, eip712StETH.address) + domainSeparator = makeDomainSeparator('Liquid staked Ether 2.0', '2', chainId, stEthPermit.address) await snapshot.make() }) @@ -50,8 +49,15 @@ contract('StETHPermit', ([deployer, ...accounts]) => { await stEthPermit.mintShares(permitParams.owner, initialBalance, { from: deployer }) }) + it('EIP-712 signature helper reverts when zero stETH address passed', async () => { + await assert.revertsWithCustomError( + EIP712StETH.new(ZERO_ADDRESS, { from: deployer }), + `ZeroStETHAddress()` + ) + }) + it('EIP-712 signature helper contract matches the stored one', async () => { - assert.equal(await stEthPermit.getEIP712StETH(), eip712StETH.address) + assert.equals(await stEthPermit.getEIP712StETH(), eip712StETH.address) }) it('grants allowance when a valid permit is given', async () => { @@ -64,11 +70,11 @@ contract('StETHPermit', ([deployer, ...accounts]) => { let { v, r, s } = signPermit(owner, spender, value, nonce, deadline, domainSeparator, alice.key) // check that the allowance is initially zero - assertBn(await stEthPermit.allowance(owner, spender), bn(0)) + assert.equals(await stEthPermit.allowance(owner, spender), bn(0)) // check that the next nonce expected is zero - assertBn(await stEthPermit.nonces(owner), bn(0)) + assert.equals(await stEthPermit.nonces(owner), bn(0)) // check domain separator - assert.equal( + assert.equals( await stEthPermit.DOMAIN_SEPARATOR(), domainSeparator ) @@ -79,15 +85,15 @@ contract('StETHPermit', ([deployer, ...accounts]) => { ) // check that allowance is updated - assertBn(await stEthPermit.allowance(owner, spender), bn(value)) + assert.equals(await stEthPermit.allowance(owner, spender), bn(value)) - assertEvent( + assert.emits( receipt, 'Approval', - { expectedArgs: { owner: owner, spender: spender, value: bn(value) } } + { owner: owner, spender: spender, value: bn(value) } ) - assertBn(await stEthPermit.nonces(owner), bn(1)) + assert.equals(await stEthPermit.nonces(owner), bn(1)) // increment nonce nonce = 1 @@ -99,15 +105,15 @@ contract('StETHPermit', ([deployer, ...accounts]) => { const receipt2 = await stEthPermit.permit(owner, spender, value, deadline, v, r, s, { from: charlie }) // check that allowance is updated - assertBn(await stEthPermit.allowance(owner, spender), bn(value)) + assert.equals(await stEthPermit.allowance(owner, spender), bn(value)) - assertEvent( + assert.emits( receipt2, 'Approval', - { expectedArgs: { owner: owner, spender: spender, value: bn(value) } } + { owner: owner, spender: spender, value: bn(value) } ) - assertBn(await stEthPermit.nonces(owner), bn(2)) + assert.equals(await stEthPermit.nonces(owner), bn(2)) }) it('reverts if the signature does not match given parameters', async () => { @@ -116,7 +122,7 @@ contract('StETHPermit', ([deployer, ...accounts]) => { const { v, r, s } = signPermit(owner, spender, value, nonce, deadline, domainSeparator, alice.key) // try to cheat by claiming the approved amount + 1 - await assertRevert( + await assert.reverts( stEthPermit.permit( owner, spender, @@ -131,7 +137,7 @@ contract('StETHPermit', ([deployer, ...accounts]) => { ) // check that msg is incorrect even if claim the approved amount - 1 - await assertRevert( + await assert.reverts( stEthPermit.permit( owner, spender, @@ -154,7 +160,7 @@ contract('StETHPermit', ([deployer, ...accounts]) => { // try to cheat by submitting the permit that is signed by a // wrong person - await assertRevert( + await assert.reverts( stEthPermit.permit(owner, spender, value, deadline, v, r, s, { from: charlie }), @@ -166,7 +172,7 @@ contract('StETHPermit', ([deployer, ...accounts]) => { await web3.eth.sendTransaction({ to: bob.address, from: accounts[0], value: ETH(10) }) // even Bob himself can't call permit with the invalid sig - await assertRevert( + await assert.reverts( stEthPermit.permit(owner, spender, value, deadline, v, r, s, { from: bob.address }), @@ -181,7 +187,7 @@ contract('StETHPermit', ([deployer, ...accounts]) => { const { v, r, s } = signPermit(owner, spender, value, nonce, deadline, domainSeparator, alice.key) // try to submit the permit that is expired - await assertRevert( + await assert.reverts( stEthPermit.permit(owner, spender, value, deadline, v, r, s, { from: charlie }), @@ -194,11 +200,11 @@ contract('StETHPermit', ([deployer, ...accounts]) => { const { v, r, s } = signPermit(owner, spender, value, nonce, deadline1min, domainSeparator, alice.key) const receipt = await stEthPermit.permit(owner, spender, value, deadline1min, v, r, s, { from: charlie }) - assertBn(await stEthPermit.nonces(owner), bn(1)) - assertEvent( + assert.equals(await stEthPermit.nonces(owner), bn(1)) + assert.emits( receipt, 'Approval', - { expectedArgs: { owner: owner, spender: spender, value: bn(value) } } + { owner: owner, spender: spender, value: bn(value) } ) } }) @@ -209,10 +215,10 @@ contract('StETHPermit', ([deployer, ...accounts]) => { // create a signed permit const { v, r, s } = signPermit(owner, spender, value, nonce, deadline, domainSeparator, alice.key) // check that the next nonce expected is 0, not 1 - assertBn(await stEthPermit.nonces(owner), bn(0)) + assert.equals(await stEthPermit.nonces(owner), bn(0)) // try to submit the permit - await assertRevert( + await assert.reverts( stEthPermit.permit(owner, spender, value, deadline, v, r, s, { from: charlie }), @@ -229,7 +235,7 @@ contract('StETHPermit', ([deployer, ...accounts]) => { await stEthPermit.permit(owner, spender, value, deadline, v, r, s, { from: charlie }) // try to submit the permit again - await assertRevert( + await assert.reverts( stEthPermit.permit(owner, spender, value, deadline, v, r, s, { from: charlie }), @@ -241,7 +247,7 @@ contract('StETHPermit', ([deployer, ...accounts]) => { await web3.eth.sendTransaction({ to: alice.address, from: accounts[0], value: ETH(10) }) // try to submit the permit again from Alice herself - await assertRevert( + await assert.reverts( stEthPermit.permit(owner, spender, value, deadline, v, r, s, { from: alice.address }), @@ -262,7 +268,7 @@ contract('StETHPermit', ([deployer, ...accounts]) => { const permit2 = signPermit(owner, spender, 1e6, nonce, deadline, domainSeparator, alice.key) // try to submit the permit again - await assertRevert( + await assert.reverts( stEthPermit.permit(owner, spender, 1e6, deadline, permit2.v, permit2.r, permit2.s, { from: charlie }), 'ERC20Permit: invalid signature' ) @@ -276,7 +282,7 @@ contract('StETHPermit', ([deployer, ...accounts]) => { const { v, r, s } = signPermit(owner, spender, value, nonce, deadline, domainSeparator, alice.key) // try to submit the permit with invalid approval parameters - await assertRevert( + await assert.reverts( stEthPermit.permit(owner, spender, value, deadline, v, r, s, { from: charlie }), @@ -292,7 +298,7 @@ contract('StETHPermit', ([deployer, ...accounts]) => { const { v, r, s } = signTransferAuthorization(from, to, value, validAfter, validBefore, nonce, domainSeparator, alice.key) // try to submit the transfer permit - await assertRevert( + await assert.reverts( stEthPermit.permit(from, to, value, validBefore, v, r, s, { from: charlie }), From 7690377c580d758faf101b86e4f8f82f12ed5f80 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Mon, 20 Feb 2023 18:24:17 +0700 Subject: [PATCH 145/199] test: ValidatorsExitBusOracle._handleConsensusReportData updates total requests processed count --- ...exit-bus-oracle-submit-report-data.test.js | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index 04954157e..cad1c36fc 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -241,6 +241,41 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger assert.equals(+storageAfter.requestsProcessed, requests.length) assert.equals(+storageAfter.dataFormat, DATA_FORMAT_LIST) }) + + it('updates total requests processed count', async () => { + let currentCount = 0 + const countStep0 = await oracle.getTotalRequestsProcessed() + assert.equals(+countStep0, currentCount) + + // Step 1 — process 1 item + const requestsStep1 = [{ moduleId: 3, nodeOpId: 1, valIndex: 2, valPubkey: PUBKEYS[1] }] + const reportStep1 = await prepareReportAndSubmitHash(requestsStep1) + await oracle.submitReportData(reportStep1, oracleVersion, { from: member1 }) + const countStep1 = await oracle.getTotalRequestsProcessed() + currentCount += requestsStep1.length + assert.equals(+countStep1, currentCount) + + // Step 2 — process 2 items + await consensus.advanceTimeToNextFrameStart() + const requestsStep2 = [ + { moduleId: 4, nodeOpId: 2, valIndex: 2, valPubkey: PUBKEYS[2] }, + { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[3] } + ] + const reportStep2 = await prepareReportAndSubmitHash(requestsStep2) + await oracle.submitReportData(reportStep2, oracleVersion, { from: member1 }) + const countStep2 = await oracle.getTotalRequestsProcessed() + currentCount += requestsStep2.length + assert.equals(+countStep2, currentCount) + + // Step 3 — process no items + await consensus.advanceTimeToNextFrameStart() + const requestsStep3 = [] + const reportStep3 = await prepareReportAndSubmitHash(requestsStep3) + await oracle.submitReportData(reportStep3, oracleVersion, { from: member1 }) + const countStep3 = await oracle.getTotalRequestsProcessed() + currentCount += requestsStep3.length + assert.equals(+countStep3, currentCount) + }) }) context(`requires validator indices for the same node operator to increase`, () => { From 58e160157264a7ccef2bafaf95a2218845914ea7 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Mon, 20 Feb 2023 13:31:39 +0200 Subject: [PATCH 146/199] fix: proper checks on claim and claimable ether --- contracts/0.8.9/WithdrawalQueue.sol | 14 +++++++++- contracts/0.8.9/WithdrawalQueueBase.sol | 35 ++++++++++--------------- lib/abi/WithdrawalQueue.json | 2 +- lib/abi/WithdrawalQueueBase.json | 2 +- lib/abi/WithdrawalQueueERC721.json | 2 +- test/0.8.9/withdrawal-queue.test.js | 9 ++++--- 6 files changed, 36 insertions(+), 28 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index c5cecf5d3..01819dea8 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -209,7 +209,7 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit { claimableEthValues = new uint256[](_requestIds.length); for (uint256 i = 0; i < _requestIds.length; ++i) { - (, claimableEthValues[i]) = _calculateClaimableEth(_requestIds[i], _hints[i]); + claimableEthValues[i] = _getClaimableEther(_requestIds[i], _hints[i]); } } @@ -395,4 +395,16 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit revert RequestAmountTooLarge(_amountOfStETH); } } + + /// @notice returns claimable ether under the request with _requestId. + function _getClaimableEther(uint256 _requestId, uint256 _hint) internal view returns (uint256) { + if (_requestId == 0 || _requestId > getLastRequestId()) revert InvalidRequestId(_requestId); + + if (_requestId > getLastFinalizedRequestId()) return 0; + + WithdrawalRequest storage request = _getQueue()[_requestId]; + if (request.claimed) return 0; + + return _calculateClaimableEther(request, _requestId, _hint); + } } diff --git a/contracts/0.8.9/WithdrawalQueueBase.sol b/contracts/0.8.9/WithdrawalQueueBase.sol index 57514456e..8455e881d 100644 --- a/contracts/0.8.9/WithdrawalQueueBase.sol +++ b/contracts/0.8.9/WithdrawalQueueBase.sol @@ -87,8 +87,8 @@ abstract contract WithdrawalQueueBase { error NotOwner(address _sender, address _owner); error InvalidRequestId(uint256 _requestId); error InvalidRequestIdRange(uint256 startId, uint256 endId); + error RequestNotFoundOrNotFinalized(uint256 _requestId); error NotEnoughEther(); - error RequestNotFinalized(uint256 _requestId); error RequestAlreadyClaimed(uint256 _requestId); error InvalidHint(uint256 _hint); error CantSendValueRecipientMayHaveReverted(); @@ -198,7 +198,7 @@ abstract contract WithdrawalQueueBase { if (_start == 0) revert InvalidRequestIdRange(_start, _end); uint256 lastCheckpointIndex = getLastCheckpointIndex(); if (_end > lastCheckpointIndex) revert InvalidRequestIdRange(_start, _end); - if (_requestId > getLastFinalizedRequestId()) revert RequestNotFinalized(_requestId); + if (_requestId > getLastFinalizedRequestId()) revert RequestNotFoundOrNotFinalized(_requestId); if (_start > _end) return NOT_FOUND; // we have an empty range to search in, so return NOT_FOUND @@ -428,38 +428,33 @@ abstract contract WithdrawalQueueBase { /// @param _hint hint for discount checkpoint index to avoid extensive search over the checkpoints. /// @param _recipient address to send ether to function _claim(uint256 _requestId, uint256 _hint, address _recipient) internal { - if (_requestId > getLastFinalizedRequestId()) revert RequestNotFinalized(_requestId); + if (_requestId == 0) revert InvalidRequestId(_requestId); + if (_requestId > getLastFinalizedRequestId()) revert RequestNotFoundOrNotFinalized(_requestId); - (WithdrawalRequest storage request, uint256 ethWithDiscount) = _calculateClaimableEth(_requestId, _hint); + WithdrawalRequest storage request = _getQueue()[_requestId]; if (request.claimed) revert RequestAlreadyClaimed(_requestId); - if (msg.sender != request.owner) revert NotOwner(msg.sender, request.owner); + if (request.owner != msg.sender) revert NotOwner(msg.sender, request.owner); request.claimed = true; assert(_getRequestsByOwner()[request.owner].remove(_requestId)); + uint256 ethWithDiscount = _calculateClaimableEther(request, _requestId, _hint); + _setLockedEtherAmount(getLockedEtherAmount() - ethWithDiscount); _sendValue(payable(_recipient), ethWithDiscount); emit WithdrawalClaimed(_requestId, msg.sender, _recipient, ethWithDiscount); } - /// @notice Calculates discounted ether value for `_requestId` using a provided `_hint` - /// @return request link to request in storage - /// @return ethWithDiscount discounted eth for `_requestId`. Returns 0 if request is not claimable - function _calculateClaimableEth(uint256 _requestId, uint256 _hint) + /// @notice Calculates discounted ether value for `_requestId` using a provided `_hint`. Checks if hint is valid + /// @return claimableEther discounted eth for `_requestId`. Returns 0 if request is not claimable + function _calculateClaimableEther(WithdrawalRequest storage _request, uint256 _requestId, uint256 _hint) internal view - returns (WithdrawalRequest storage, uint256) + returns (uint256 claimableEther) { if (_hint == 0) revert InvalidHint(_hint); - if (_requestId == 0 || _requestId > getLastRequestId()) revert InvalidRequestId(_requestId); - - WithdrawalRequest storage request = _getQueue()[_requestId]; - - // shortcuts - if (_requestId > getLastFinalizedRequestId()) return (request, 0); - if (request.claimed) return (request, 0); uint256 lastCheckpointIndex = getLastCheckpointIndex(); if (_hint > lastCheckpointIndex) revert InvalidHint(_hint); @@ -477,10 +472,8 @@ abstract contract WithdrawalQueueBase { } } - uint256 ethRequested = request.cumulativeStETH - _getQueue()[_requestId - 1].cumulativeStETH; - uint256 ethWithDiscount = ethRequested * hintCheckpoint.discountFactor / E27_PRECISION_BASE; - - return (request, ethWithDiscount); + uint256 ethRequested = _request.cumulativeStETH - _getQueue()[_requestId - 1].cumulativeStETH; + return ethRequested * hintCheckpoint.discountFactor / E27_PRECISION_BASE; } // quazi-constructor diff --git a/lib/abi/WithdrawalQueue.json b/lib/abi/WithdrawalQueue.json index 3066a957a..c413e3901 100644 --- a/lib/abi/WithdrawalQueue.json +++ b/lib/abi/WithdrawalQueue.json @@ -1 +1 @@ -[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueueBase.json b/lib/abi/WithdrawalQueueBase.json index 1f141d586..4e95f8686 100644 --- a/lib/abi/WithdrawalQueueBase.json +++ b/lib/abi/WithdrawalQueueBase.json @@ -1 +1 @@ -[{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueueERC721.json b/lib/abi/WithdrawalQueueERC721.json index 6c6f75d72..8dba00692 100644 --- a/lib/abi/WithdrawalQueueERC721.json +++ b/lib/abi/WithdrawalQueueERC721.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/test/0.8.9/withdrawal-queue.test.js b/test/0.8.9/withdrawal-queue.test.js index fa8667ad2..ec8d98f2b 100644 --- a/test/0.8.9/withdrawal-queue.test.js +++ b/test/0.8.9/withdrawal-queue.test.js @@ -263,6 +263,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { it('return 0 for non-finalized request', async () => { assert.equals(await withdrawalQueue.getClaimableEther([1], [1]), ETH(0)) + assert.equals(await withdrawalQueue.getClaimableEther([1], [51]), ETH(0)) }) it('return 0 for claimed request', async () => { @@ -270,15 +271,16 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { await withdrawalQueue.claimWithdrawals([1], [1], { from: owner }) assert.equals(await withdrawalQueue.getClaimableEther([1], [1]), ETH(0)) + assert.equals(await withdrawalQueue.getClaimableEther([1], [51]), ETH(0)) }) it('reverts on invalid params', async () => { await assert.reverts(withdrawalQueue.getClaimableEther([0], [1]), 'InvalidRequestId(0)') await assert.reverts(withdrawalQueue.getClaimableEther([2], [1]), 'InvalidRequestId(2)') - await assert.reverts(withdrawalQueue.getClaimableEther([1], [0]), 'InvalidHint(0)') await withdrawalQueue.finalize(1, { from: steth.address, value: ETH(1) }) await assert.reverts(withdrawalQueue.getClaimableEther([1], [2]), 'InvalidHint(2)') + await assert.reverts(withdrawalQueue.getClaimableEther([1], [0]), 'InvalidHint(0)') await withdrawalQueue.requestWithdrawals([ETH(1)], owner, { from: user }) await assert.reverts(withdrawalQueue.getClaimableEther([1], [2]), 'InvalidHint(2)') @@ -311,8 +313,9 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { assert.equals(await ethers.provider.getBalance(owner), balanceBefore.add(bn(amount))) }) - it('One cant claim not finalized request', async () => { - await assert.reverts(withdrawalQueue.claimWithdrawals([1], [1], { from: owner }), `RequestNotFinalized(1)`) + it('One cant claim not finalized or not existed request', async () => { + await assert.reverts(withdrawalQueue.claimWithdrawals([1], [1], { from: owner }), `RequestNotFoundOrNotFinalized(1)`) + await assert.reverts(withdrawalQueue.claimWithdrawals([2], [1], { from: owner }), `RequestNotFoundOrNotFinalized(2)`) }) it('Cant claim request with a wrong hint', async () => { From d1f172ecb8e76a5e2a38dc4d5bcce53cf91592d0 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Mon, 20 Feb 2023 13:36:32 +0200 Subject: [PATCH 147/199] chore: abi --- lib/abi/WithdrawalQueue.json | 2 +- lib/abi/WithdrawalQueueBase.json | 2 +- lib/abi/WithdrawalQueueERC721.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/abi/WithdrawalQueue.json b/lib/abi/WithdrawalQueue.json index c413e3901..0cf482d55 100644 --- a/lib/abi/WithdrawalQueue.json +++ b/lib/abi/WithdrawalQueue.json @@ -1 +1 @@ -[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueueBase.json b/lib/abi/WithdrawalQueueBase.json index 4e95f8686..3f2b15df4 100644 --- a/lib/abi/WithdrawalQueueBase.json +++ b/lib/abi/WithdrawalQueueBase.json @@ -1 +1 @@ -[{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueueERC721.json b/lib/abi/WithdrawalQueueERC721.json index 8dba00692..e45525902 100644 --- a/lib/abi/WithdrawalQueueERC721.json +++ b/lib/abi/WithdrawalQueueERC721.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file From a991347aebef9399df415fb465987f5a7edb2b08 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Mon, 20 Feb 2023 13:36:52 +0200 Subject: [PATCH 148/199] test: fix wq test --- test/0.8.9/withdrawal-queue.test.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/0.8.9/withdrawal-queue.test.js b/test/0.8.9/withdrawal-queue.test.js index ec8d98f2b..7b2e0d75f 100644 --- a/test/0.8.9/withdrawal-queue.test.js +++ b/test/0.8.9/withdrawal-queue.test.js @@ -524,8 +524,15 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) it('reverts if request is not finalized', async () => { - await assert.reverts(withdrawalQueue.findCheckpointHint(11, 1, 10), "RequestNotFinalized(11)") - await assert.reverts(withdrawalQueue.findCheckpointHintUnbounded(11), "RequestNotFinalized(11)") + await withdrawalQueue.requestWithdrawals([ETH(1)], owner, { from: user }) + await assert.reverts(withdrawalQueue.findCheckpointHint(11, 1, 10), "RequestNotFoundOrNotFinalized(11)") + await assert.reverts(withdrawalQueue.findCheckpointHintUnbounded(11), "RequestNotFoundOrNotFinalized(11)") + + }) + + it('reverts if there is no such a request', async () => { + await assert.reverts(withdrawalQueue.findCheckpointHint(12, 1, 10), "RequestNotFoundOrNotFinalized(12)") + await assert.reverts(withdrawalQueue.findCheckpointHintUnbounded(12), "RequestNotFoundOrNotFinalized(12)") }) it('range search (found)', async () => { From c63fcbb0e0b692ae4891f9e97aea489d0cb526a7 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Mon, 20 Feb 2023 14:39:46 +0300 Subject: [PATCH 149/199] test: -obsolete `lidoHandleOracleReport.test.js` --- test/0.4.24/lidoHandleOracleReport.test.js | 238 --------------------- 1 file changed, 238 deletions(-) delete mode 100644 test/0.4.24/lidoHandleOracleReport.test.js diff --git a/test/0.4.24/lidoHandleOracleReport.test.js b/test/0.4.24/lidoHandleOracleReport.test.js deleted file mode 100644 index af4d83571..000000000 --- a/test/0.4.24/lidoHandleOracleReport.test.js +++ /dev/null @@ -1,238 +0,0 @@ -const hre = require('hardhat') -const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') -const { assert } = require('../helpers/assert') -const { assertRevert } = require('../helpers/assertThrow') -const { deployProtocol } = require('../helpers/protocol') -const { pushOracleReport } = require('../helpers/oracle') -const { EvmSnapshot } = require('../helpers/blockchain') - -const ETH = (value) => web3.utils.toWei(value + '', 'ether') - -contract.skip('Lido: handleOracleReport', ([appManager, stranger, depositor]) => { - let app, consensus, oracle, snapshot - - before('deploy base app', async () => { - const deployed = await deployProtocol({ - depositSecurityModuleFactory: async () => { - return { address: depositor } - } - }) - - app = deployed.pool - consensus = deployed.consensusContract - oracle = deployed.oracle - - snapshot = new EvmSnapshot(hre.ethers.provider) - await snapshot.make() - }) - - afterEach(async () => { - await snapshot.rollback() - }) - - /// - /// TODO: proper tests for the new accounting - /// - - const checkStat = async ({ depositedValidators, beaconValidators, beaconBalance }) => { - const stat = await app.getBeaconStat() - assertBn(stat.depositedValidators, depositedValidators, 'depositedValidators check') - assertBn(stat.beaconValidators, beaconValidators, 'beaconValidators check') - assertBn(stat.beaconBalance, beaconBalance, 'beaconBalance check') - } - - it('reportBeacon access control', async () => { - await assertRevert(app.handleOracleReport(0, 0, 0, 0, 0, 0, 0, false, { from: stranger }), 'APP_AUTH_FAILED') - }) - - context('with depositedVals=0, beaconVals=0, bcnBal=0, bufferedEth=0', async () => { - it('report BcnValidators:0 BcnBalance:0 = no rewards', async () => { - console.log(consensus.address, oracle.address) - await pushOracleReport(consensus, oracle, 0, 0) - checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getBufferedEther(), ETH(0)) - assertBn(await app.getTotalPooledEther(), ETH(0)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - - it('report BcnValidators:1 = revert', async () => { - await assertRevert(pushOracleReport(consensus, oracle, 1, 0), 'REPORTED_MORE_DEPOSITED') - checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getBufferedEther(), ETH(0)) - assertBn(await app.getTotalPooledEther(), ETH(0)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - }) - - context('with depositedVals=0, beaconVals=0, bcnBal=0, bufferedEth=12', async () => { - it('report BcnValidators:0 BcnBalance:0 = no rewards', async () => { - await pushOracleReport(consensus, oracle, 0, 0) - checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getBufferedEther(), ETH(12)) - assertBn(await app.getTotalPooledEther(), ETH(12)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - - await assertRevert(pushOracleReport(consensus, oracle, 1, 0), 'REPORTED_MORE_DEPOSITED') - checkStat({ depositedValidators: 0, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getBufferedEther(), ETH(12)) - assertBn(await app.getTotalPooledEther(), ETH(12)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - }) - - context('with depositedVals=1, beaconVals=0, bcnBal=0, bufferedEth=3', async () => { - it('initial state before report', async () => { - checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getBufferedEther(), ETH(3)) - assertBn(await app.getTotalPooledEther(), ETH(35)) - }) - - it('report BcnValidators:0 BcnBalance:0 = no rewards', async () => { - await pushOracleReport(consensus, oracle, 0, 0) - checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getBufferedEther(), ETH(3)) - assertBn(await app.getTotalPooledEther(), ETH(35)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - - it('report BcnValidators:2 = revert', async () => { - await assertRevert( - pushOracleReport(consensus, oracle, 2, ETH(65)), - 'REPORTED_MORE_DEPOSITED' - ) - checkStat({ depositedValidators: 1, beaconValidators: 0, beaconBalance: ETH(0) }) - assertBn(await app.getBufferedEther(), ETH(3)) - assertBn(await app.getTotalPooledEther(), ETH(35)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - - it('report BcnValidators:1 BcnBalance:31 = no rewards', async () => { - await pushOracleReport(consensus, oracle, 1, ETH(31)) - checkStat({ depositedValidators: 1, beaconValidators: 1, beaconBalance: ETH(31) }) - assertBn(await app.getBufferedEther(), ETH(3)) - assertBn(await app.getTotalPooledEther(), ETH(34)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - - it('report BcnValidators:1 BcnBalance:32 = no rewards', async () => { - await pushOracleReport(consensus, oracle, 1, ETH(32)) - checkStat({ depositedValidators: 1, beaconValidators: 1, beaconBalance: ETH(32) }) - assertBn(await app.getBufferedEther(), ETH(3)) - assertBn(await app.getTotalPooledEther(), ETH(35)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - }) - - context('with depositedVals=2, beaconVals=1, bcnBal=30, bufferedEth=5', async () => { - beforeEach(async function () { - await app.setDepositedValidators(2) - await app.setBeaconBalance(ETH(30)) - await app.setBufferedEther({ from: stranger, value: ETH(5) }) - await app.setBeaconValidators(1) - await app.setTotalShares(ETH(67)) - }) - - it('initial state before report', async () => { - checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(30) }) - assertBn(await app.getBufferedEther(), ETH(5)) - assertBn(await app.getTotalPooledEther(), ETH(67)) - }) - - it('report BcnValidators:1 BcnBalance:0 = no rewards', async () => { - await pushOracleReport(consensus, oracle, 1, 0) - checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(0) }) - assertBn(await app.getBufferedEther(), ETH(5)) - assertBn(await app.getTotalPooledEther(), ETH(37)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - - it('report BcnValidators:1 BcnBalance:1 = no rewards', async () => { - await pushOracleReport({epochId: 100, clValidators: 1, clBalance: ETH(1)}) - checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(1) }) - assertBn(await app.getBufferedEther(), ETH(5)) - assertBn(await app.getTotalPooledEther(), ETH(38)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - - it('report BcnValidators:2 BcnBalance:62 = no reward', async () => { - await pushOracleReport({epochId: 100, clValidators: 2, clBalance: ETH(62)}) - checkStat({ depositedValidators: 2, beaconValidators: 2, beaconBalance: ETH(62) }) - assertBn(await app.getBufferedEther(), ETH(5)) - assertBn(await app.getTotalPooledEther(), ETH(67)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - - it('report BcnValidators:1 BcnBalance:31 = reward:1', async () => { - await pushOracleReport({epochId: 100, clValidators: 2, clBalance: ETH(63)}) - checkStat({ depositedValidators: 2, beaconValidators: 2, beaconBalance: ETH(63) }) - assertBn(await app.getBufferedEther(), ETH(5)) - assertBn(await app.getTotalPooledEther(), ETH(68)) - // assert.equal(await app.distributeFeeCalled(), true) - // assertBn(await app.totalRewards(), ETH(1)) // rounding error - }) - - it('report BcnValidators:2 BcnBalance:63 = reward:1', async () => { - await pushOracleReport({epochId: 100, clValidators: 2, clBalance: ETH(63)}) - checkStat({ depositedValidators: 2, beaconValidators: 2, beaconBalance: ETH(63) }) - assertBn(await app.getBufferedEther(), ETH(5)) - assertBn(await app.getTotalPooledEther(), ETH(68)) - // assert.equal(await app.distributeFeeCalled(), true) - // assertBn(await app.totalRewards(), ETH(1)) // rounding error - }) - - it('report BcnValidators:3 = revert with REPORTED_MORE_DEPOSITED', async () => { - await assertRevert( - pushOracleReport({epochId: 110, clValidators: 3, clBalance: ETH(65)}), - 'REPORTED_MORE_DEPOSITED' - ) - checkStat({ depositedValidators: 2, beaconValidators: 1, beaconBalance: ETH(30) }) - assertBn(await app.getBufferedEther(), ETH(5)) - assertBn(await app.getTotalPooledEther(), ETH(67)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - }) - - context('with depositedVals=5, beaconVals=4, bcnBal=1, bufferedEth=0', async () => { - beforeEach(async function () { - await app.setDepositedValidators(5) - await app.setBeaconBalance(ETH(1)) - await app.setBufferedEther({ from: stranger, value: ETH(0) }) - await app.setBeaconValidators(4) - }) - - // See LIP-1 for explanation - // https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-1.md - it('report decreased BcnValidators:3 = revert with REPORTED_LESS_VALIDATORS', async () => { - await assertRevert( - pushOracleReport(consensus, oracle, 3, ETH(1)), - 'REPORTED_LESS_VALIDATORS' - ) - await assertRevert( - pushOracleReport(consensus, oracle, 2, ETH(10)), - 'REPORTED_LESS_VALIDATORS' - ) - await assertRevert( - pushOracleReport(consensus, oracle, 1, ETH(123)), - 'REPORTED_LESS_VALIDATORS' - ) - // values stay intact - checkStat({ depositedValidators: 5, beaconValidators: 4, beaconBalance: ETH(1) }) - assertBn(await app.getBufferedEther(), ETH(0)) - assertBn(await app.getTotalPooledEther(), ETH(33)) - // assert.equal(await app.distributeFeeCalled(), false) - // assertBn(await app.totalRewards(), 0) - }) - }) -}) From eb19d963b0bdab26efaf52d4d9007bff44a0ec68 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Mon, 20 Feb 2023 18:44:26 +0700 Subject: [PATCH 150/199] test: ValidatorsExitBusOracle._handleConsensusReportData checks that moduleId is not equals zero --- .../validators-exit-bus-oracle-submit-report-data.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index cad1c36fc..37bf296e9 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -220,6 +220,13 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger }) }) + it('reverts if moduleId equals zero', async () => { + const report = await prepareReportAndSubmitHash([ + { moduleId: 0, nodeOpId: 3, valIndex: 0, valPubkey: PUBKEYS[0] } + ]) + await assert.reverts(oracle.submitReportData(report, oracleVersion, { from: member1 }), 'InvalidRequestsData()') + }) + it('updates processing state', async () => { const storageBefore = await oracle.getDataProcessingState() assert.equals(+storageBefore.refSlot, 0) From 61e1ce31ddc599d8fb7f9969ccf5c52c59cfa2c7 Mon Sep 17 00:00:00 2001 From: Logachev Nikita Date: Mon, 20 Feb 2023 18:38:21 +0700 Subject: [PATCH 151/199] add check address --- contracts/0.8.9/StakingRouter.sol | 9 +++++++++ lib/abi/StakingRouter.json | 2 +- test/0.8.9/staking-router.test.js | 21 ++++++++++++++++++--- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/contracts/0.8.9/StakingRouter.sol b/contracts/0.8.9/StakingRouter.sol index 9686ee7a6..dff74ae2d 100644 --- a/contracts/0.8.9/StakingRouter.sol +++ b/contracts/0.8.9/StakingRouter.sol @@ -54,6 +54,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version uint256 currentNodeOpExitedValidatorsCount, uint256 currentNodeOpStuckValidatorsCount ); + error StakingModuleAddressExists(); enum StakingModuleStatus { Active, // deposits and rewards allowed @@ -184,6 +185,14 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version uint256 newStakingModuleIndex = getStakingModulesCount(); if (newStakingModuleIndex >= 32) revert StakingModulesLimitExceeded(); + + for (uint256 i; i < newStakingModuleIndex; ) { + if (_stakingModuleAddress == _getStakingModuleByIndex(i).stakingModuleAddress) revert StakingModuleAddressExists(); + unchecked { + ++i; + } + } + StakingModule storage newStakingModule = _getStakingModuleByIndex(newStakingModuleIndex); uint24 newStakingModuleId = uint24(LAST_STAKING_MODULE_ID_POSITION.getStorageUint256()) + 1; diff --git a/lib/abi/StakingRouter.json b/lib/abi/StakingRouter.json index eadd0ae03..5b0f25cae 100644 --- a/lib/abi/StakingRouter.json +++ b/lib/abi/StakingRouter.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"EmptyWithdrawalsCredentials","type":"error"},{"inputs":[],"name":"ExitedValidatorsCountCannotDecrease","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidReportData","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotExpectedBalance","type":"error"},{"inputs":[],"name":"StakingModuleIdTooLarge","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","type":"error"},{"inputs":[],"name":"StakingModuleNotPaused","type":"error"},{"inputs":[],"name":"StakingModuleStatusTheSame","type":"error"},{"inputs":[],"name":"StakingModuleUnregistered","type":"error"},{"inputs":[],"name":"StakingModuleWrongName","type":"error"},{"inputs":[],"name":"StakingModulesLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpStuckValidatorsCount","type":"uint256"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ValueOver100Percent","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","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":false,"internalType":"address","name":"stakingModule","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"createdBy","type":"address"}],"name":"StakingModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unreportedExitedValidatorsCount","type":"uint256"}],"name":"StakingModuleExitedValidatorsIncompleteReporting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingModuleFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"enum StakingRouter.StakingModuleStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleTargetShareSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingRouterETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalCredentials","type":"bytes32"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"WithdrawalCredentialsSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PRECISION_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_WITHDRAWAL_CREDENTIALS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_REWARDS_MINTED_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_MANAGE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_SET_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_stakingModuleAddress","type":"address"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxDepositsCount","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"depositsCount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getAllNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"}],"name":"getDepositsAllocation","outputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLido","outputs":[{"internalType":"contract ILido","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256[]","name":"_nodeOperatorIds","type":"uint256[]"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"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":"getStakingFeeAggregateDistribution","outputs":[{"internalType":"uint96","name":"modulesFee","type":"uint96"},{"internalType":"uint96","name":"treasuryFee","type":"uint96"},{"internalType":"uint256","name":"basePrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingFeeAggregateDistributionE4Precision","outputs":[{"internalType":"uint16","name":"modulesFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModule","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleActiveValidatorsCount","outputs":[{"internalType":"uint256","name":"activeValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"}],"name":"getStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleIds","outputs":[{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleLastDepositBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleMaxDepositsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleStatus","outputs":[{"internalType":"enum StakingRouter.StakingModuleStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleSummary","outputs":[{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModules","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule[]","name":"res","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingRewardsDistribution","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"},{"internalType":"uint96[]","name":"stakingModuleFees","type":"uint96[]"},{"internalType":"uint96","name":"totalFee","type":"uint96"},{"internalType":"uint256","name":"precisionPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFeeE4Precision","outputs":[{"internalType":"uint16","name":"totalFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalCredentials","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"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"pauseStakingModule","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":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_totalShares","type":"uint256[]"}],"name":"reportRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"resumeStakingModule","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":"_stakingModuleId","type":"uint256"},{"internalType":"enum StakingRouter.StakingModuleStatus","name":"_status","type":"uint8"}],"name":"setStakingModuleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","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":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"_triggerUpdateFinish","type":"bool"},{"components":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorStuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorStuckValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.ValidatorsCountCorrection","name":"_correction","type":"tuple"}],"name":"unsafeSetExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"EmptyWithdrawalsCredentials","type":"error"},{"inputs":[],"name":"ExitedValidatorsCountCannotDecrease","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidReportData","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotExpectedBalance","type":"error"},{"inputs":[],"name":"StakingModuleAddressExists","type":"error"},{"inputs":[],"name":"StakingModuleIdTooLarge","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","type":"error"},{"inputs":[],"name":"StakingModuleNotPaused","type":"error"},{"inputs":[],"name":"StakingModuleStatusTheSame","type":"error"},{"inputs":[],"name":"StakingModuleUnregistered","type":"error"},{"inputs":[],"name":"StakingModuleWrongName","type":"error"},{"inputs":[],"name":"StakingModulesLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpStuckValidatorsCount","type":"uint256"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ValueOver100Percent","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","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":false,"internalType":"address","name":"stakingModule","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"createdBy","type":"address"}],"name":"StakingModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unreportedExitedValidatorsCount","type":"uint256"}],"name":"StakingModuleExitedValidatorsIncompleteReporting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingModuleFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"enum StakingRouter.StakingModuleStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleTargetShareSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingRouterETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalCredentials","type":"bytes32"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"WithdrawalCredentialsSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PRECISION_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_WITHDRAWAL_CREDENTIALS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_REWARDS_MINTED_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_MANAGE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_SET_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_stakingModuleAddress","type":"address"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxDepositsCount","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"depositsCount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getAllNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"}],"name":"getDepositsAllocation","outputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLido","outputs":[{"internalType":"contract ILido","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256[]","name":"_nodeOperatorIds","type":"uint256[]"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"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":"getStakingFeeAggregateDistribution","outputs":[{"internalType":"uint96","name":"modulesFee","type":"uint96"},{"internalType":"uint96","name":"treasuryFee","type":"uint96"},{"internalType":"uint256","name":"basePrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingFeeAggregateDistributionE4Precision","outputs":[{"internalType":"uint16","name":"modulesFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModule","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleActiveValidatorsCount","outputs":[{"internalType":"uint256","name":"activeValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"}],"name":"getStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleIds","outputs":[{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleLastDepositBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleMaxDepositsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleStatus","outputs":[{"internalType":"enum StakingRouter.StakingModuleStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleSummary","outputs":[{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModules","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule[]","name":"res","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingRewardsDistribution","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"},{"internalType":"uint96[]","name":"stakingModuleFees","type":"uint96[]"},{"internalType":"uint96","name":"totalFee","type":"uint96"},{"internalType":"uint256","name":"precisionPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFeeE4Precision","outputs":[{"internalType":"uint16","name":"totalFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalCredentials","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"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"pauseStakingModule","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":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_totalShares","type":"uint256[]"}],"name":"reportRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"resumeStakingModule","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":"_stakingModuleId","type":"uint256"},{"internalType":"enum StakingRouter.StakingModuleStatus","name":"_status","type":"uint8"}],"name":"setStakingModuleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","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":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"_triggerUpdateFinish","type":"bool"},{"components":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorStuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorStuckValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.ValidatorsCountCorrection","name":"_correction","type":"tuple"}],"name":"unsafeSetExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/test/0.8.9/staking-router.test.js b/test/0.8.9/staking-router.test.js index 883b5566e..22f9cb232 100644 --- a/test/0.8.9/staking-router.test.js +++ b/test/0.8.9/staking-router.test.js @@ -199,6 +199,19 @@ contract('StakingRouter', ([deployer, lido, admin, appManager, stranger]) => { await snapshot.revert() }) + it('reverts if module address exists', async () => { + await assert.revertsWithCustomError( + app.addStakingModule( + 'Test', + stakingModule.address, + 100, + 1000, + 2000, + { from: appManager}), + 'StakingModuleAddressExists()' + ) + }) + it('set withdrawal credentials does not allowed without role', async () => { const newWC = '0x'.padEnd(66, '5678') await assert.reverts( @@ -265,12 +278,14 @@ contract('StakingRouter', ([deployer, lido, admin, appManager, stranger]) => { await snapshot.revert() }) it('staking modules limit is 32', async () => { - const stakingModule = await StakingModuleMock.new({ from: deployer }) for (var i = 0; i < 32; i++) { - await app.addStakingModule('Test module', stakingModule.address, 100, 100, 100, { from: appManager }) + const stakingModule = await StakingModuleMock.new({ from: deployer }) + let tx = await app.addStakingModule('Test module', stakingModule.address, 100, 100, 100, { from: appManager }) } + + const oneMoreStakingModule = await StakingModuleMock.new({ from: deployer }) await assert.revertsWithCustomError( - app.addStakingModule('Test module', stakingModule.address, 100, 100, 100, { from: appManager }), + app.addStakingModule('Test module', oneMoreStakingModule.address, 100, 100, 100, { from: appManager }), `StakingModulesLimitExceeded()` ) }) From 90b526fade99f15da5842899ebc72a1b0171c622 Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Mon, 20 Feb 2023 18:45:07 +0700 Subject: [PATCH 152/199] test: ValidatorsExitBusOracle._handleConsensusReportData emits ValidatorExitRequest events --- ...exit-bus-oracle-submit-report-data.test.js | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index 37bf296e9..6f7d63856 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -227,6 +227,32 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger await assert.reverts(oracle.submitReportData(report, oracleVersion, { from: member1 }), 'InvalidRequestsData()') }) + it('emits ValidatorExitRequest events', async () => { + const requests = [ + { moduleId: 4, nodeOpId: 2, valIndex: 2, valPubkey: PUBKEYS[2] }, + { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[3] } + ] + const report = await prepareReportAndSubmitHash(requests) + const tx = await oracle.submitReportData(report, oracleVersion, { from: member1 }) + const timestamp = await consensus.getTime() + + assert.emits(tx, 'ValidatorExitRequest', { + stakingModuleId: requests[0].moduleId, + nodeOperatorId: requests[0].nodeOpId, + validatorIndex: requests[0].valIndex, + validatorPubkey: requests[0].valPubkey, + timestamp + }) + + assert.emits(tx, 'ValidatorExitRequest', { + stakingModuleId: requests[1].moduleId, + nodeOperatorId: requests[1].nodeOpId, + validatorIndex: requests[1].valIndex, + validatorPubkey: requests[1].valPubkey, + timestamp + }) + }) + it('updates processing state', async () => { const storageBefore = await oracle.getDataProcessingState() assert.equals(+storageBefore.refSlot, 0) @@ -283,6 +309,23 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger currentCount += requestsStep3.length assert.equals(+countStep3, currentCount) }) + + // TODO: check why it reverts + // it('', async () => { + // // Step 1 + // const requestsStep1 = [{ moduleId: 3, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[1] }] + // const reportStep1 = await prepareReportAndSubmitHash(requestsStep1) + // await oracle.submitReportData(reportStep1, oracleVersion, { from: member1 }) + + // // Step 2 + // // no await consensus.advanceTimeToNextFrameStart() + // const requestsStep2 = [ + // { moduleId: 4, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[2] }, + // { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[3] } + // ] + // const reportStep2 = await prepareReportAndSubmitHash(requestsStep2) + // await oracle.submitReportData(reportStep2, oracleVersion, { from: member1 }) + // }) }) context(`requires validator indices for the same node operator to increase`, () => { From 41d2413fae9f79c02b21e9f36b66181d82ac988b Mon Sep 17 00:00:00 2001 From: Dmitrii Podlesnyi Date: Mon, 20 Feb 2023 19:06:36 +0700 Subject: [PATCH 153/199] test: remove unrelevant testcase --- ...s-exit-bus-oracle-submit-report-data.test.js | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index 6f7d63856..1aa9ca2d1 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -309,23 +309,6 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger currentCount += requestsStep3.length assert.equals(+countStep3, currentCount) }) - - // TODO: check why it reverts - // it('', async () => { - // // Step 1 - // const requestsStep1 = [{ moduleId: 3, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[1] }] - // const reportStep1 = await prepareReportAndSubmitHash(requestsStep1) - // await oracle.submitReportData(reportStep1, oracleVersion, { from: member1 }) - - // // Step 2 - // // no await consensus.advanceTimeToNextFrameStart() - // const requestsStep2 = [ - // { moduleId: 4, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[2] }, - // { moduleId: 5, nodeOpId: 3, valIndex: 2, valPubkey: PUBKEYS[3] } - // ] - // const reportStep2 = await prepareReportAndSubmitHash(requestsStep2) - // await oracle.submitReportData(reportStep2, oracleVersion, { from: member1 }) - // }) }) context(`requires validator indices for the same node operator to increase`, () => { From dc90118e44e5b6ea47c2d196b262ed01e3944618 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Mon, 20 Feb 2023 19:16:07 +0700 Subject: [PATCH 154/199] feat: pause tests and clean up --- .../validators-exit-bus-oracle-deploy.test.js | 32 ++++++++++++------- ...exit-bus-oracle-submit-report-data.test.js | 10 +++++- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js index 4579f9a9d..35148c5b7 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-deploy.test.js @@ -31,9 +31,6 @@ function getReportDataItems(r) { function calcReportDataHash(reportItems) { const data = web3.eth.abi.encodeParameters(['(uint256,uint256,uint256,uint256,bytes)'], [reportItems]) - // const toS = x => Array.isArray(x) ? `[${x.map(toS)}]` : `${x}` - // console.log(toS(reportItems)) - // console.log(data) return web3.utils.keccak256(data) } @@ -100,13 +97,16 @@ async function deployOracleReportSanityCheckerForExitBus(lidoLocator, admin) { return oracleReportSanityChecker } -async function deployExitBusOracle(admin, { - dataSubmitter = null, - lastProcessingRefSlot = 0, - resumeAfterDeploy = false, - pauser = ZERO_ADDRESS, - resumer = ZERO_ADDRESS, -} = {}) { +async function deployExitBusOracle( + admin, + { + dataSubmitter = null, + lastProcessingRefSlot = 0, + resumeAfterDeploy = false, + pauser = ZERO_ADDRESS, + resumer = ZERO_ADDRESS + } = {} +) { const locator = (await deployLocatorWithDummyAddressesImplementation(admin)).address const oracle = await ValidatorsExitBusOracle.new(SECONDS_PER_SLOT, GENESIS_TIME, locator, { from: admin }) @@ -129,7 +129,7 @@ async function deployExitBusOracle(admin, { consensus.address, CONSENSUS_VERSION, lastProcessingRefSlot, - {from: admin} + { from: admin } ) assert.emits(initTx, 'ContractVersionSet', { version: 1 }) @@ -164,6 +164,7 @@ async function deployExitBusOracle(admin, { return { consensus, oracle, oracleReportSanityChecker, locator, initTx } } + contract('ValidatorsExitBusOracle', ([admin, member1]) => { let consensus let oracle @@ -180,7 +181,6 @@ contract('ValidatorsExitBusOracle', ([admin, member1]) => { assert.equal(+(await oracle.getTime()), time1) await consensus.advanceTimeBy(SECONDS_PER_SLOT) - const time2 = +(await consensus.getTime()) assert.equal(time2, time1 + SECONDS_PER_SLOT) assert.equal(+(await oracle.getTime()), time2) @@ -192,5 +192,13 @@ contract('ValidatorsExitBusOracle', ([admin, member1]) => { assert.equal(+(await oracle.SECONDS_PER_SLOT()), SECONDS_PER_SLOT) assert.equal(await oracle.isPaused(), true) }) + + it('pause/resume operations work', async () => { + assert.equal(await oracle.isPaused(), true) + await oracle.resume() + assert.equal(await oracle.isPaused(), false) + await oracle.pause(123) + assert.equal(await oracle.isPaused(), true) + }) }) }) diff --git a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js index cad1c36fc..a87d8020b 100644 --- a/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js +++ b/test/0.8.9/oracle/validators-exit-bus-oracle-submit-report-data.test.js @@ -370,7 +370,7 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger }) }) - context(`only consensus member or SUBMIT_DATA_ROLE can submit report`, () => { + context(`only consensus member or SUBMIT_DATA_ROLE can submit report on unpaused contract`, () => { beforeEach(setup) it('reverts on stranger', async () => { @@ -391,6 +391,14 @@ contract('ValidatorsExitBusOracle', ([admin, member1, member2, member3, stranger const report = await prepareReportAndSubmitHash() await oracle.submitReportData(report, oracleVersion, { from: member1 }) }) + + it('reverts on paused contract', async () => { + await consensus.advanceTimeToNextFrameStart() + const PAUSE_INFINITELY = await oracle.PAUSE_INFINITELY() + await oracle.pause(PAUSE_INFINITELY, { from: admin }) + const report = await prepareReportAndSubmitHash() + assert.reverts(oracle.submitReportData(report, oracleVersion, { from: member1 }), 'ResumedExpected()') + }) }) context('invokes internal baseOracle checks', () => { From b90b6f97699453c096552de0c5a960db357f2a38 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Mon, 20 Feb 2023 19:16:51 +0700 Subject: [PATCH 155/199] chore: abi --- lib/abi/ValidatorsExitBusOracle.json | 516 +-------------------------- 1 file changed, 1 insertion(+), 515 deletions(-) diff --git a/lib/abi/ValidatorsExitBusOracle.json b/lib/abi/ValidatorsExitBusOracle.json index 13f8b1e8c..d8dfe9d41 100644 --- a/lib/abi/ValidatorsExitBusOracle.json +++ b/lib/abi/ValidatorsExitBusOracle.json @@ -1,515 +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": [], "name": "InvalidContractVersionIncrement", "type": "error" }, - { "inputs": [], "name": "InvalidRequestsData", "type": "error" }, - { "inputs": [], "name": "InvalidRequestsDataLength", "type": "error" }, - { "inputs": [], "name": "InvalidRequestsDataSortOrder", "type": "error" }, - { - "inputs": [ - { "internalType": "uint256", "name": "moduleId", "type": "uint256" }, - { "internalType": "uint256", "name": "nodeOpId", "type": "uint256" }, - { "internalType": "uint256", "name": "prevRequestedValidatorIndex", "type": "uint256" }, - { "internalType": "uint256", "name": "requestedValidatorIndex", "type": "uint256" } - ], - "name": "NodeOpValidatorIndexMustIncrease", - "type": "error" - }, - { "inputs": [], "name": "NonZeroContractVersionOnInit", "type": "error" }, - { "inputs": [], "name": "OnlyConsensusContractCanSubmitReport", "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": "processingRefSlot", "type": "uint256" } - ], - "name": "RefSlotCannotBeLessThanProcessingOne", - "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": "ResumedExpected", "type": "error" }, - { "inputs": [], "name": "SenderNotAllowed", "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": [], "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": "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" }, - { "indexed": false, "internalType": "uint256", "name": "processingDeadlineTime", "type": "uint256" } - ], - "name": "ReportSubmitted", - "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": "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": "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": [], - "name": "getLastProcessingRefSlot", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "moduleId", "type": "uint256" }, - { "internalType": "uint256[]", "name": "nodeOpIds", "type": "uint256[]" } - ], - "name": "getLastRequestedValidatorIndices", - "outputs": [{ "internalType": "int256[]", "name": "", "type": "int256[]" }], - "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": "pauser", "type": "address" }, - { "internalType": "address", "name": "resumer", "type": "address" }, - { "internalType": "address", "name": "consensusContract", "type": "address" }, - { "internalType": "uint256", "name": "consensusVersion", "type": "uint256" }, - { "internalType": "uint256", "name": "lastProcessingRefSlot", "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": "pause", - "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": "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": "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":[{"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":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidRequestsData","type":"error"},{"inputs":[],"name":"InvalidRequestsDataLength","type":"error"},{"inputs":[],"name":"InvalidRequestsDataSortOrder","type":"error"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256","name":"nodeOpId","type":"uint256"},{"internalType":"uint256","name":"prevRequestedValidatorIndex","type":"uint256"},{"internalType":"uint256","name":"requestedValidatorIndex","type":"uint256"}],"name":"NodeOpValidatorIndexMustIncrease","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","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":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"ResumedExpected","type":"error"},{"inputs":[],"name":"SenderNotAllowed","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":[],"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":"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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"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":"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":[],"name":"getLastProcessingRefSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"moduleId","type":"uint256"},{"internalType":"uint256[]","name":"nodeOpIds","type":"uint256[]"}],"name":"getLastRequestedValidatorIndices","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"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":"pauser","type":"address"},{"internalType":"address","name":"resumer","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"lastProcessingRefSlot","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":"pause","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":"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":"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"}] \ No newline at end of file From be5fbd70e95e34bb9911eccdae57f4f6b5a8c1c9 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Mon, 20 Feb 2023 14:41:05 +0200 Subject: [PATCH 156/199] =?UTF-8?q?=F0=9F=92=85:=20tidy=20up=20interfaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/0.8.9/WithdrawalQueue.sol | 23 ++- contracts/0.8.9/WithdrawalQueueBase.sol | 194 +++++++++++------------- lib/abi/WithdrawalQueue.json | 2 +- lib/abi/WithdrawalQueueBase.json | 2 +- lib/abi/WithdrawalQueueERC721.json | 2 +- test/0.8.9/withdrawal-queue.test.js | 51 ++++--- 6 files changed, 133 insertions(+), 141 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueue.sol b/contracts/0.8.9/WithdrawalQueue.sol index 01819dea8..1f190a64d 100644 --- a/contracts/0.8.9/WithdrawalQueue.sol +++ b/contracts/0.8.9/WithdrawalQueue.sol @@ -8,6 +8,7 @@ import {WithdrawalQueueBase} from "./WithdrawalQueueBase.sol"; import {IERC20} from "@openzeppelin/contracts-v4.4/token/ERC20/IERC20.sol"; import {IERC20Permit} from "@openzeppelin/contracts-v4.4/token/ERC20/extensions/draft-IERC20Permit.sol"; +import {EnumerableSet} from "@openzeppelin/contracts-v4.4/utils/structs/EnumerableSet.sol"; import {AccessControlEnumerable} from "./utils/access/AccessControlEnumerable.sol"; import {UnstructuredStorage} from "./lib/UnstructuredStorage.sol"; import {PausableUntil} from "./utils/PausableUntil.sol"; @@ -32,6 +33,7 @@ interface IWstETH is IERC20, IERC20Permit { /// @author folkyatina abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, WithdrawalQueueBase, Versioned { using UnstructuredStorage for bytes32; + using EnumerableSet for EnumerableSet.UintSet; /// Bunker mode activation timestamp bytes32 internal constant BUNKER_MODE_SINCE_TIMESTAMP_POSITION = @@ -185,16 +187,26 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit return requestWithdrawalsWstETH(_amounts, _owner); } + /// @notice Returns all withdrawal requests that belongs to the `_owner` address + /// + /// WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + /// to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + /// this function has an unbounded cost, and using it as part of a state-changing function may render the function + /// uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + function getWithdrawalRequests(address _owner) external view returns (uint256[] memory requestsIds) { + return _getRequestsByOwner()[_owner].values(); + } + /// @notice Returns statuses for the array of request ids /// @param _requestIds array of withdrawal request ids - function getWithdrawalRequestStatuses(uint256[] calldata _requestIds) + function getWithdrawalStatus(uint256[] calldata _requestIds) external view returns (WithdrawalRequestStatus[] memory statuses) { statuses = new WithdrawalRequestStatus[](_requestIds.length); for (uint256 i = 0; i < _requestIds.length; ++i) { - statuses[i] = getWithdrawalRequestStatus(_requestIds[i]); + statuses[i] = _getStatus(_requestIds[i]); } } @@ -251,13 +263,13 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit /// @notice Claim one`_requestId` request once finalized sending locked ether to the owner /// @param _requestId request id to claim - /// @dev will use `findCheckpointHintUnbounded()` to find a hint, which can lead to OOG + /// @dev use unbounded loop to find a hint, which can lead to OOG /// @dev /// Reverts if requestId or hint are not valid /// Reverts if request is not finalized or already claimed /// Reverts if msg sender is not an owner of request function claimWithdrawal(uint256 _requestId) external { - _claim(_requestId, findCheckpointHintUnbounded(_requestId), msg.sender); + _claim(_requestId, _findCheckpointHint(_requestId, 1, getLastCheckpointIndex()), msg.sender); _emitTransfer(msg.sender, address(0), _requestId); } @@ -276,7 +288,7 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit uint256 prevRequestId = 0; for (uint256 i = 0; i < _requestIds.length; ++i) { if (_requestIds[i] < prevRequestId) revert RequestIdsNotSorted(); - hintIds[i] = findCheckpointHint(_requestIds[i], _firstIndex, _lastIndex); + hintIds[i] = _findCheckpointHint(_requestIds[i], _firstIndex, _lastIndex); _firstIndex = hintIds[i]; prevRequestId = _requestIds[i]; } @@ -285,7 +297,6 @@ abstract contract WithdrawalQueue is AccessControlEnumerable, PausableUntil, Wit /// @notice Finds the list of hints for the given `_requestIds` searching among the checkpoints with indices /// in the range `[1, lastCheckpointIndex]`. NB! Array of request ids should be sorted /// @dev WARNING! OOG is possible if used onchain. - /// See `findCheckpointHints(uint256[] calldata _requestIds, uint256 _firstIndex, uint256 _lastIndex)` for onchain use /// @param _requestIds ids of the requests sorted in the ascending order to get hints for function findCheckpointHintsUnbounded(uint256[] calldata _requestIds) public diff --git a/contracts/0.8.9/WithdrawalQueueBase.sol b/contracts/0.8.9/WithdrawalQueueBase.sol index 8455e881d..4d3f7886c 100644 --- a/contracts/0.8.9/WithdrawalQueueBase.sol +++ b/contracts/0.8.9/WithdrawalQueueBase.sol @@ -65,6 +65,22 @@ abstract contract WithdrawalQueueBase { uint96 discountFactor; } + /// @notice output format struct for `_getWithdrawalRequestStatus()` + struct WithdrawalRequestStatus { + /// @notice stETH token amount that was locked on withdrawal queue for this request + uint256 amountOfStETH; + /// @notice amount of stETH shares locked on withdrawal queue for this request + uint256 amountOfShares; + /// @notice address that can claim or transfer this request + address owner; + /// @notice timestamp of when the request was created, in seconds + uint256 timestamp; + /// @notice true, if request is finalized + bool isFinalized; + /// @notice true, if request is claimed. Request is claimable if (isFinalized && !isClaimed) + bool isClaimed; + } + /// @dev Contains both stETH token amount and its corresponding shares amount event WithdrawalRequested( uint256 indexed requestId, @@ -124,113 +140,6 @@ abstract contract WithdrawalQueueBase { _getQueue()[getLastRequestId()].cumulativeStETH - _getQueue()[getLastFinalizedRequestId()].cumulativeStETH; } - /// @notice Returns all withdrawal requests that belongs to the `_owner` address - /// - /// WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed - /// to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that - /// this function has an unbounded cost, and using it as part of a state-changing function may render the function - /// uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. - function getWithdrawalRequests(address _owner) external view returns (uint256[] memory requestsIds) { - return _getRequestsByOwner()[_owner].values(); - } - - /// @notice output format struct for `getWithdrawalRequestStatus()` - struct WithdrawalRequestStatus { - /// @notice stETH token amount that was locked on withdrawal queue for this request - uint256 amountOfStETH; - /// @notice amount of stETH shares locked on withdrawal queue for this request - uint256 amountOfShares; - /// @notice address that can claim or transfer this request - address owner; - /// @notice timestamp of when the request was created, in seconds - uint256 timestamp; - /// @notice true, if request is finalized - bool isFinalized; - /// @notice true, if request is claimed. Request is claimable if (isFinalized && !isClaimed) - bool isClaimed; - } - - /// @notice Returns status of the withdrawal request with `_requestId` id - function getWithdrawalRequestStatus(uint256 _requestId) - public - view - returns (WithdrawalRequestStatus memory status) - { - if (_requestId == 0 || _requestId > getLastRequestId()) revert InvalidRequestId(_requestId); - - WithdrawalRequest memory request = _getQueue()[_requestId]; - WithdrawalRequest memory previousRequest = _getQueue()[_requestId - 1]; - - status = WithdrawalRequestStatus( - request.cumulativeStETH - previousRequest.cumulativeStETH, - request.cumulativeShares - previousRequest.cumulativeShares, - request.owner, - request.timestamp, - _requestId <= getLastFinalizedRequestId(), - request.claimed - ); - } - - /// @notice View function to find a hint to pass it to `claimWithdrawal()`. - /// @dev WARNING! OOG is possible if used onchain, contains unbounded loop inside - /// See `findCheckpointHint(uint256 _requestId, uint256 _firstIndex, uint256 _lastIndex)` for onchain use - /// @param _requestId request id to be claimed with this hint - function findCheckpointHintUnbounded(uint256 _requestId) public view returns (uint256) { - return findCheckpointHint(_requestId, 1, getLastCheckpointIndex()); - } - - /// @notice View function to find a checkpoint hint for `claimWithdrawal()` - /// Search will be performed in the range of `[_firstIndex, _lastIndex]` - /// - /// NB!: Range search ought to be used to optimize gas cost. - /// You can utilize the following invariant: - /// `if (requestId2 > requestId1) than hint2 >= hint1`, - /// so you can search for `hint2` in the range starting from `hint1` - /// - /// @param _requestId request id we are searching the checkpoint for - /// @param _start index of the left boundary of the search range - /// @param _end index of the right boundary of the search range - /// - /// @return value that hints `claimWithdrawal` to find the discount for the request, - /// or 0 if hint not found in the range - function findCheckpointHint(uint256 _requestId, uint256 _start, uint256 _end) public view returns (uint256) { - if (_requestId == 0) revert InvalidRequestId(_requestId); - if (_start == 0) revert InvalidRequestIdRange(_start, _end); - uint256 lastCheckpointIndex = getLastCheckpointIndex(); - if (_end > lastCheckpointIndex) revert InvalidRequestIdRange(_start, _end); - if (_requestId > getLastFinalizedRequestId()) revert RequestNotFoundOrNotFinalized(_requestId); - - if (_start > _end) return NOT_FOUND; // we have an empty range to search in, so return NOT_FOUND - - // Right boundary - if (_requestId >= _getCheckpoints()[_end].fromRequestId) { - // it's the last checkpoint, so it's valid - if (_end == lastCheckpointIndex) return _end; - // it fits right before the next checkpoint - if (_requestId < _getCheckpoints()[_end + 1].fromRequestId) return _end; - - return NOT_FOUND; - } - // Left boundary - if (_requestId < _getCheckpoints()[_start].fromRequestId) { - return NOT_FOUND; - } - - // Binary search - uint256 min = _start; - uint256 max = _end - 1; - - while (max > min) { - uint256 mid = (max + min + 1) / 2; - if (_getCheckpoints()[mid].fromRequestId <= _requestId) { - min = mid; - } else { - max = mid - 1; - } - } - return min; - } - /// @notice Search for the latest request in the queue in the range of `[startId, endId]`, /// that has `request.timestamp <= maxTimestamp` /// @@ -397,7 +306,7 @@ abstract contract WithdrawalQueueBase { _amountOfETH, requestToFinalize.cumulativeShares - lastFinalizedRequest.cumulativeShares, block.timestamp - ); + ); } /// @dev creates a new `WithdrawalRequest` in the queue @@ -423,6 +332,75 @@ abstract contract WithdrawalQueueBase { emit WithdrawalRequested(requestId, msg.sender, _owner, _amountOfStETH, _amountOfShares); } + /// @notice Returns status of the withdrawal request with `_requestId` id + function _getStatus(uint256 _requestId) internal view returns (WithdrawalRequestStatus memory status) { + if (_requestId == 0 || _requestId > getLastRequestId()) revert InvalidRequestId(_requestId); + + WithdrawalRequest memory request = _getQueue()[_requestId]; + WithdrawalRequest memory previousRequest = _getQueue()[_requestId - 1]; + + status = WithdrawalRequestStatus( + request.cumulativeStETH - previousRequest.cumulativeStETH, + request.cumulativeShares - previousRequest.cumulativeShares, + request.owner, + request.timestamp, + _requestId <= getLastFinalizedRequestId(), + request.claimed + ); + } + + /// @notice View function to find a checkpoint hint for `claimWithdrawal()` + /// Search will be performed in the range of `[_firstIndex, _lastIndex]` + /// + /// NB!: Range search ought to be used to optimize gas cost. + /// You can utilize the following invariant: + /// `if (requestId2 > requestId1) than hint2 >= hint1`, + /// so you can search for `hint2` in the range starting from `hint1` + /// + /// @param _requestId request id we are searching the checkpoint for + /// @param _start index of the left boundary of the search range + /// @param _end index of the right boundary of the search range + /// + /// @return value that hints `claimWithdrawal` to find the discount for the request, + /// or 0 if hint not found in the range + function _findCheckpointHint(uint256 _requestId, uint256 _start, uint256 _end) internal view returns (uint256) { + if (_requestId == 0) revert InvalidRequestId(_requestId); + if (_start == 0) revert InvalidRequestIdRange(_start, _end); + uint256 lastCheckpointIndex = getLastCheckpointIndex(); + if (_end > lastCheckpointIndex) revert InvalidRequestIdRange(_start, _end); + if (_requestId > getLastFinalizedRequestId()) revert RequestNotFoundOrNotFinalized(_requestId); + + if (_start > _end) return NOT_FOUND; // we have an empty range to search in, so return NOT_FOUND + + // Right boundary + if (_requestId >= _getCheckpoints()[_end].fromRequestId) { + // it's the last checkpoint, so it's valid + if (_end == lastCheckpointIndex) return _end; + // it fits right before the next checkpoint + if (_requestId < _getCheckpoints()[_end + 1].fromRequestId) return _end; + + return NOT_FOUND; + } + // Left boundary + if (_requestId < _getCheckpoints()[_start].fromRequestId) { + return NOT_FOUND; + } + + // Binary search + uint256 min = _start; + uint256 max = _end - 1; + + while (max > min) { + uint256 mid = (max + min + 1) / 2; + if (_getCheckpoints()[mid].fromRequestId <= _requestId) { + min = mid; + } else { + max = mid - 1; + } + } + return min; + } + /// @notice Claim `_requestId` request and transfer locked ether to `_recipient`. Emits WithdrawalClaimed event /// @param _requestId request id to claim /// @param _hint hint for discount checkpoint index to avoid extensive search over the checkpoints. diff --git a/lib/abi/WithdrawalQueue.json b/lib/abi/WithdrawalQueue.json index 0cf482d55..630bba300 100644 --- a/lib/abi/WithdrawalQueue.json +++ b/lib/abi/WithdrawalQueue.json @@ -1 +1 @@ -[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueueBase.json b/lib/abi/WithdrawalQueueBase.json index 3f2b15df4..bb0aec71d 100644 --- a/lib/abi/WithdrawalQueueBase.json +++ b/lib/abi/WithdrawalQueueBase.json @@ -1 +1 @@ -[{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueueERC721.json b/lib/abi/WithdrawalQueueERC721.json index e45525902..ce9a574ad 100644 --- a/lib/abi/WithdrawalQueueERC721.json +++ b/lib/abi/WithdrawalQueueERC721.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"findCheckpointHint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"findCheckpointHintUnbounded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"_requestId","type":"uint256"}],"name":"getWithdrawalRequestStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus","name":"status","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalRequestStatuses","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/test/0.8.9/withdrawal-queue.test.js b/test/0.8.9/withdrawal-queue.test.js index 7b2e0d75f..3cdc196b3 100644 --- a/test/0.8.9/withdrawal-queue.test.js +++ b/test/0.8.9/withdrawal-queue.test.js @@ -69,7 +69,10 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { assert.equals(await withdrawalQueue.unfinalizedStETH(), StETH(300)) assert.equals(await withdrawalQueue.getWithdrawalRequests(owner), [1]) - const request = await withdrawalQueue.getWithdrawalRequestStatus(requestId) + const requests = await withdrawalQueue.getWithdrawalStatus([requestId]) + assert.equals(requests.length, 1) + + const request = requests[0] assert.equals(request.owner, owner) assert.equals(request.amountOfStETH, StETH(300)) @@ -106,7 +109,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { assert.equals(await withdrawalQueue.getLastRequestId(), requestId) assert.equals(await withdrawalQueue.getLastFinalizedRequestId(), 0) - const request = await withdrawalQueue.getWithdrawalRequestStatus(requestId) + const request = (await withdrawalQueue.getWithdrawalStatus([requestId]))[0] assert.equals(request.owner, owner) assert.equals(request.amountOfStETH, min) @@ -144,7 +147,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { assert.equals(await withdrawalQueue.getLastRequestId(), requestId) assert.equals(await withdrawalQueue.getLastFinalizedRequestId(), 0) - const request = await withdrawalQueue.getWithdrawalRequestStatus(requestId) + const request = (await withdrawalQueue.getWithdrawalStatus([requestId]))[0] assert.equals(request.owner, owner) assert.equals(request.amountOfStETH, max) @@ -387,7 +390,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { it('works', async () => { for (let i = 1; i <= numOfRequests; i++) { - const timestamp = (await withdrawalQueue.getWithdrawalRequestStatus(i)).timestamp; + const timestamp = ((await withdrawalQueue.getWithdrawalStatus([i]))[0]).timestamp; assert.equals(await withdrawalQueue.findLastFinalizableRequestIdByTimestamp(timestamp, 1, 10), i) } }) @@ -397,7 +400,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) it('return zero if no unfinalized request found', async () => { - const timestamp = (await withdrawalQueue.getWithdrawalRequestStatus(1)).timestamp; + const timestamp = ((await withdrawalQueue.getWithdrawalStatus([1]))[0]).timestamp; await withdrawalQueue.finalize(1, { from: steth.address, value: ETH[10] }) assert.equals(await withdrawalQueue.findLastFinalizableRequestIdByTimestamp(timestamp, 2, 10), 0) @@ -407,7 +410,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { await assert.reverts(withdrawalQueue.findLastFinalizableRequestIdByTimestamp(0, 0, 10), "ZeroTimestamp()") - const timestamp = (await withdrawalQueue.getWithdrawalRequestStatus(2)).timestamp; + const timestamp = ((await withdrawalQueue.getWithdrawalStatus([2]))[0]).timestamp; await assert.reverts(withdrawalQueue.findLastFinalizableRequestIdByTimestamp(timestamp, 0, 10), "InvalidRequestIdRange(0, 10)") @@ -480,7 +483,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { it('works', async () => { for (let i = 1; i <= numOfRequests; i++) { const budget = ETH(i * 10 + 5); - const timestamp = (await withdrawalQueue.getWithdrawalRequestStatus(i)).timestamp; + const timestamp = (await withdrawalQueue.getWithdrawalStatus([i]))[0].timestamp; assert.equals(await withdrawalQueue.findLastFinalizableRequestId(budget, shareRate(150), timestamp), i) } }) @@ -488,7 +491,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { it('returns zero if no unfinalized requests', async () => { await withdrawalQueue.finalize(10, { from: steth.address, value: ETH[10] }) - const timestamp = (await withdrawalQueue.getWithdrawalRequestStatus(10)).timestamp; + const timestamp = (await withdrawalQueue.getWithdrawalStatus([10]))[0].timestamp; assert.equals(await withdrawalQueue.findLastFinalizableRequestId(ETH(100), shareRate(100), timestamp), 0) }) @@ -504,7 +507,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { }) }) - context('findCheckpointHint()', async () => { + context('findCheckpointsHint()', async () => { const numOfRequests = 10; const requests = Array(numOfRequests).fill(ETH(20)) const discountedPrices = Array(numOfRequests).fill().map((_, i) => ETH(i)); @@ -515,38 +518,38 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { await withdrawalQueue.finalize(i, { from: steth.address, value: discountedPrices[i] }) } assert.equals(await withdrawalQueue.getLastCheckpointIndex(), numOfRequests) - assert.equals(await withdrawalQueue.findCheckpointHintUnbounded(await withdrawalQueue.getLastFinalizedRequestId()), + assert.equals(await withdrawalQueue.findCheckpointHintsUnbounded([await withdrawalQueue.getLastFinalizedRequestId()]), await withdrawalQueue.getLastCheckpointIndex()) }) it('works unbounded', async () => { - assert.equals(await withdrawalQueue.findCheckpointHintUnbounded(10), await withdrawalQueue.getLastCheckpointIndex()) + assert.equals(await withdrawalQueue.findCheckpointHintsUnbounded([10]), await withdrawalQueue.getLastCheckpointIndex()) }) it('reverts if request is not finalized', async () => { await withdrawalQueue.requestWithdrawals([ETH(1)], owner, { from: user }) - await assert.reverts(withdrawalQueue.findCheckpointHint(11, 1, 10), "RequestNotFoundOrNotFinalized(11)") - await assert.reverts(withdrawalQueue.findCheckpointHintUnbounded(11), "RequestNotFoundOrNotFinalized(11)") + await assert.reverts(withdrawalQueue.findCheckpointHints([11], 1, 10), "RequestNotFoundOrNotFinalized(11)") + await assert.reverts(withdrawalQueue.findCheckpointHintsUnbounded([11]), "RequestNotFoundOrNotFinalized(11)") }) it('reverts if there is no such a request', async () => { - await assert.reverts(withdrawalQueue.findCheckpointHint(12, 1, 10), "RequestNotFoundOrNotFinalized(12)") - await assert.reverts(withdrawalQueue.findCheckpointHintUnbounded(12), "RequestNotFoundOrNotFinalized(12)") + await assert.reverts(withdrawalQueue.findCheckpointHints([12], 1, 10), "RequestNotFoundOrNotFinalized(12)") + await assert.reverts(withdrawalQueue.findCheckpointHintsUnbounded([12]), "RequestNotFoundOrNotFinalized(12)") }) it('range search (found)', async () => { - assert.equals(await withdrawalQueue.findCheckpointHint(5, 1, 9), 5) - assert.equals(await withdrawalQueue.findCheckpointHint(1, 1, 9), 1) - assert.equals(await withdrawalQueue.findCheckpointHint(9, 1, 9), 9) - assert.equals(await withdrawalQueue.findCheckpointHint(5, 5, 5), 5) + assert.equals(await withdrawalQueue.findCheckpointHints([5], 1, 9), 5) + assert.equals(await withdrawalQueue.findCheckpointHints([1], 1, 9), 1) + assert.equals(await withdrawalQueue.findCheckpointHints([9], 1, 9), 9) + assert.equals(await withdrawalQueue.findCheckpointHints([5], 5, 5), 5) }) it('range search (not found)', async () => { - assert.equals(await withdrawalQueue.findCheckpointHint(10, 1, 5), 0) - assert.equals(await withdrawalQueue.findCheckpointHint(6, 1, 5), 0) - assert.equals(await withdrawalQueue.findCheckpointHint(1, 5, 5), 0) - assert.equals(await withdrawalQueue.findCheckpointHint(4, 5, 9), 0) + assert.equals(await withdrawalQueue.findCheckpointHints([10], 1, 5), 0) + assert.equals(await withdrawalQueue.findCheckpointHints([6], 1, 5), 0) + assert.equals(await withdrawalQueue.findCheckpointHints([1], 5, 5), 0) + assert.equals(await withdrawalQueue.findCheckpointHints([4], 5, 9), 0) }) it('sequential search', async () => { @@ -561,7 +564,7 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { for (let i = 1; i <= lastIndex; i += searchLength) { let end = i + searchLength - 1 if (end > lastIndex) end = lastIndex - let foundIndex = await withdrawalQueue.findCheckpointHint(requestId, i, end) + let foundIndex = await withdrawalQueue.findCheckpointHints([requestId], i, end) if (foundIndex != 0) return foundIndex } } From 4472dfbb9bd67ada5c845ed8f91a0566372068b1 Mon Sep 17 00:00:00 2001 From: Evgeny Taktarov Date: Mon, 20 Feb 2023 19:58:38 +0700 Subject: [PATCH 157/199] fix: snapshot variable not defined --- test/0.8.9/oracle/hash-consensus-access-control.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/0.8.9/oracle/hash-consensus-access-control.test.js b/test/0.8.9/oracle/hash-consensus-access-control.test.js index 1da7ceb2d..bad3de0de 100644 --- a/test/0.8.9/oracle/hash-consensus-access-control.test.js +++ b/test/0.8.9/oracle/hash-consensus-access-control.test.js @@ -11,6 +11,7 @@ const MockReportProcessor = artifacts.require('MockReportProcessor') contract('HashConsensus', ([admin, account1, account2, member1, member2]) => { let consensus = null let reportProcessor = null + let snapshot = null const manageMembersAndQuorumRoleKeccak156 = web3.utils.keccak256('MANAGE_MEMBERS_AND_QUORUM_ROLE') const disableConsensusRoleKeccak156 = web3.utils.keccak256('DISABLE_CONSENSUS_ROLE') const manageFrameConfigRoleKeccak156 = web3.utils.keccak256('MANAGE_FRAME_CONFIG_ROLE') From 79abc23d970ee7ec88bc86bd32ae86220c655b50 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Mon, 20 Feb 2023 17:57:12 +0300 Subject: [PATCH 158/199] test: fix eip712 deploy factory --- test/helpers/factories.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/helpers/factories.js b/test/helpers/factories.js index 6b7760a2f..7842dbe8a 100644 --- a/test/helpers/factories.js +++ b/test/helpers/factories.js @@ -281,8 +281,8 @@ async function withdrawalVaultFactory({ pool, treasury }) { return await WithdrawalVault.new(pool.address, treasury.address) } -async function eip712StETHFactory({ appManager }) { - return await EIP712StETH.new({ from: appManager.address }) +async function eip712StETHFactory({ pool, appManager }) { + return await EIP712StETH.new(pool.address, { from: appManager.address }) } async function stakingModulesFactory(_) { From 9663a94cfa19e791c91e3cae58abca1f074777a4 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Mon, 20 Feb 2023 18:19:36 +0300 Subject: [PATCH 159/199] refactor: IEIP712 -> IEIP712StETH --- contracts/0.4.24/StETHPermit.sol | 6 +++--- contracts/0.8.9/EIP712StETH.sol | 4 ++-- .../common/interfaces/{IEIP712.sol => IEIP712StETH.sol} | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) rename contracts/common/interfaces/{IEIP712.sol => IEIP712StETH.sol} (93%) diff --git a/contracts/0.4.24/StETHPermit.sol b/contracts/0.4.24/StETHPermit.sol index fe05c818c..88f19032b 100644 --- a/contracts/0.4.24/StETHPermit.sol +++ b/contracts/0.4.24/StETHPermit.sol @@ -7,7 +7,7 @@ pragma solidity 0.4.24; import {UnstructuredStorage} from "@aragon/os/contracts/common/UnstructuredStorage.sol"; import {ECDSA} from "../common/lib/ECDSA.sol"; -import {IEIP712} from "../common/interfaces/IEIP712.sol"; +import {IEIP712StETH} from "../common/interfaces/IEIP712StETH.sol"; import {StETH} from "./StETH.sol"; @@ -100,7 +100,7 @@ contract StETHPermit is IERC2612, StETH { abi.encode(PERMIT_TYPEHASH, _owner, _spender, _value, _useNonce(_owner), _deadline) ); - bytes32 hash = IEIP712(getEIP712StETH()).hashTypedDataV4(address(this), structHash); + bytes32 hash = IEIP712StETH(getEIP712StETH()).hashTypedDataV4(address(this), structHash); address signer = ECDSA.recover(hash, _v, _r, _s); require(signer == _owner, "ERC20Permit: invalid signature"); @@ -124,7 +124,7 @@ contract StETHPermit is IERC2612, StETH { */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32) { - return IEIP712(getEIP712StETH()).domainSeparatorV4(address(this)); + return IEIP712StETH(getEIP712StETH()).domainSeparatorV4(address(this)); } /** diff --git a/contracts/0.8.9/EIP712StETH.sol b/contracts/0.8.9/EIP712StETH.sol index f761047a2..f6e50b344 100644 --- a/contracts/0.8.9/EIP712StETH.sol +++ b/contracts/0.8.9/EIP712StETH.sol @@ -6,7 +6,7 @@ pragma solidity 0.8.9; import {ECDSA} from "@openzeppelin/contracts-v4.4/utils/cryptography/ECDSA.sol"; -import {IEIP712} from "../common/interfaces/IEIP712.sol"; +import {IEIP712StETH} from "../common/interfaces/IEIP712StETH.sol"; /** * NOTE: The code below is taken from "@openzeppelin/contracts-v4.4/utils/cryptography/draft-EIP712.sol" @@ -31,7 +31,7 @@ import {IEIP712} from "../common/interfaces/IEIP712.sol"; * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * */ -contract EIP712StETH is IEIP712 { +contract EIP712StETH is IEIP712StETH { /* solhint-disable var-name-mixedcase */ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. diff --git a/contracts/common/interfaces/IEIP712.sol b/contracts/common/interfaces/IEIP712StETH.sol similarity index 93% rename from contracts/common/interfaces/IEIP712.sol rename to contracts/common/interfaces/IEIP712StETH.sol index 1636432bc..7368e8222 100644 --- a/contracts/common/interfaces/IEIP712.sol +++ b/contracts/common/interfaces/IEIP712StETH.sol @@ -6,12 +6,12 @@ pragma solidity >=0.4.24 <0.9.0; /** - * @dev Helper interface of EIP712. + * @dev Helper interface of EIP712 StETH-dedicated helper. * * Has an access to the CHAIN_ID opcode and relies on immutables internally * Both are unavailable for Solidity 0.4.24. */ -interface IEIP712 { +interface IEIP712StETH { /** * @dev Returns the domain separator for the current chain. */ From 1a361d11b0be778596a92a242cb688466718b3f3 Mon Sep 17 00:00:00 2001 From: Alexandr Tarelkin Date: Mon, 20 Feb 2023 19:00:21 +0300 Subject: [PATCH 160/199] fix rewards distribution tests --- test/0.4.24/lido-handle-oracle-report.test.js | 13 +- test/helpers/factories.js | 3 + test/helpers/utils.js | 15 +- .../lido_rewards_distribution_math.js | 308 +++++++++++------- 4 files changed, 214 insertions(+), 125 deletions(-) diff --git a/test/0.4.24/lido-handle-oracle-report.test.js b/test/0.4.24/lido-handle-oracle-report.test.js index c23ddb927..602e4341a 100644 --- a/test/0.4.24/lido-handle-oracle-report.test.js +++ b/test/0.4.24/lido-handle-oracle-report.test.js @@ -1,6 +1,6 @@ const hre = require('hardhat') const { assert } = require('../helpers/assert') -const { ETH, toBN, genKeys, setBalance, StETH } = require('../helpers/utils') +const { ETH, toBN, genKeys, setBalance, StETH, calcSharesMintedAsFees } = require('../helpers/utils') const { deployProtocol } = require('../helpers/protocol') const { EvmSnapshot } = require('../helpers/blockchain') const { ZERO_ADDRESS, INITIAL_HOLDER } = require('../helpers/constants') @@ -83,17 +83,6 @@ const checkEvents = async ({ ) } -const calcSharesMintedAsFees = (rewards, fee, feePoints, prevTotalShares, newTotalEther) => { - return toBN(rewards) - .mul(toBN(fee)) - .mul(toBN(prevTotalShares)) - .div( - toBN(newTotalEther) - .mul(toBN(feePoints)) - .sub(toBN(rewards).mul(toBN(fee))) - ) -} - contract('Lido: handleOracleReport', ([appManager, , , , , , , stranger, anotherStranger, depositor, operator]) => { let deployed, snapshot, lido, treasury, voting, oracle let curatedModule, oracleReportSanityChecker, elRewardsVault diff --git a/test/helpers/factories.js b/test/helpers/factories.js index 7842dbe8a..8dad00bf4 100644 --- a/test/helpers/factories.js +++ b/test/helpers/factories.js @@ -221,6 +221,9 @@ async function stakingRouterFactory({ depositContract, dao, appManager, voting, await stakingRouter.grantRole(await stakingRouter.REPORT_EXITED_VALIDATORS_ROLE(), pool.address, { from: appManager.address }) + await stakingRouter.grantRole(await stakingRouter.REPORT_EXITED_VALIDATORS_ROLE(), voting.address, { + from: appManager.address + }) await stakingRouter.grantRole(await stakingRouter.UNSAFE_SET_EXITED_VALIDATORS_ROLE(), voting.address, { from: appManager.address }) diff --git a/test/helpers/utils.js b/test/helpers/utils.js index bdaa8e559..01f0bb3f7 100644 --- a/test/helpers/utils.js +++ b/test/helpers/utils.js @@ -154,6 +154,18 @@ const prepIdsCountsPayload = (ids, counts) => { } } +const calcSharesMintedAsFees = (rewards, fee, feePoints, prevTotalShares, newTotalEther) => { + return toBN(rewards) + .mul(toBN(fee)) + .mul(toBN(prevTotalShares)) + .div( + toBN(newTotalEther) + .mul(toBN(feePoints)) + .sub(toBN(rewards).mul(toBN(fee))) + ) +} + + module.exports = { ZERO_HASH, pad, @@ -188,5 +200,6 @@ module.exports = { toNum, toStr, setBalance, - prepIdsCountsPayload + prepIdsCountsPayload, + calcSharesMintedAsFees } diff --git a/test/scenario/lido_rewards_distribution_math.js b/test/scenario/lido_rewards_distribution_math.js index c226b8ede..6ba20bcc5 100644 --- a/test/scenario/lido_rewards_distribution_math.js +++ b/test/scenario/lido_rewards_distribution_math.js @@ -3,7 +3,7 @@ const { assertBn, assertEvent } = require('@aragon/contract-helpers-test/src/ass const { ZERO_ADDRESS } = require('@aragon/contract-helpers-test') const { waitBlocks } = require('../helpers/blockchain') -const { pad, ETH, hexConcat } = require('../helpers/utils') +const { pad, ETH, hexConcat, toBN, calcSharesMintedAsFees } = require('../helpers/utils') const { deployProtocol } = require('../helpers/protocol') const { setupNodeOperatorsRegistry } = require('../helpers/staking-modules') const { assert } = require('../helpers/assert') @@ -12,6 +12,10 @@ const { pushOracleReport } = require('../helpers/oracle') const { SECONDS_PER_FRAME } = require('../helpers/constants') const { oracleReportSanityCheckerStubFactory } = require('../helpers/factories') +const Lido = artifacts.require('Lido') + +const initialHolderBalanceETH = 1 + const tenKBN = new BN(10000) // Fee and its distribution are in basis points, 10000 corresponding to 100% @@ -28,17 +32,7 @@ const StakingModuleStatus = { } contract('Lido: rewards distribution math', (addresses) => { - const [ - // the address which we use to simulate the voting DAO application - // node operators - operator_1, - operator_2, - // users who deposit Ether to the pool - user1, - user2, - // unrelated address - nobody - ] = addresses + const [, , , , , , , , , , , , , operator_1, operator_2, user1, user2, nobody] = addresses let pool, nodeOperatorsRegistry, token let stakingRouter @@ -167,6 +161,7 @@ contract('Lido: rewards distribution math', (addresses) => { it(`registers submit correctly`, async () => { const depositedEthValue = 34 const depositAmount = ETH(depositedEthValue) + const expectedTotalEther = ETH(depositedEthValue + initialHolderBalanceETH) const receipt = await pool.submit(ZERO_ADDRESS, { value: depositAmount, from: user1 }) @@ -176,19 +171,20 @@ contract('Lido: rewards distribution math', (addresses) => { assertBn(ether2Stat.depositedValidators, 0, 'one validator have received the ether2') assertBn(ether2Stat.beaconBalance, 0, `no remote ether2 on validator's balance is reported yet`) - assertBn(await pool.getBufferedEther(), ETH(depositedEthValue), `all the ether is buffered until deposit`) - assertBn(await pool.getTotalPooledEther(), depositAmount, 'total pooled ether') + assertBn(await pool.getBufferedEther(), expectedTotalEther, `all the ether is buffered until deposit`) + assertBn(await pool.getTotalPooledEther(), expectedTotalEther, 'total pooled ether') // The amount of tokens corresponding to the deposited ETH value was minted to the user assertBn(await token.balanceOf(user1), depositAmount, 'user1 tokens') - assertBn(await token.totalSupply(), depositAmount, 'token total supply') + assertBn(await token.totalSupply(), expectedTotalEther, 'token total supply') // Total shares are equal to deposited eth before ratio change and fee mint - assertBn(await token.getTotalShares(), depositAmount, 'total shares') + assertBn(await token.getTotalShares(), expectedTotalEther, 'total shares') assertBn(await token.balanceOf(treasuryAddr), new BN(0), 'treasury balance is zero') assertBn(await token.balanceOf(nodeOperator1.address), new BN(0), 'nodeOperator1 balance is zero') + }) it(`the first deposit gets deployed`, async () => { @@ -219,7 +215,6 @@ contract('Lido: rewards distribution math', (addresses) => { '0x', signatures ) - assertBn( await nodeOperatorsRegistry.getUnusedSigningKeyCount(0), 0, @@ -231,7 +226,7 @@ contract('Lido: rewards distribution math', (addresses) => { 'user1 balance is equal first reported value + their buffered deposit value' ) assertBn(await token.sharesOf(user1), ETH(34), 'user1 shares are equal to the first deposit') - assertBn(await token.totalSupply(), ETH(34), 'token total supply') + assertBn(await token.totalSupply(), ETH(34 + initialHolderBalanceETH), 'token total supply') assertBn(await token.balanceOf(treasuryAddr), ETH(0), 'treasury balance equals buffered value') assertBn(await token.balanceOf(nodeOperator1.address), new BN(0), 'nodeOperator1 balance is zero') @@ -252,63 +247,104 @@ contract('Lido: rewards distribution math', (addresses) => { const receipt = await reportBeacon(1, reportingValue) - const treasuryTokenDelta = (await pool.balanceOf(treasuryAddr)) - treasuryBalanceBefore - const treasurySharesDelta = (await pool.sharesOf(treasuryAddr)) - treasurySharesBefore - const nodeOperatorsRegistryTokenDelta = - (await pool.balanceOf(nodeOperatorsRegistry.address)) - nodeOperatorsRegistryBalanceBefore - const nodeOperatorsRegistrySharesDelta = - (await pool.sharesOf(nodeOperatorsRegistry.address)) - nodeOperatorsRegistrySharesBefore + const sharesMintedAsFees = calcSharesMintedAsFees( + profitAmount, + 1000, + 10000, + prevTotalShares, + await pool.getTotalPooledEther() + ) - const awaitedDeltas = await getAwaitedFeesSharesTokensDeltas(profitAmount, prevTotalShares, 1) - const { - totalFeeToDistribute, - nodeOperatorsSharesToMint, - treasurySharesToMint, - nodeOperatorsFeeToMint, - treasuryFeeToMint - } = awaitedDeltas + const totalFeeToDistribute = await pool.getPooledEthByShares(sharesMintedAsFees) + const nodeOperatorsSharesToMint = sharesMintedAsFees.div(toBN(2)) + const treasurySharesToMint = sharesMintedAsFees.sub(nodeOperatorsSharesToMint) + const nodeOperatorsFeeToMint = await pool.getPooledEthByShares(nodeOperatorsSharesToMint) + const treasuryFeeMint = await pool.getPooledEthByShares(treasurySharesToMint) - assert.equals(nodeOperatorsRegistrySharesDelta, nodeOperatorsSharesToMint, 'nodeOperator1 shares are correct') - assert.equals(treasurySharesDelta, treasurySharesToMint, 'treasury shares are correct') - assert.equalsDelta(nodeOperatorsFeeToMint, treasuryTokenDelta, 1, 'reported the expected total fee') - assert.equalsDelta(nodeOperatorsRegistryTokenDelta, nodeOperatorsFeeToMint, 1, 'treasury shares are correct') + assert.equals( + await pool.sharesOf(nodeOperatorsRegistry.address), + nodeOperatorsRegistrySharesBefore.add(nodeOperatorsSharesToMint), + 'nodeOperator1 shares are correct' + ) + assert.equals( + await pool.sharesOf(treasuryAddr), + treasurySharesBefore.add(treasurySharesToMint), + 'treasury shares are correct' + ) + assert.equalsDelta( + await pool.balanceOf(treasuryAddr), + treasuryBalanceBefore.add(treasuryFeeMint), + 1, + 'reported the expected total fee' + ) + assert.equalsDelta( + await pool.balanceOf(nodeOperatorsRegistry.address), + nodeOperatorsRegistryBalanceBefore.add(nodeOperatorsFeeToMint), + 1, + 'reported the expected total fee' + ) - assert.emits(receipt, 'Transfer', { - to: nodeOperatorsRegistry.address, - value: nodeOperatorsFeeToMint - }) - assert.emits(receipt, 'Transfer', { - to: treasuryAddr, - value: nodeOperatorsFeeToMint - }) - assert.emits(receipt, 'TransferShares', { - to: nodeOperatorsRegistry.address, - sharesValue: nodeOperatorsSharesToMint - }) - assert.emits(receipt, 'TransferShares', { - to: treasuryAddr, - sharesValue: treasurySharesToMint - }) + assert.emits( + receipt, + 'Transfer', + { + to: nodeOperatorsRegistry.address, + value: nodeOperatorsFeeToMint + }, + { abi: Lido.abi } + ) + assert.emits( + receipt, + 'Transfer', + { + to: treasuryAddr, + value: treasuryFeeMint + }, + { abi: Lido.abi } + ) + assert.emits( + receipt, + 'TransferShares', + { + to: nodeOperatorsRegistry.address, + sharesValue: nodeOperatorsSharesToMint + }, + { abi: Lido.abi } + ) + assert.emits( + receipt, + 'TransferShares', + { + to: treasuryAddr, + sharesValue: treasurySharesToMint + }, + { abi: Lido.abi } + ) - assertBn( + assert.equalsDelta( await token.balanceOf(user1), - // 32 staked 2 buffered 1 profit - new BN(ETH(32 + 2 + 1)).sub(totalFeeToDistribute), + '34874285714285714286', + 1, 'user1 balance is equal first reported value + their buffered deposit value' ) assertBn(await token.sharesOf(user1), ETH(34), 'user1 shares are equal to the first deposit') - assertBn(await token.totalSupply(), ETH(35), 'token total supply') - assertBn(await token.balanceOf(treasuryAddr), treasuryFeeToMint, 'treasury balance = fee') - assertBn(treasuryTokenDelta, treasuryFeeToMint, 'treasury balance = fee') + assertBn(await token.totalSupply(), ETH(36), 'token total supply') + assert.equals(await pool.getTotalShares(), prevTotalShares.add(sharesMintedAsFees)) - // kicks rewards distribution - await nodeOperatorsRegistry.finishUpdatingExitedValidatorsKeysCount({ from: voting }) - assertBn(await token.balanceOf(nodeOperator1.address), nodeOperatorsFeeToMint, 'nodeOperator1 balance = fee') + // TODO: check math after rewards distribution fixes + await stakingRouter.reportStakingModuleExitedValidatorsCountByNodeOperator(1, [], [], { from: voting }) + + assert.equalsDelta( + await token.balanceOf(nodeOperator1.address), + nodeOperatorsFeeToMint, + 1, + 'nodeOperator1 balance = fee' + ) const nodeOperator1TokenDelta = (await token.balanceOf(operator_1)) - nodeOperator1TokenBefore - // TODO merge: 1 wei - // assertBn(nodeOperator1TokenDelta, nodeOperatorsFeeToMint, 'nodeOperator1 balance = fee') + + assert.equalsDelta(nodeOperator1TokenDelta, nodeOperatorsFeeToMint, 1, 'nodeOperator1 balance = fee') }) it(`adds another node operator`, async () => { @@ -355,13 +391,17 @@ contract('Lido: rewards distribution math', (addresses) => { assertEvent(receipt, 'Transfer', { expectedArgs: { from: 0, to: user2, value: awaitedTokens } }) // 2 from the previous deposit of the first user - assertBn(await pool.getBufferedEther(), ETH(depositedEthValue + 2), `all the ether is buffered until deposit`) + assertBn( + await pool.getBufferedEther(), + ETH(depositedEthValue + 2 + initialHolderBalanceETH), + `all the ether is buffered until deposit` + ) // The amount of tokens corresponding to the deposited ETH value was minted to the user assertBn(await token.balanceOf(user2), awaitedTokens, 'user2 tokens') // current deposit + firstDeposit + first profit - assertBn(await token.totalSupply(), ETH(depositedEthValue + 34 + 1), 'token total supply') + assertBn(await token.totalSupply(), ETH(depositedEthValue + 34 + 1 + initialHolderBalanceETH), 'token total supply') // Total shares are equal to deposited eth before ratio change and fee mint assertBn(await token.getTotalShares(), sharesBefore.add(awaitedShares), 'total shares') }) @@ -448,64 +488,108 @@ contract('Lido: rewards distribution math', (addresses) => { const profitAmountEth = 2 const profitAmount = ETH(profitAmountEth) const bufferedAmount = ETH(2) - // first deposit + first profit + second deposit - // note no buffered eth values - const reportingValue = ETH(32 + 1 + 32 + profitAmountEth) + + const reportingValue = ETH(65 + profitAmountEth) const prevTotalShares = await pool.getTotalShares() - const treasuryBalanceBefore = await pool.balanceOf(treasuryAddr) - const nodeOperatorsRegistryBalanceBefore = await pool.balanceOf(nodeOperatorsRegistry.address) const treasurySharesBefore = await pool.sharesOf(treasuryAddr) const nodeOperatorsRegistrySharesBefore = await pool.sharesOf(nodeOperatorsRegistry.address) + const nodeOperator1SharesBefore = await pool.sharesOf(nodeOperator1.address) + const nodeOperator2SharesBefore = await pool.sharesOf(nodeOperator2.address) + const receipt = await reportBeacon(2, reportingValue) - const treasuryTokenDelta = (await pool.balanceOf(treasuryAddr)) - treasuryBalanceBefore - const treasurySharesDelta = (await pool.sharesOf(treasuryAddr)) - treasurySharesBefore - const nodeOperatorsRegistryTokenDelta = - (await pool.balanceOf(nodeOperatorsRegistry.address)) - nodeOperatorsRegistryBalanceBefore - const nodeOperatorsRegistrySharesDelta = - (await pool.sharesOf(nodeOperatorsRegistry.address)) - nodeOperatorsRegistrySharesBefore - - const awaitedDeltas = await getAwaitedFeesSharesTokensDeltas(profitAmount, prevTotalShares, 2) - const { - totalFeeToDistribute, - nodeOperatorsSharesToMint, - treasurySharesToMint, - nodeOperatorsFeeToMint, - treasuryFeeToMint - } = awaitedDeltas - assert.equals(nodeOperatorsRegistrySharesDelta, nodeOperatorsSharesToMint, 'nodeOperator1 shares are correct') - assert.equals(treasurySharesDelta, treasurySharesToMint, 'treasury shares are correct') - assert.equalsDelta(nodeOperatorsFeeToMint, treasuryTokenDelta, 1, 'reported the expected total fee') - assert.equalsDelta(nodeOperatorsRegistryTokenDelta, nodeOperatorsFeeToMint, 1, 'treasury shares are correct') + const sharesMintedAsFees = calcSharesMintedAsFees( + profitAmount, + 1000, + 10000, + prevTotalShares, + await pool.getTotalPooledEther() + ) + const totalFeeToDistribute = await pool.getPooledEthByShares(sharesMintedAsFees) + const nodeOperatorsSharesToMint = sharesMintedAsFees.div(toBN(2)) + const treasurySharesToMint = sharesMintedAsFees.sub(nodeOperatorsSharesToMint) + const nodeOperatorsFeeToMint = await pool.getPooledEthByShares(nodeOperatorsSharesToMint) + const treasuryFeeMint = await pool.getPooledEthByShares(treasurySharesToMint) + + assert.equals( + await pool.sharesOf(nodeOperatorsRegistry.address), + nodeOperatorsRegistrySharesBefore.add(nodeOperatorsSharesToMint), + 'nodeOperatorRegistry shares are correct' + ) + assert.equals( + await pool.sharesOf(treasuryAddr), + treasurySharesBefore.add(treasurySharesToMint), + 'treasury shares are correct' + ) + assert.equalsDelta( + await pool.balanceOf(treasuryAddr), + await pool.getPooledEthByShares(treasurySharesBefore.add(treasurySharesToMint)), + 1, + 'treasury fee' + ) + assert.equalsDelta( + await pool.balanceOf(nodeOperatorsRegistry.address), + await pool.getPooledEthByShares(nodeOperatorsRegistrySharesBefore.add(nodeOperatorsSharesToMint)), + 1, + 'nodeOperatorRegistry fee' + ) - assert.emits(receipt, 'Transfer', { - to: nodeOperatorsRegistry.address, - value: nodeOperatorsFeeToMint - }) - assert.emits(receipt, 'Transfer', { - to: treasuryAddr, - value: nodeOperatorsFeeToMint - }) - assert.emits(receipt, 'TransferShares', { - to: nodeOperatorsRegistry.address, - sharesValue: nodeOperatorsSharesToMint - }) - assert.emits(receipt, 'TransferShares', { - to: treasuryAddr, - sharesValue: treasurySharesToMint - }) + assert.emits( + receipt, + 'Transfer', + { + to: nodeOperatorsRegistry.address, + value: nodeOperatorsFeeToMint + }, + { abi: Lido.abi } + ) + assert.emits( + receipt, + 'Transfer', + { + to: treasuryAddr, + value: treasuryFeeMint + }, + { abi: Lido.abi } + ) + assert.emits( + receipt, + 'TransferShares', + { + to: nodeOperatorsRegistry.address, + sharesValue: nodeOperatorsSharesToMint + }, + { abi: Lido.abi } + ) + assert.emits( + receipt, + 'TransferShares', + { + to: treasuryAddr, + sharesValue: treasurySharesToMint + }, + { abi: Lido.abi } + ) + + assert.equalsDelta( + await token.balanceOf(user1), + '35797428571428571429', + 1, + 'user1 balance is equal first reported value + their buffered deposit value' + ) + assertBn(await token.sharesOf(user1), ETH(34), 'user1 shares are equal to the first deposit') - // TODO merge: 1 wei - // assertBn(await token.balanceOf(nodeOperatorsRegistry.address), nodeOperatorsFeeToMint, 'nodeOperatorsRegistry balance = fee') - const nodeOperator1SharesBefore = await token.sharesOf(nodeOperator1.address) - const nodeOperator2SharesBefore = await token.sharesOf(nodeOperator2.address) - // kicks rewards distribution - await nodeOperatorsRegistry.finishUpdatingExitedValidatorsKeysCount({ from: voting }) + assertBn(await token.totalSupply(), ETH(70), 'token total supply') + assert.equals(await pool.getTotalShares(), prevTotalShares.add(sharesMintedAsFees)) + + // TODO: check math after rewards distribution fixes + await stakingRouter.reportStakingModuleExitedValidatorsCountByNodeOperator(1, [], [], { from: voting }) const nodeOperator1SharesDelta = (await token.sharesOf(nodeOperator1.address)).sub(nodeOperator1SharesBefore) const nodeOperator2SharesDelta = (await token.sharesOf(nodeOperator2.address)).sub(nodeOperator2SharesBefore) + assertBn( nodeOperator2SharesDelta, await pool.sharesOf(nodeOperator2.address), @@ -653,7 +737,7 @@ contract('Lido: rewards distribution math', (addresses) => { ) assertBn(await token.sharesOf(user1), user1SharesBefore, 'user1 shares are equal to the first deposit') assertBn(await token.totalSupply(), totalSupplyBefore, 'token total supply') - assertBn(await token.getBufferedEther(), ETH(2), '') + assertBn(await token.getBufferedEther(), ETH(3), '') }) it(`rewards distribution`, async () => { From 991ab15ffe17760995455df8a33c109867660626 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Mon, 20 Feb 2023 18:04:05 +0100 Subject: [PATCH 161/199] refactor: sig keys lib --- contracts/0.4.24/lib/SigningKeys.sol | 290 ++++++++++++------ .../0.4.24/nos/NodeOperatorsRegistry.sol | 54 ++-- .../0.4.24/test_helpers/SiginigKyesMock.sol | 60 ++++ test/0.4.24/node-operators-registry.test.js | 20 +- test/0.4.24/signingkey-lib.test.js | 255 +++++++++++++++ test/helpers/signing-keys.js | 8 +- 6 files changed, 562 insertions(+), 125 deletions(-) create mode 100644 contracts/0.4.24/test_helpers/SiginigKyesMock.sol create mode 100644 test/0.4.24/signingkey-lib.test.js diff --git a/contracts/0.4.24/lib/SigningKeys.sol b/contracts/0.4.24/lib/SigningKeys.sol index b27d3a416..793f68f89 100644 --- a/contracts/0.4.24/lib/SigningKeys.sol +++ b/contracts/0.4.24/lib/SigningKeys.sol @@ -6,7 +6,9 @@ pragma solidity 0.4.24; import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol"; import {SafeMath64} from "@aragon/os/contracts/lib/math/SafeMath64.sol"; -import {MemUtils} from "../../common/lib/MemUtils.sol"; +// import {MemUtils} from "../../common/lib/MemUtils.sol"; + +import "hardhat/console.sol"; library SigningKeys { using SafeMath for uint256; @@ -34,137 +36,237 @@ library SigningKeys { return 0 == k1 && 0 == (k2 >> ((2 * 32 - PUBKEY_LENGTH) * 8)); } - function getKeyOffset(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) - internal - pure - returns (uint256) - { + function getKeyOffset(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal pure returns (uint256) { return uint256(keccak256(abi.encodePacked(_position, _nodeOperatorId, _keyIndex))); } - function addKeysSigs( + function saveKeysSigs( bytes32 _position, uint256 _nodeOperatorId, - uint256 _keysCount, uint256 _startIndex, + uint256 _keysCount, bytes _publicKeys, bytes _signatures ) internal returns (uint256) { - require(_keysCount != 0, "NO_KEYS"); - require(_keysCount <= UINT64_MAX, "KEYS_COUNT_TOO_LARGE"); - require(_publicKeys.length == _keysCount.mul(PUBKEY_LENGTH), "INVALID_LENGTH"); - require(_signatures.length == _keysCount.mul(SIGNATURE_LENGTH), "INVALID_LENGTH"); - - (bytes memory key, bytes memory sig) = initKeySig(1); - for (uint256 i = 0; i < _keysCount; ++i) { - MemUtils.copyBytes(_publicKeys, key, i * PUBKEY_LENGTH, 0, PUBKEY_LENGTH); - require(!isKeyEmpty(key), "EMPTY_KEY"); - MemUtils.copyBytes(_signatures, sig, i * SIGNATURE_LENGTH, 0, SIGNATURE_LENGTH); - - _position.storeKeySig(_nodeOperatorId, _startIndex, key, sig); - _startIndex = _startIndex.add(1); - emit SigningKeyAdded(_nodeOperatorId, key); - } - return _startIndex; - } + require(_keysCount > 0 && _startIndex.add(_keysCount - 1) <= UINT64_MAX, "INVALID_KEYS_COUNT"); + require( + _publicKeys.length == _keysCount.mul(PUBKEY_LENGTH) && _signatures.length == _keysCount.mul(SIGNATURE_LENGTH), + "LENGTH_MISMATCH" + ); - function removeUnusedKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _index, uint256 _lastIndex) - internal - returns (uint256) - { - (bytes memory removedKey,) = _position.loadKeySig(_nodeOperatorId, _index); + uint256 curOffset; + bool isEmpty; + bytes memory tmpKey = new bytes(48); - if (_index < _lastIndex) { - (bytes memory key, bytes memory signature) = _position.loadKeySig(_nodeOperatorId, _lastIndex); - _position.storeKeySig(_nodeOperatorId, _index, key, signature); - } + for (uint256 i; i < _keysCount;) { + curOffset = _position.getKeyOffset(_nodeOperatorId, _startIndex); + assembly { + let _ofs := add(add(_publicKeys, 0x20), mul(i, 48)) //PUBKEY_LENGTH = 48 + let _part1 := mload(_ofs) // bytes 0..31 + let _part2 := mload(add(_ofs, 0x10)) // bytes 16..47 + isEmpty := iszero(or(_part1, _part2)) - _position.deleteKeySig(_nodeOperatorId, _lastIndex); - emit SigningKeyRemoved(_nodeOperatorId, removedKey); + /// @dev custom revert error + // if iszero(or(_part1, _part2)) { + // let ptrError := mload(0x40) + // mstore(ptrError, shl(224, 0x08c379a0)) // selector of `Error(string)` + // mstore(add(ptrError, 4), 0x20) // offset of the abi.encoded `string` + // mstore(add(ptrError, 0x24), 9) // error text length + // mstore(add(ptrError, 0x44), "EMPTY_KEY") // error text 0x454d5054595f4b4559 + // revert(ptrError, 0x64) // revert data length is 4 bytes for selector and 3 slots of 0x20 bytes + // } + mstore(add(tmpKey, 0x30), _part2) // store 2nd part first + mstore(add(tmpKey, 0x20), _part1) // store 1st part with overwrite bytes 16-31 + } - return _lastIndex; + require(!isEmpty, "EMPTY_KEY"); + assembly { + // store key + sstore(curOffset, mload(add(tmpKey, 0x20))) // store bytes 0..31 + sstore(add(curOffset, 1), shl(128, mload(add(tmpKey, 0x30)))) // store bytes 32..47 + // store signature + let _ofs := add(add(_signatures, 0x20), mul(i, 96)) //SIGNATURE_LENGTH = 96 + sstore(add(curOffset, 2), mload(_ofs)) + sstore(add(curOffset, 3), mload(add(_ofs, 0x20))) + sstore(add(curOffset, 4), mload(add(_ofs, 0x40))) + i := add(i, 1) + _startIndex := add(_startIndex, 1) + } + emit SigningKeyAdded(_nodeOperatorId, tmpKey); + } + return _startIndex; } - function storeKeySig( + function removeKeysSigs( bytes32 _position, uint256 _nodeOperatorId, - uint256 _keyIndex, - bytes memory _pubkey, - bytes memory _signature + uint256 _startIndex, + uint256 _keysCount, + uint256 _totalKeysCount ) internal { - // assert(_pubkey.length == PUBKEY_LENGTH); - // assert(_signature.length == SIGNATURE_LENGTH); + require(_keysCount > 0 && _startIndex.add(_keysCount) <= _totalKeysCount && _totalKeysCount <= UINT64_MAX, "INVALID_KEYS_COUNT"); - // key - uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - uint256 keyExcessBits = (2 * 32 - PUBKEY_LENGTH) * 8; - assembly { - sstore(offset, mload(add(_pubkey, 0x20))) - sstore(add(offset, 1), shl(keyExcessBits, shr(keyExcessBits, mload(add(_pubkey, 0x40))))) - } - offset += 2; + uint256 curOffset; + uint256 lastOffset; + uint256 j; + bytes memory tmpKey = new bytes(48); + + console.log("_nodeOperatorId", _nodeOperatorId); + console.log("_startIndex", _startIndex); + console.log("_keysCount", _keysCount); + console.log("_totalKeysCount", _totalKeysCount); + + for (uint256 i = _startIndex + _keysCount; i > _startIndex;) { + curOffset = _position.getKeyOffset(_nodeOperatorId, i - 1); + console.log("curOffset", curOffset); - // signature - for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { assembly { - sstore(offset, mload(add(_signature, add(0x20, i)))) + // read key + mstore(add(tmpKey, 0x30), shr(128, sload(add(curOffset, 1)))) // bytes 16..47 + mstore(add(tmpKey, 0x20), sload(curOffset)) // bytes 0..31 + } + if (i < _totalKeysCount) { + lastOffset = _position.getKeyOffset(_nodeOperatorId, _totalKeysCount - 1); + assembly { + // read key + mstore(add(tmpKey, 0x30), shr(128, sload(add(lastOffset, 1)))) // bytes 16..47 + mstore(add(tmpKey, 0x20), sload(lastOffset)) // bytes 0..31 + } + for (j = 0; j < 5;) { + assembly { + sstore(add(curOffset, j), sload(add(lastOffset, j))) + j := add(j, 1) + } + } + curOffset = lastOffset; + } + for (j = 0; j < 5;) { + assembly { + sstore(add(curOffset, j), 0) + j := add(j, 1) + } } - offset++; - } - } - function deleteKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal { - uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - for (uint256 i = 0; i < (PUBKEY_LENGTH + SIGNATURE_LENGTH) / 32 + 1; ++i) { assembly { - sstore(add(offset, i), 0) + _totalKeysCount := sub(_totalKeysCount, 1) + i := sub(i, 1) } + emit SigningKeyRemoved(_nodeOperatorId, tmpKey); + console.logBytes(tmpKey); } } - function loadKeySigAndAppend( + // function removeUnusedKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _index, uint256 _lastIndex) + // internal + // returns (uint256) + // { + // (bytes memory removedKey,) = _position.loadKeySig(_nodeOperatorId, _index); + + // if (_index < _lastIndex) { + // (bytes memory key, bytes memory signature) = _position.loadKeySig(_nodeOperatorId, _lastIndex); + // _position.storeKeySig(_nodeOperatorId, _index, key, signature); + // } + + // _position.deleteKeySig(_nodeOperatorId, _lastIndex); + // emit SigningKeyRemoved(_nodeOperatorId, removedKey); + + // return _lastIndex; + // } + + // function storeKeySig( + // bytes32 _position, + // uint256 _nodeOperatorId, + // uint256 _keyIndex, + // bytes memory _pubkey, + // bytes memory _signature + // ) internal { + // // assert(_pubkey.length == PUBKEY_LENGTH); + // // assert(_signature.length == SIGNATURE_LENGTH); + + // // key + // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); + // uint256 keyExcessBits = (2 * 32 - PUBKEY_LENGTH) * 8; + // assembly { + // sstore(offset, mload(add(_pubkey, 0x20))) + // sstore(add(offset, 1), shl(keyExcessBits, shr(keyExcessBits, mload(add(_pubkey, 0x40))))) + // } + // offset += 2; + + // // signature + // for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { + // assembly { + // sstore(offset, mload(add(_signature, add(0x20, i)))) + // } + // offset++; + // } + // } + + // function deleteKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal { + // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); + // for (uint256 i = 0; i < (PUBKEY_LENGTH + SIGNATURE_LENGTH) / 32 + 1; ++i) { + // assembly { + // sstore(add(offset, i), 0) + // } + // } + // } + + function loadKeysSigs( bytes32 _position, uint256 _nodeOperatorId, - uint256 _keyIndex, - uint256 _offset, + uint256 _startIndex, + uint256 _keysCount, bytes memory _pubkeys, - bytes memory _signatures + bytes memory _signatures, + uint256 _bufOffset // key offset inside _pubkeys/_signatures buffers ) internal view { - (bytes memory pubkey, bytes memory signature) = _position.loadKeySig(_nodeOperatorId, _keyIndex); - MemUtils.copyBytes(pubkey, _pubkeys, _offset.mul(PUBKEY_LENGTH)); - MemUtils.copyBytes(signature, _signatures, _offset.mul(SIGNATURE_LENGTH)); - } - - function loadKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) - internal - view - returns (bytes memory pubkey, bytes memory signature) - { - uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - - // key - bytes memory tmpKey = MemUtils.unsafeAllocateBytes(64); - assembly { - mstore(add(tmpKey, 0x20), sload(offset)) - mstore(add(tmpKey, 0x40), sload(add(offset, 1))) - } - offset += 2; - pubkey = MemUtils.unsafeAllocateBytes(PUBKEY_LENGTH); - MemUtils.copyBytes(tmpKey, pubkey, 0, 0, PUBKEY_LENGTH); - // signature - signature = MemUtils.unsafeAllocateBytes(SIGNATURE_LENGTH); - for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { + uint256 curOffset; + for (uint256 i; i < _keysCount;) { + curOffset = _position.getKeyOffset(_nodeOperatorId, _startIndex + i); assembly { - mstore(add(signature, add(0x20, i)), sload(offset)) + // read key + let _ofs := add(add(_pubkeys, 0x20), mul(add(_bufOffset, i), 48)) //PUBKEY_LENGTH = 48 + mstore(add(_ofs, 0x10), shr(128, sload(add(curOffset, 1)))) // bytes 16..47 + mstore(_ofs, sload(curOffset)) // bytes 0..31 + // store signature + _ofs := add(add(_signatures, 0x20), mul(add(_bufOffset, i), 96)) //SIGNATURE_LENGTH = 96 + mstore(_ofs, sload(add(curOffset, 2))) + mstore(add(_ofs, 0x20), sload(add(curOffset, 3))) + mstore(add(_ofs, 0x40), sload(add(curOffset, 4))) + i := add(i, 1) } - offset++; } } - function initKeySig(uint256 _count) internal pure returns (bytes memory, bytes memory) { + // function loadKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) + // internal + // view + // returns (bytes memory pubkey, bytes memory signature) + // { + // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); + + // // key + // bytes memory tmpKey = MemUtils.unsafeAllocateBytes(64); + // assembly { + // mstore(add(tmpKey, 0x20), sload(offset)) + // mstore(add(tmpKey, 0x40), sload(add(offset, 1))) + // } + // offset += 2; + // pubkey = MemUtils.unsafeAllocateBytes(PUBKEY_LENGTH); + // MemUtils.copyBytes(tmpKey, pubkey, 0, 0, PUBKEY_LENGTH); + // // signature + // signature = MemUtils.unsafeAllocateBytes(SIGNATURE_LENGTH); + // for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { + // assembly { + // mstore(add(signature, add(0x20, i)), sload(offset)) + // } + // offset++; + // } + // } + + function initKeysSigsBuf(uint256 _count) internal pure returns (bytes memory, bytes memory) { return ( - MemUtils.unsafeAllocateBytes(_count.mul(PUBKEY_LENGTH)), - MemUtils.unsafeAllocateBytes(_count.mul(SIGNATURE_LENGTH)) + new bytes(_count.mul(PUBKEY_LENGTH)), new bytes(_count.mul(SIGNATURE_LENGTH)) + // MemUtils.unsafeAllocateBytes(_count.mul(PUBKEY_LENGTH)), MemUtils.unsafeAllocateBytes(_count.mul(SIGNATURE_LENGTH)) ); } } diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 741c33720..bcee74e87 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -795,12 +795,13 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256[] memory _nodeOperatorIds, uint256[] memory _activeKeyCountsAfterAllocation ) internal returns (bytes memory pubkeys, bytes memory signatures) { - (pubkeys, signatures) = SigningKeys.initKeySig(_keysCountToLoad); + (pubkeys, signatures) = SigningKeys.initKeysSigsBuf(_keysCountToLoad); uint256 loadedKeysCount = 0; uint64 depositedSigningKeysCountBefore; uint64 depositedSigningKeysCountAfter; - uint256 keyIndex; + // uint256 keyIndex; + uint256 keysCount; Packed64x4.Packed memory signingKeysStats; for (uint256 i; i < _nodeOperatorIds.length; ++i) { signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorIds[i]); @@ -808,14 +809,20 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { depositedSigningKeysCountAfter = signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET) + uint64(_activeKeyCountsAfterAllocation[i]); - if (depositedSigningKeysCountBefore == depositedSigningKeysCountAfter) continue; + keysCount = depositedSigningKeysCountAfter.sub(depositedSigningKeysCountBefore); + if (keysCount == 0) continue; - for (keyIndex = depositedSigningKeysCountBefore; keyIndex < depositedSigningKeysCountAfter; ++keyIndex) { - SIGNING_KEYS_MAPPING_NAME.loadKeySigAndAppend( - _nodeOperatorIds[i], keyIndex, loadedKeysCount, pubkeys, signatures - ); - ++loadedKeysCount; - } + SIGNING_KEYS_MAPPING_NAME.loadKeysSigs( + _nodeOperatorIds[i], depositedSigningKeysCountBefore, keysCount, pubkeys, signatures, loadedKeysCount + ); + loadedKeysCount += keysCount; + + // for (keyIndex = depositedSigningKeysCountBefore; keyIndex < depositedSigningKeysCountAfter; ++keyIndex) { + // SIGNING_KEYS_MAPPING_NAME.loadKeysSigs( + // _nodeOperatorIds[i], keyIndex, loadedKeysCount, pubkeys, signatures + // ); + // ++loadedKeysCount; + // } emit DepositedSigningKeysCountChanged(_nodeOperatorIds[i], depositedSigningKeysCountAfter); signingKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, depositedSigningKeysCountAfter); _saveOperatorSigningKeysStats(_nodeOperatorIds[i], signingKeysStats); @@ -946,10 +953,9 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _requireValidRange(totalSigningKeysCount.add(_keysCount) <= UINT64_MAX); - // - totalSigningKeysCount = - SIGNING_KEYS_MAPPING_NAME.addKeysSigs(_nodeOperatorId, _keysCount, totalSigningKeysCount, _publicKeys, _signatures); + SIGNING_KEYS_MAPPING_NAME.saveKeysSigs(_nodeOperatorId, totalSigningKeysCount, _keysCount, _publicKeys, _signatures); + totalSigningKeysCount += _keysCount; emit TotalSigningKeysCountChanged(_nodeOperatorId, totalSigningKeysCount); signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, uint64(totalSigningKeysCount)); @@ -1007,16 +1013,20 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); uint256 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); - uint256 _toIndex = _fromIndex.add(_keysCount); + // uint256 _toIndex = _fromIndex.add(_keysCount); // comapring _toIndex <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than MAX_UINT64 - _requireValidRange(_fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) && _toIndex <= totalSigningKeysCount); + _requireValidRange(_fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) && _fromIndex.add(_keysCount) <= totalSigningKeysCount); /// @todo: move to lib // removing from the last index to the highest one, so we won't get outside the array - for (uint256 i = _toIndex; i > _fromIndex; --i) { - totalSigningKeysCount = - SIGNING_KEYS_MAPPING_NAME.removeUnusedKeySig(_nodeOperatorId, i - 1, totalSigningKeysCount.sub(1)); - } + + SIGNING_KEYS_MAPPING_NAME.removeKeysSigs(_nodeOperatorId, _fromIndex, _keysCount, totalSigningKeysCount); + + // for (uint256 i = _toIndex; i > _fromIndex; --i) { + // totalSigningKeysCount = + // SIGNING_KEYS_MAPPING_NAME.removeUnusedKeySig(_nodeOperatorId, i - 1, totalSigningKeysCount.sub(1)); + // } + totalSigningKeysCount -= _keysCount; signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, uint64(totalSigningKeysCount)); emit TotalSigningKeysCountChanged(_nodeOperatorId, totalSigningKeysCount); @@ -1089,13 +1099,17 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _requireValidRange(_offset.add(_limit) <= signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET)); uint256 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); - (pubkeys, signatures) = SigningKeys.initKeySig(_limit); + (pubkeys, signatures) = SigningKeys.initKeysSigsBuf(_limit); used = new bool[](_limit); + SIGNING_KEYS_MAPPING_NAME.loadKeysSigs(_nodeOperatorId, _offset, _limit, pubkeys, signatures, 0); for (uint256 i; i < _limit; ++i) { - SIGNING_KEYS_MAPPING_NAME.loadKeySigAndAppend(_nodeOperatorId, _offset + i, i, pubkeys, signatures); used[i] = (_offset + i) < depositedSigningKeysCount; } + // for (uint256 i; i < _limit; ++i) { + // SIGNING_KEYS_MAPPING_NAME.loadKeySigAndAppend(_nodeOperatorId, _offset + i, i, pubkeys, signatures); + // used[i] = (_offset + i) < depositedSigningKeysCount; + // } } /// @notice Returns the type of the staking module diff --git a/contracts/0.4.24/test_helpers/SiginigKyesMock.sol b/contracts/0.4.24/test_helpers/SiginigKyesMock.sol new file mode 100644 index 000000000..0b379e137 --- /dev/null +++ b/contracts/0.4.24/test_helpers/SiginigKyesMock.sol @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2023 Lido +// SPDX-License-Identifier: GPL-3.0 + +// See contracts/COMPILERS.md +pragma solidity 0.4.24; + +import {SigningKeys} from "../lib/SigningKeys.sol"; + +import "hardhat/console.sol"; + +contract SigningKeysMock { + using SigningKeys for bytes32; + + bytes32 public constant KEYSSIGS_POSITION = keccak256("KEYSSIGS_POSITION"); + + uint256[] public _nodeOperatorIds; + + constructor(uint256[] memory ids) public { + _nodeOperatorIds = ids; + } + + function getKeyOffset(uint256 _nodeOperatorId, uint256 _keyIndex) external pure returns (uint256) { + return KEYSSIGS_POSITION.getKeyOffset(_nodeOperatorId, _keyIndex); + } + + function saveKeysSigs( + uint256 _nodeOperatorId, + uint256 _startIndex, + uint256 _keysCount, + bytes _publicKeys, + bytes _signatures + ) external returns (uint256) { + return KEYSSIGS_POSITION.saveKeysSigs(_nodeOperatorId, _startIndex, _keysCount, _publicKeys, _signatures); + } + + function removeKeysSigs( + uint256 _nodeOperatorId, + uint256 _startIndex, + uint256 _keysCount, + uint256 _lastIndex + ) external { + KEYSSIGS_POSITION.removeKeysSigs(_nodeOperatorId, _startIndex, _keysCount, _lastIndex); + } + + function loadKeysSigs(uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount) + external + view + returns (bytes memory pubkeys, bytes memory signatures) + { + (pubkeys, signatures) = SigningKeys.initKeysSigsBuf(_keysCount); + KEYSSIGS_POSITION.loadKeysSigs( + _nodeOperatorId, + _startIndex, + _keysCount, + pubkeys, + signatures, + 0 // key offset inside _pubkeys/_signatures buffers + ); + } +} diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index c9706deb9..fd81a83fa 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -2157,31 +2157,31 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob ) }) - it('reverts with "INVALID_LENGTH" error when public keys batch has invalid length', async () => { + it('reverts with "LENGTH_MISMATCH" error when public keys batch has invalid length', async () => { const keysCount = 2 const [publicKeys, signatures] = secondNodeOperatorKeys.slice(0, keysCount) await assert.reverts( app.addSigningKeys(firstNodeOperatorId, keysCount, publicKeys + 'deadbeaf', signatures, { from: voting }), - 'INVALID_LENGTH' + 'LENGTH_MISMATCH' ) }) - it('reverts with "INVALID_LENGTH" error when signatures batch has invalid length', async () => { + it('reverts with "LENGTH_MISMATCH" error when signatures batch has invalid length', async () => { const keysCount = 2 const [publicKeys, signatures] = secondNodeOperatorKeys.slice(0, keysCount) await assert.reverts( app.addSigningKeys(firstNodeOperatorId, keysCount, publicKeys, signatures.slice(0, -2), { from: voting }), - 'INVALID_LENGTH' + 'LENGTH_MISMATCH' ) }) - it('reverts with "INVALID_LENGTH" error when public keys and signatures length mismatch', async () => { + it('reverts with "LENGTH_MISMATCH" error when public keys and signatures length mismatch', async () => { const keysCount = 2 const [publicKeys] = secondNodeOperatorKeys.slice(0, keysCount) const [, signatures] = secondNodeOperatorKeys.slice(0, keysCount + 1) await assert.reverts( app.addSigningKeys(firstNodeOperatorId, keysCount, publicKeys, signatures.slice(0, -2), { from: voting }), - 'INVALID_LENGTH' + 'LENGTH_MISMATCH' ) }) @@ -2379,7 +2379,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) }) - describe('removeSigningKey()', async () => { + describe.only('removeSigningKey()', async () => { const firstNodeOperatorId = 0 const secondNodeOperatorId = 1 const nonExistentNodeOperatorId = 3 @@ -2681,10 +2681,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob ) }) - it('emits SigningKeyRemoved event with correct params', async () => { + it.only('emits SigningKeyRemoved event with correct params', async () => { const keyIndex = NODE_OPERATORS[firstNodeOperatorId].depositedSigningKeysCount assert.isTrue(keyIndex <= NODE_OPERATORS[firstNodeOperatorId].totalSigningKeysCount) const receipt = await app.removeSigningKey(firstNodeOperatorId, keyIndex, { from: voting }) + console.log('AAAA', { + keyIndex, + kkk: firstNodeOperatorKeys.slice() + }); assert.emits( receipt, 'SigningKeyRemoved', diff --git a/test/0.4.24/signingkey-lib.test.js b/test/0.4.24/signingkey-lib.test.js new file mode 100644 index 000000000..4d8adcc73 --- /dev/null +++ b/test/0.4.24/signingkey-lib.test.js @@ -0,0 +1,255 @@ +const { assert } = require('../helpers/assert') +const { assertRevert } = require('../helpers/assertThrow') +const { EvmSnapshot } = require('../helpers/blockchain') +const { ZERO_ADDRESS, getEventAt } = require('@aragon/contract-helpers-test') +const { toBN, padRight } = require('../helpers/utils') +const signingKeys = require('../helpers/signing-keys') +const { prepIdsCountsPayload } = require('../helpers/utils') +const SigningKeysMock = artifacts.require('SigningKeysMock') +const SigningKeys = artifacts.require('SigningKeys') + +const nodeOpId1 = 1 +const nodeOpId2 = 2 + +contract('SigningKeys', ([appManager, voting, user1, user2, user3, nobody]) => { + let app + const snapshot = new EvmSnapshot(hre.ethers.provider) + + const firstNodeOperatorId = 0 + const firstNodeOperatorStartIndex = 0 + const firstNodeOperatorKeys = new signingKeys.FakeValidatorKeys(5, { kFill: 'a', sFill: 'b' }) + const firstNodeOperatorLastIndex = firstNodeOperatorKeys.count - 1 + const secondNodeOperatorId = 1 + const secondNodeOperatorStartIndex = 0 + const secondNodeOperatorKeys = new signingKeys.FakeValidatorKeys(7, { kFill: 'c', sFill: 'd' }) + const secondNodeOperatorLastIndex = secondNodeOperatorKeys.count - 1 + + before('deploy base app', async () => { + // Deploy the app's base contract. + app = await SigningKeysMock.new([nodeOpId1, nodeOpId2]) + await snapshot.make() + }) + + afterEach(async () => { + await snapshot.rollback() + }) + + describe('saveKeysSigs()', () => { + it('reverts with INVALID_KEYS_COUNT error when keys count > UINT64_MAX', async () => { + const keysCount = toBN('0x10000000000000001') + await assert.reverts( + app.saveKeysSigs(firstNodeOperatorId, firstNodeOperatorStartIndex, keysCount, '0x', '0x'), + 'INVALID_KEYS_COUNT' + ) + }) + + it('reverts with "INVALID_KEYS_COUNT" error when keys count is 0', async () => { + const keysCount = 0 + await assert.reverts( + app.saveKeysSigs(firstNodeOperatorId, firstNodeOperatorStartIndex, keysCount, '0x', '0x'), + 'INVALID_KEYS_COUNT' + ) + }) + + it('reverts with "LENGTH_MISMATCH" error when public keys batch has invalid length', async () => { + const keysCount = 2 + const [publicKeys, signatures] = firstNodeOperatorKeys.slice(0, keysCount) + await assert.reverts( + app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + keysCount, + publicKeys + 'deadbeaf', + signatures + ), + 'LENGTH_MISMATCH' + ) + }) + + it('reverts with "LENGTH_MISMATCH" error when signatures batch has invalid length', async () => { + const keysCount = 2 + const [publicKeys, signatures] = firstNodeOperatorKeys.slice(0, keysCount) + await assert.reverts( + app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + keysCount, + publicKeys, + signatures.slice(0, -2) + ), + 'LENGTH_MISMATCH' + ) + }) + + it('reverts with "LENGTH_MISMATCH" error when public keys and signatures length mismatch', async () => { + const keysCount = 2 + const [publicKeys] = firstNodeOperatorKeys.slice(0, keysCount) + const [, signatures] = firstNodeOperatorKeys.slice(0, keysCount + 1) + await assert.reverts( + app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + keysCount, + publicKeys, + signatures.slice(0, -2) + ), + 'LENGTH_MISMATCH' + ) + }) + + it('reverts with "EMPTY_KEY" error when public key is zero bytes batch (at 1st position)', async () => { + const keysCount = 1 + const [, signature] = firstNodeOperatorKeys.get(0) + await assert.reverts( + app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + keysCount, + signingKeys.EMPTY_PUBLIC_KEY, + signature + ), + 'EMPTY_KEY' + ) + }) + + it('reverts with "EMPTY_KEY" error when public key is zero bytes batch (at last position)', async () => { + const keysCount = 3 + let [publicKeys] = firstNodeOperatorKeys.slice(0, keysCount - 1) + const [, signatures] = firstNodeOperatorKeys.slice(0, keysCount) + publicKeys += signingKeys.EMPTY_PUBLIC_KEY.substring(2) + await assert.reverts( + app.saveKeysSigs(firstNodeOperatorId, firstNodeOperatorStartIndex, keysCount, publicKeys, signatures), + 'EMPTY_KEY' + ) + }) + + it('emits SigningKeyAdded with correct params for every added key', async () => { + const receipt = await app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + ...firstNodeOperatorKeys.slice() + ) + for (let i = 0; i < firstNodeOperatorKeys.count; ++i) { + assert.emits( + receipt, + 'SigningKeyAdded', + { nodeOperatorId: firstNodeOperatorId, pubkey: firstNodeOperatorKeys.get(i)[0] }, + { abi: SigningKeys._json.abi } + ) + } + }) + + it('stores keys correctly', async () => { + await app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + ...firstNodeOperatorKeys.slice() + ) + + await app.saveKeysSigs( + secondNodeOperatorId, + secondNodeOperatorStartIndex, + secondNodeOperatorKeys.count, + ...secondNodeOperatorKeys.slice() + ) + + for (let i = 0; i < firstNodeOperatorKeys.count; ++i) { + const { pubkeys, signatures } = await app.loadKeysSigs(firstNodeOperatorId, i, 1) + const [expectedPublicKey, expectedSignature] = firstNodeOperatorKeys.get(i) + assert.equal(pubkeys, expectedPublicKey) + assert.equal(signatures, expectedSignature) + } + for (let i = 0; i < secondNodeOperatorKeys.count; ++i) { + const { pubkeys, signatures } = await app.loadKeysSigs(secondNodeOperatorId, i, 1) + const [expectedPublicKey, expectedSignature] = secondNodeOperatorKeys.get(i) + assert.equal(pubkeys, expectedPublicKey) + assert.equal(signatures, expectedSignature) + } + }) + }) + + describe('removeKeysSigs()', async () => { + beforeEach(async () => { + await app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + ...firstNodeOperatorKeys.slice() + ) + await app.saveKeysSigs( + secondNodeOperatorId, + secondNodeOperatorStartIndex, + secondNodeOperatorKeys.count, + ...secondNodeOperatorKeys.slice() + ) + }) + + it('reverts with INVALID_KEYS_COUNT error when keys count is zero ', async () => { + const keysCount = 0 + await assert.reverts( + app.removeKeysSigs(firstNodeOperatorId, firstNodeOperatorStartIndex, keysCount, firstNodeOperatorLastIndex), + 'INVALID_KEYS_COUNT' + ) + }) + + it('reverts with INVALID_KEYS_COUNT error when index is greater than last keys index', async () => { + const keyIndex = firstNodeOperatorLastIndex + 1 + const keysCount = 1 + await assert.reverts( + app.removeKeysSigs(firstNodeOperatorId, keyIndex, keysCount, firstNodeOperatorLastIndex), + 'INVALID_KEYS_COUNT' + ) + }) + + it('reverts with INVALID_KEYS_COUNT error when keys count is greater than last keys index', async () => { + const keysCount = firstNodeOperatorKeys.count + 1 + await assert.reverts( + app.removeKeysSigs(firstNodeOperatorId, firstNodeOperatorStartIndex, keysCount, firstNodeOperatorLastIndex), + 'INVALID_KEYS_COUNT' + ) + }) + + it.only('emits SigningKeyAdded with correct params for every added key', async () => { + const receipt = await app.removeKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + firstNodeOperatorLastIndex + ) + + for (let i = firstNodeOperatorStartIndex; i < firstNodeOperatorKeys.count; ++i) { + assert.emits( + receipt, + 'SigningKeyRemoved', + { nodeOperatorId: firstNodeOperatorId, pubkey: firstNodeOperatorKeys.get(i)[0] }, + { abi: SigningKeys._json.abi } + ) + } + }) + + it.only('removes keys correctly (clear storage)', async () => { + await app.removeKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + firstNodeOperatorLastIndex + ) + + for (let i = firstNodeOperatorStartIndex; i < firstNodeOperatorKeys.count; ++i) { + const { pubkeys, signatures } = await app.loadKeysSigs(firstNodeOperatorId, i, 1) + assert.equal(pubkeys, signingKeys.EMPTY_PUBLIC_KEY) + assert.equal(signatures, signingKeys.EMPTY_SIGNATURE) + } + }) + + it.only('removes keys correctly (move last to deleted position)', async () => { + await app.removeKeysSigs(firstNodeOperatorId, 0, 1, firstNodeOperatorLastIndex) + const { pubkeys, signatures } = await app.loadKeysSigs(firstNodeOperatorId, 0, 1) + const [expectedPublicKey, expectedSignature] = firstNodeOperatorKeys.get(firstNodeOperatorLastIndex) + assert.equal(pubkeys, expectedPublicKey) + assert.equal(signatures, expectedSignature) + }) + }) +}) diff --git a/test/helpers/signing-keys.js b/test/helpers/signing-keys.js index ac3c45ded..dffd9a4f8 100644 --- a/test/helpers/signing-keys.js +++ b/test/helpers/signing-keys.js @@ -1,6 +1,7 @@ const PUBKEY_LENGTH = 48 const SIGNATURE_LENGTH = 96 const EMPTY_PUBLIC_KEY = '0x' + '0'.repeat(2 * PUBKEY_LENGTH) +const EMPTY_SIGNATURE = '0x' + '0'.repeat(2 * SIGNATURE_LENGTH) const { pad, hexConcat, hexSplit } = require('./utils') const { strip0x } = require('../0.6.12/helpers') @@ -39,18 +40,18 @@ class ValidatorKeys { } class FakeValidatorKeys extends ValidatorKeys { - constructor(length, seed = randomInt(10, 10 ** 9)) { + constructor(length, { seed = randomInt(10, 10 ** 9), kFill = 'f', sFill = 'e' } = {}) { super( Array(length) .fill(0) .map((_, i) => Number(seed + i).toString(16)) .map((v) => (v.length % 2 === 0 ? v : '0' + v)) // make resulting hex str length representation even(faa -> 0faa) - .map((v) => pad('0x' + v, PUBKEY_LENGTH, 'f')), + .map((v) => pad('0x' + v, PUBKEY_LENGTH, kFill)), Array(length) .fill(0) .map((_, i) => Number(seed + i).toString(16)) .map((v) => (v.length % 2 === 0 ? v : '0' + v)) // make resulting hex str length representation even(faa -> 0faa) - .map((v) => pad('0x' + v, SIGNATURE_LENGTH, 'e')) + .map((v) => pad('0x' + v, SIGNATURE_LENGTH, sFill)) ) } } @@ -71,6 +72,7 @@ module.exports = { PUBKEY_LENGTH, SIGNATURE_LENGTH, EMPTY_PUBLIC_KEY, + EMPTY_SIGNATURE, FakeValidatorKeys, splitPublicKeysBatch, splitSignaturesBatch From 6f3f3333673ba1f148022c2e3e3d46a6ebfe07a5 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Mon, 20 Feb 2023 18:20:10 +0100 Subject: [PATCH 162/199] fix: nor test mock --- contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index 3cfeb7c8f..055bc7160 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -94,6 +94,10 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { operator.signingKeysStats = signingKeysStats; + Packed64x4.Packed memory operatorTargetStats; + operatorTargetStats.set(MAX_VALIDATORS_COUNT_OFFSET, vettedSigningKeysCount); + operator.targetValidatorsStats = operatorTargetStats; + emit NodeOperatorAdded(id, _name, _rewardAddress, 0); Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); @@ -115,7 +119,7 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { stuckPenaltyStats.set(REFUNDED_VALIDATORS_COUNT_OFFSET, refundedValidatorsCount); stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, stuckPenaltyEndAt); _nodeOperators[_nodeOperatorId].stuckPenaltyStats = stuckPenaltyStats; - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateTotalMaxValidatorsCount(_nodeOperatorId); } function testing_getTotalSigningKeysStats() From ccecef2819d82ea0237723f1a75210e8a713f7e4 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Mon, 20 Feb 2023 18:28:42 +0100 Subject: [PATCH 163/199] refactor: remove comments --- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 6 ------ 1 file changed, 6 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 741c33720..abe3ebb7b 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -550,7 +550,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { ); _saveTotalSigningKeysStats(totalSigningKeysStats); - /// @todo optimize: reuse totalSigningKeysStats _updateTotalMaxValidatorsCount(_nodeOperatorId); } } @@ -719,7 +718,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint64 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); uint64 vettedSigningKeysCount = signingKeysStats.get(VETTED_KEYS_COUNT_OFFSET); - /// @todo check for MAX_VALIDATORS_COUNT_OFFSET < MAX_UINT64 - 1 uint64 oldMaxSigningKeysCount = operatorTargetStats.get(MAX_VALIDATORS_COUNT_OFFSET); uint64 newMaxSigningKeysCount = depositedSigningKeysCount; @@ -758,8 +756,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 depositedSigningKeysCount; uint256 exitedSigningKeysCount; - /// @todo check for MAX_VALIDATORS_COUNT_OFFSET < MAX_UINT64 - 1 - for (uint256 nodeOperatorId; nodeOperatorId < nodeOperatorsCount; ++nodeOperatorId) { (maxSigningKeysCount, exitedSigningKeysCount, depositedSigningKeysCount) = _getNodeOperatorWithLimitApplied(nodeOperatorId); @@ -1011,7 +1007,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // comapring _toIndex <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than MAX_UINT64 _requireValidRange(_fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) && _toIndex <= totalSigningKeysCount); - /// @todo: move to lib // removing from the last index to the highest one, so we won't get outside the array for (uint256 i = _toIndex; i > _fromIndex; --i) { totalSigningKeysCount = @@ -1034,7 +1029,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).sub(uint64(_keysCount)) ); _saveTotalSigningKeysStats(totalSigningKeysStats); - /// @todo optimize: reuse totalSigningKeysStats _updateTotalMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); From e07c122bea7e740226369d6d9d019f477d52b1ab Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Mon, 20 Feb 2023 19:36:21 +0200 Subject: [PATCH 164/199] test: fix hash consensus test initialization --- test/0.8.9/oracle/hash-consensus-access-control.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/0.8.9/oracle/hash-consensus-access-control.test.js b/test/0.8.9/oracle/hash-consensus-access-control.test.js index bad3de0de..6ebea9717 100644 --- a/test/0.8.9/oracle/hash-consensus-access-control.test.js +++ b/test/0.8.9/oracle/hash-consensus-access-control.test.js @@ -12,6 +12,8 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2]) => { let consensus = null let reportProcessor = null let snapshot = null + let reportProcessor2 = null + const manageMembersAndQuorumRoleKeccak156 = web3.utils.keccak256('MANAGE_MEMBERS_AND_QUORUM_ROLE') const disableConsensusRoleKeccak156 = web3.utils.keccak256('DISABLE_CONSENSUS_ROLE') const manageFrameConfigRoleKeccak156 = web3.utils.keccak256('MANAGE_FRAME_CONFIG_ROLE') @@ -23,6 +25,8 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2]) => { consensus = deployed.consensus reportProcessor = deployed.reportProcessor + reportProcessor2 = await MockReportProcessor.new(CONSENSUS_VERSION, { from: admin }) + snapshot = new EvmSnapshot(hre.ethers.provider) await snapshot.make() } @@ -174,8 +178,6 @@ contract('HashConsensus', ([admin, account1, account2, member1, member2]) => { context('MANAGE_REPORT_PROCESSOR_ROLE', () => { context('setReportProcessor', async () => { - const reportProcessor2 = await MockReportProcessor.new(CONSENSUS_VERSION, { from: admin }) - it('should revert without MANAGE_REPORT_PROCESSOR_ROLE role', async () => { await assert.revertsOZAccessControl( consensus.setReportProcessor(reportProcessor2.address, { from: account1 }), From f291dd207a42cc757fa8d71e51f2cd3cf135edf4 Mon Sep 17 00:00:00 2001 From: Bogdan Kovtun Date: Mon, 20 Feb 2023 21:55:30 +0400 Subject: [PATCH 165/199] Add early return to NOR obtainDepositData() --- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 1ba696e20..8bb75897e 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -675,6 +675,9 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { bytes /* _depositCalldata */ ) external returns (bytes memory publicKeys, bytes memory signatures) { _auth(STAKING_ROUTER_ROLE); + + if (_depositsCount == 0) return (new bytes(0), new bytes(0)); + ( uint256 allocatedKeysCount, uint256[] memory nodeOperatorIds, From aa30cea7e704f080c1ab152e6bcbf3a31d7abf2c Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Mon, 20 Feb 2023 21:55:54 +0200 Subject: [PATCH 166/199] =?UTF-8?q?=F0=9F=92=85:=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/0.8.9/WithdrawalQueueBase.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/0.8.9/WithdrawalQueueBase.sol b/contracts/0.8.9/WithdrawalQueueBase.sol index 4d3f7886c..74487cec4 100644 --- a/contracts/0.8.9/WithdrawalQueueBase.sol +++ b/contracts/0.8.9/WithdrawalQueueBase.sol @@ -65,7 +65,7 @@ abstract contract WithdrawalQueueBase { uint96 discountFactor; } - /// @notice output format struct for `_getWithdrawalRequestStatus()` + /// @notice output format struct for `_getWithdrawalStatus()` method struct WithdrawalRequestStatus { /// @notice stETH token amount that was locked on withdrawal queue for this request uint256 amountOfStETH; From 6cb8edc28d4a20aba98b2d5a92c328a521d7204c Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Tue, 21 Feb 2023 00:15:18 +0300 Subject: [PATCH 167/199] feat: +eip712Domain for StETHPermit --- contracts/0.4.24/Lido.sol | 2 +- contracts/0.4.24/StETHPermit.sol | 19 +++++++++++++++++++ contracts/0.8.9/EIP712StETH.sol | 18 ++++++++++++++++++ contracts/common/interfaces/IEIP712StETH.sol | 11 +++++++++++ lib/abi/EIP712StETH.json | 2 +- lib/abi/Lido.json | 2 +- lib/abi/StETHPermit.json | 2 +- test/0.4.24/stethpermit.test.js | 14 ++++++++++++++ 8 files changed, 66 insertions(+), 4 deletions(-) diff --git a/contracts/0.4.24/Lido.sol b/contracts/0.4.24/Lido.sol index 158220700..47061b896 100644 --- a/contracts/0.4.24/Lido.sol +++ b/contracts/0.4.24/Lido.sol @@ -1097,7 +1097,7 @@ contract Lido is Versioned, StETHPermit, AragonApp { uint256 clValidators = CL_VALIDATORS_POSITION.getStorageUint256(); // clValidators can never be less than deposited ones. assert(depositedValidators >= clValidators); - return depositedValidators.sub(clValidators).mul(DEPOSIT_SIZE); + return (depositedValidators - clValidators).mul(DEPOSIT_SIZE); } /** diff --git a/contracts/0.4.24/StETHPermit.sol b/contracts/0.4.24/StETHPermit.sol index 88f19032b..6b7071746 100644 --- a/contracts/0.4.24/StETHPermit.sol +++ b/contracts/0.4.24/StETHPermit.sol @@ -127,6 +127,25 @@ contract StETHPermit is IERC2612, StETH { return IEIP712StETH(getEIP712StETH()).domainSeparatorV4(address(this)); } + /** + * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 + * signature. + * + * NB: compairing to the full-fledged ERC-5267 version: + * - `salt` and `extensions` are unused + * - `flags` is hex"0f" or 01111b + * + * @dev using shortened returns to reduce a bytecode size + */ + function eip712Domain() external view returns ( + string memory name, + string memory version, + uint256 chainId, + address verifyingContract + ) { + return IEIP712StETH(getEIP712StETH()).eip712Domain(address(this)); + } + /** * @dev "Consume a nonce": return the current value and increment. */ diff --git a/contracts/0.8.9/EIP712StETH.sol b/contracts/0.8.9/EIP712StETH.sol index f6e50b344..4e7055ef0 100644 --- a/contracts/0.8.9/EIP712StETH.sol +++ b/contracts/0.8.9/EIP712StETH.sol @@ -103,4 +103,22 @@ contract EIP712StETH is IEIP712StETH { function hashTypedDataV4(address _stETH, bytes32 _structHash) external view override returns (bytes32) { return ECDSA.toTypedDataHash(domainSeparatorV4(_stETH), _structHash); } + + /** + * @dev returns the fields and values that describe the domain separator + * used by stETH for EIP-712 signature. + */ + function eip712Domain(address _stETH) external view returns ( + string memory name, + string memory version, + uint256 chainId, + address verifyingContract + ) { + return ( + "Liquid staked Ether 2.0", + "2", + block.chainid, + _stETH + ); + } } diff --git a/contracts/common/interfaces/IEIP712StETH.sol b/contracts/common/interfaces/IEIP712StETH.sol index 7368e8222..75ef5f2b8 100644 --- a/contracts/common/interfaces/IEIP712StETH.sol +++ b/contracts/common/interfaces/IEIP712StETH.sol @@ -33,4 +33,15 @@ interface IEIP712StETH { * ``` */ function hashTypedDataV4(address _stETH, bytes32 _structHash) external view returns (bytes32); + + /** + * @dev returns the fields and values that describe the domain separator + * used by stETH for EIP-712 signature. + */ + function eip712Domain(address _stETH) external view returns ( + string memory name, + string memory version, + uint256 chainId, + address verifyingContract + ); } diff --git a/lib/abi/EIP712StETH.json b/lib/abi/EIP712StETH.json index bb6f561c4..d811a60f0 100644 --- a/lib/abi/EIP712StETH.json +++ b/lib/abi/EIP712StETH.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_stETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ZeroStETHAddress","type":"error"},{"inputs":[{"internalType":"address","name":"_stETH","type":"address"}],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stETH","type":"address"},{"internalType":"bytes32","name":"_structHash","type":"bytes32"}],"name":"hashTypedDataV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_stETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ZeroStETHAddress","type":"error"},{"inputs":[{"internalType":"address","name":"_stETH","type":"address"}],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stETH","type":"address"}],"name":"eip712Domain","outputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stETH","type":"address"},{"internalType":"bytes32","name":"_structHash","type":"bytes32"}],"name":"hashTypedDataV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/lib/abi/Lido.json b/lib/abi/Lido.json index 43d9f9d89..58ee3388a 100644 --- a/lib/abi/Lido.json +++ b/lib/abi/Lido.json @@ -1 +1 @@ -[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getEIP712StETH","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_clValidators","type":"uint256"},{"name":"_clBalance","type":"uint256"},{"name":"_withdrawalVaultBalance","type":"uint256"},{"name":"_elRewardsVaultBalance","type":"uint256"},{"name":"_lastFinalizableRequestId","type":"uint256"},{"name":"_simulatedShareRate","type":"uint256"}],"name":"handleOracleReport","outputs":[{"name":"postTotalPooledEther","type":"uint256"},{"name":"postTotalShares","type":"uint256"},{"name":"withdrawals","type":"uint256"},{"name":"elRewards","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"totalFee","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getDepositableEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}] \ No newline at end of file +[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"eip712Domain","outputs":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getEIP712StETH","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_clValidators","type":"uint256"},{"name":"_clBalance","type":"uint256"},{"name":"_withdrawalVaultBalance","type":"uint256"},{"name":"_elRewardsVaultBalance","type":"uint256"},{"name":"_lastFinalizableRequestId","type":"uint256"},{"name":"_simulatedShareRate","type":"uint256"}],"name":"handleOracleReport","outputs":[{"name":"postTotalPooledEther","type":"uint256"},{"name":"postTotalShares","type":"uint256"},{"name":"withdrawals","type":"uint256"},{"name":"elRewards","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"totalFee","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getDepositableEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}] \ No newline at end of file diff --git a/lib/abi/StETHPermit.json b/lib/abi/StETHPermit.json index 9ea8f13d1..b3ae6e2cc 100644 --- a/lib/abi/StETHPermit.json +++ b/lib/abi/StETHPermit.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getEIP712StETH","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}] \ No newline at end of file +[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"eip712Domain","outputs":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getEIP712StETH","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}] \ No newline at end of file diff --git a/test/0.4.24/stethpermit.test.js b/test/0.4.24/stethpermit.test.js index acab0e364..b9290fde8 100644 --- a/test/0.4.24/stethpermit.test.js +++ b/test/0.4.24/stethpermit.test.js @@ -60,6 +60,20 @@ contract('StETHPermit', ([deployer, ...accounts]) => { assert.equals(await stEthPermit.getEIP712StETH(), eip712StETH.address) }) + it('eip712Domain() is correct', async () => { + const { name, version, chainId, verifyingContract } = await stEthPermit.eip712Domain() + + assert.equals(name, 'Liquid staked Ether 2.0') + assert.equals(version, '2') + assert.equals(chainId, await web3.eth.net.getId()) + assert.equals(verifyingContract, stEthPermit.address) + + assert.equals( + makeDomainSeparator(name, version, chainId, verifyingContract), + domainSeparator + ) + }) + it('grants allowance when a valid permit is given', async () => { const { owner, spender, deadline } = permitParams let { value } = permitParams From 419ce82cfccf81cf3d253d59cd2d0abfe67375ce Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 02:00:58 +0100 Subject: [PATCH 168/199] refactor: fixes, comments --- .../0.4.24/nos/NodeOperatorsRegistry.sol | 234 ++++++++++------- contracts/0.4.24/template/LidoTemplate.sol | 2 +- .../NodeOperatorsRegistryMock.sol | 12 +- lib/abi/NodeOperatorsRegistry.json | 2 +- .../node-operators-registry-penalty.test.js | 7 +- test/0.4.24/node-operators-registry.test.js | 241 ++++++++++++------ 6 files changed, 316 insertions(+), 182 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index abe3ebb7b..ce28af1de 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -44,7 +44,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { event NodeOperatorRewardAddressSet(uint256 indexed nodeOperatorId, address rewardAddress); event NodeOperatorTotalKeysTrimmed(uint256 indexed nodeOperatorId, uint64 totalKeysTrimmed); event KeysOpIndexSet(uint256 keysOpIndex); - event ContractVersionSet(uint256 version); event StakingModuleTypeSet(bytes32 moduleType); event RewardsDistributed(address indexed rewardAddress, uint256 sharesAmount); event LocatorContractSet(address locatorAddress); @@ -55,6 +54,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { event NonceChanged(uint256 nonce); event StuckValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 stuckValidatorsCount); + event StuckPenaltyDelayChanged(uint256 stuckPenaltyDelay); event RefundedValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 RefundedValidatorsCount); event TargetValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 targetValidatorsCount); event NodeOperatorPenalized(address indexed recipientAddress, uint256 sharesPenalizedAmount); @@ -108,8 +108,22 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// @dev refunded keys count from dao uint8 internal constant REFUNDED_VALIDATORS_COUNT_OFFSET = 1; /// @dev extra penalty time after stuck keys resolved (refunded and/or exited) + /// @notice field is also used as flag for "half-cleaned" panlty status + /// Operator is PENALIZED if `STUCK_VALIDATORS_COUNT > REFUNDED_VALIDATORS_COUNT` or + /// `STUCK_VALIDATORS_COUNT <= REFUNDED_VALIDATORS_COUNT && STUCK_PENALTY_END_TIMESTAMP <= refund timastamp + STUCK_PENALTY_DELAY` + /// When operator refund all stuck validators and time has pass STUCK_PENALTY_DELAY, but STUCK_PENALTY_END_TIMESTAMP not zeroed, + /// then Operator can receive reawards but can't get new deposits until the new Oracle report or `clearNodeOperatorPenalty` is called. uint8 internal constant STUCK_PENALTY_END_TIMESTAMP_OFFSET = 2; + // Summary SigningKeysStats + uint8 internal constant SUMMARY_MAX_VALIDATORS_COUNT_OFFSET = 0; + /// @dev Number of keys in the EXITED state for this operator for all time + uint8 internal constant SUMMARY_EXITED_KEYS_COUNT_OFFSET = 1; + /// @dev Total number of keys of this operator for all time + uint8 internal constant SUMMARY_TOTAL_KEYS_COUNT_OFFSET = 2; + /// @dev Number of keys of this operator which were in DEPOSITED state for all time + uint8 internal constant SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET = 3; + // // UNSTRUCTURED STORAGE POSITIONS // @@ -175,9 +189,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { Packed64x4.Packed targetValidatorsStats; } - struct NodeOperatorTotals { - Packed64x4.Packed signingKeysStats; - // Packed64x4.Packed targetValidatorsStats; + struct NodeOperatorSummary { + Packed64x4.Packed summarySigningKeysStats; } // @@ -186,28 +199,28 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// @dev Mapping of all node operators. Mapping is used to be able to extend the struct. mapping(uint256 => NodeOperator) internal _nodeOperators; - NodeOperatorTotals internal _nodeOperatorTotals; + NodeOperatorSummary internal _nodeOperatorSummary; // // METHODS // - function initialize(address _locator, bytes32 _type) public onlyInit { + function initialize(address _locator, bytes32 _type, uint256 _stuckPenaltyDelay) public onlyInit { // Initializations for v1 --> v2 - _initialize_v2(_locator, _type); + _initialize_v2(_locator, _type, _stuckPenaltyDelay); initialized(); } /// @notice A function to finalize upgrade to v2 (from v1). Can be called only once /// For more details see https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-10.md - function finalizeUpgrade_v2(address _locator, bytes32 _type) external { - require(hasInitialized() && !isPetrified(), "CONTRACT_NOT_INITIALIZED_OR_PETRIFIED"); + function finalizeUpgrade_v2(address _locator, bytes32 _type, uint256 _stuckPenaltyDelay) external { + require(hasInitialized(), "CONTRACT_NOT_INITIALIZED"); _checkContractVersion(0); - _initialize_v2(_locator, _type); + _initialize_v2(_locator, _type, _stuckPenaltyDelay); uint256 totalOperators = getNodeOperatorsCount(); Packed64x4.Packed memory signingKeysStats; Packed64x4.Packed memory operatorTargetStats; - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); uint64 vettedSigningKeysCountBefore; uint64 totalSigningKeysCount; uint64 depositedSigningKeysCount; @@ -222,55 +235,62 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // trim vetted signing keys count when node operator is not active vettedSigningKeysCountAfter = depositedSigningKeysCount; } else { - vettedSigningKeysCountAfter = uint64(Math256.min(totalSigningKeysCount, Math256.max(uint256(depositedSigningKeysCount), uint256(vettedSigningKeysCountBefore)))); + vettedSigningKeysCountAfter = uint64( + Math256.min( + totalSigningKeysCount, + Math256.max(uint256(depositedSigningKeysCount), uint256(vettedSigningKeysCountBefore)) + ) + ); } if (vettedSigningKeysCountBefore != vettedSigningKeysCountAfter) { signingKeysStats.set(VETTED_KEYS_COUNT_OFFSET, vettedSigningKeysCountAfter); _saveOperatorSigningKeysStats(nodeOperatorId, signingKeysStats); - - operatorTargetStats = _loadOperatorTargetValidatorsStats(nodeOperatorId); - operatorTargetStats.set(MAX_VALIDATORS_COUNT_OFFSET, vettedSigningKeysCountAfter); - _saveOperatorTargetValidatorsStats(nodeOperatorId, operatorTargetStats); - emit VettedSigningKeysCountChanged(nodeOperatorId, vettedSigningKeysCountAfter); } - totalSigningKeysStats.set( - VETTED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET).add(vettedSigningKeysCountAfter) + operatorTargetStats = _loadOperatorTargetValidatorsStats(nodeOperatorId); + operatorTargetStats.set(MAX_VALIDATORS_COUNT_OFFSET, vettedSigningKeysCountAfter); + _saveOperatorTargetValidatorsStats(nodeOperatorId, operatorTargetStats); + + summarySigningKeysStats.set( + SUMMARY_MAX_VALIDATORS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_MAX_VALIDATORS_COUNT_OFFSET).add(vettedSigningKeysCountAfter) ); - totalSigningKeysStats.set( - DEPOSITED_KEYS_COUNT_OFFSET, - totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(depositedSigningKeysCount) + summarySigningKeysStats.set( + SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET).add(depositedSigningKeysCount) ); - totalSigningKeysStats.set( - EXITED_KEYS_COUNT_OFFSET, - totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET).add(signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET)) + summarySigningKeysStats.set( + SUMMARY_EXITED_KEYS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_EXITED_KEYS_COUNT_OFFSET).add( + signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET) + ) ); - totalSigningKeysStats.set( - TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).add(totalSigningKeysCount) + summarySigningKeysStats.set( + SUMMARY_TOTAL_KEYS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_TOTAL_KEYS_COUNT_OFFSET).add(totalSigningKeysCount) ); } - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); _increaseValidatorsKeysNonce(); } - function _initialize_v2(address _locator, bytes32 _type) internal { + function _initialize_v2(address _locator, bytes32 _type, uint256 _stuckPenaltyDelay) internal { _onlyNonZeroAddress(_locator); LIDO_LOCATOR_POSITION.setStorageAddress(_locator); TYPE_POSITION.setStorageBytes32(_type); _setContractVersion(2); - _setStuckPenaltyDelay(2 days); + _setStuckPenaltyDelay(_stuckPenaltyDelay); // set unlimited allowance for burner from staking router // to burn stuck keys penalized shares IStETH(getLocator().lido()).approve(getLocator().burner(), ~uint256(0)); - emit ContractVersionSet(2); emit LocatorContractSet(_locator); emit StakingModuleTypeSet(_type); } @@ -390,7 +410,11 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint64 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); uint64 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); - uint64 vettedSigningKeysCountAfter = uint64(Math256.min(totalSigningKeysCount, Math256.max(uint256(_vettedSigningKeysCount), uint256(depositedSigningKeysCount)))); + uint64 vettedSigningKeysCountAfter = uint64( + Math256.min( + totalSigningKeysCount, Math256.max(uint256(_vettedSigningKeysCount), uint256(depositedSigningKeysCount)) + ) + ); if (vettedSigningKeysCountAfter == vettedSigningKeysCountBefore) { return; @@ -418,12 +442,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// /// @param _nodeOperatorIds bytes packed array of the node operators id /// @param _stuckValidatorsCounts bytes packed array of the new number of stuck validators for the node operators - function updateStuckValidatorsCount( - bytes _nodeOperatorIds, - bytes _stuckValidatorsCounts - ) - external - { + function updateStuckValidatorsCount(bytes _nodeOperatorIds, bytes _stuckValidatorsCounts) external { _auth(STAKING_ROUTER_ROLE); _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _stuckValidatorsCounts.length % 16 == 0); @@ -435,11 +454,19 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint64 validatorsCount; uint256 _nodeOperatorIdsOffset; uint256 _stuckValidatorsCountsOffset; + + /// @dev calldata layout: + /// | func sig (4 bytes) | ABI-enc data | + /// + /// ABI-enc data: + /// + /// | 32 bytes | 32 bytes | 32 bytes | ... | 32 bytes | ...... | + /// | ids len offset | counts len offset | ids len | ids | counts len | counts | assembly { _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) - _stuckValidatorsCountsOffset := add(calldataload(36), 36) // signature_bytes4 + arg2_bytes calldata offset + 32 (length slot)) + _stuckValidatorsCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot)) } - for (uint256 i; i < nodeOperatorsCount; ) { + for (uint256 i; i < nodeOperatorsCount;) { /// @solidity memory-safe-assembly assembly { nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) @@ -455,33 +482,34 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// for node operator with given id /// /// @param _nodeOperatorIds bytes packed array of the node operators id - /// @param _stuckValidatorsCounts bytes packed array of the new number of EXITED validators for the node operators + /// @param _exitedValidatorsCounts bytes packed array of the new number of EXITED validators for the node operators function updateExitedValidatorsCount( bytes _nodeOperatorIds, - bytes _stuckValidatorsCounts + bytes _exitedValidatorsCounts ) external { _auth(STAKING_ROUTER_ROLE); - _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _stuckValidatorsCounts.length % 16 == 0); + _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _exitedValidatorsCounts.length % 16 == 0); uint256 nodeOperatorsCount = _nodeOperatorIds.length / 8; - _requireValidReportData(_stuckValidatorsCounts.length / 16 == nodeOperatorsCount); + _requireValidReportData(_exitedValidatorsCounts.length / 16 == nodeOperatorsCount); uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); uint256 nodeOperatorId; uint64 validatorsCount; uint256 _nodeOperatorIdsOffset; - uint256 _stuckValidatorsCountsOffset; + uint256 _exitedValidatorsCountsOffset; + /// @dev see comments for `updateStuckValidatorsCount` assembly { _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) - _stuckValidatorsCountsOffset := add(calldataload(36), 36) // signature_bytes4 + arg2_bytes calldata offset + 32 (length slot)) + _exitedValidatorsCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot)) } - for (uint256 i; i < nodeOperatorsCount; ) { + for (uint256 i; i < nodeOperatorsCount;) { /// @solidity memory-safe-assembly assembly { nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) - validatorsCount := shr(128, calldataload(add(_stuckValidatorsCountsOffset, mul(i, 16)))) + validatorsCount := shr(128, calldataload(add(_exitedValidatorsCountsOffset, mul(i, 16)))) i := add(i, 1) } _requireValidRange(nodeOperatorId < totalNodeOperatorsCount); @@ -521,7 +549,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _onlyExistedNodeOperator(_nodeOperatorId); _auth(STAKING_ROUTER_ROLE); - _updateExitedValidatorsCount(_nodeOperatorId, uint64(_exitedValidatorsCount), true /* _allowDecrease */); + _updateExitedValidatorsCount(_nodeOperatorId, uint64(_exitedValidatorsCount), true /* _allowDecrease */ ); _updateStuckValidatorsCount(_nodeOperatorId, uint64(_stuckValidatorsCount)); } @@ -543,12 +571,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit ExitedSigningKeysCountChanged(_nodeOperatorId, _exitedValidatorsKeysCount); // upd totals - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); - totalSigningKeysStats.set( - EXITED_KEYS_COUNT_OFFSET, - uint64(int64(totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET)) + totalExitedValidatorsDelta) + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); + summarySigningKeysStats.set( + SUMMARY_EXITED_KEYS_COUNT_OFFSET, + uint64(int64(summarySigningKeysStats.get(SUMMARY_EXITED_KEYS_COUNT_OFFSET)) + totalExitedValidatorsDelta) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); _updateTotalMaxValidatorsCount(_nodeOperatorId); } @@ -613,13 +641,13 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { function _updateTotalMaxValidatorsCount(uint256 _nodeOperatorId) internal returns (int64 maxSigningKeysDelta) { maxSigningKeysDelta = _applyNodeOperatorLimits(_nodeOperatorId); if (maxSigningKeysDelta != 0) { - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); - totalSigningKeysStats.set( + summarySigningKeysStats.set( VETTED_KEYS_COUNT_OFFSET, - uint64(int64(totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET)) + maxSigningKeysDelta) + uint64(int64(summarySigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET)) + maxSigningKeysDelta) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); } } @@ -697,7 +725,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _increaseValidatorsKeysNonce(); } - function _getNodeOperatorWithLimitApplied(uint256 _nodeOperatorId) + function _getNodeOperator(uint256 _nodeOperatorId) internal view returns (uint64 maxSigningKeysCount, uint64 exitedSigningKeysCount, uint64 depositedSigningKeysCount) @@ -721,7 +749,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint64 oldMaxSigningKeysCount = operatorTargetStats.get(MAX_VALIDATORS_COUNT_OFFSET); uint64 newMaxSigningKeysCount = depositedSigningKeysCount; - if (!isOperatorPenalized(_nodeOperatorId, true)) { + if (isOperatorPenaltyCleared(_nodeOperatorId)) { if (operatorTargetStats.get(IS_TARGET_LIMIT_ACTIVE_OFFSET) == 0) { newMaxSigningKeysCount = vettedSigningKeysCount; } else { @@ -757,8 +785,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 exitedSigningKeysCount; for (uint256 nodeOperatorId; nodeOperatorId < nodeOperatorsCount; ++nodeOperatorId) { - (maxSigningKeysCount, exitedSigningKeysCount, depositedSigningKeysCount) = - _getNodeOperatorWithLimitApplied(nodeOperatorId); + (maxSigningKeysCount, exitedSigningKeysCount, depositedSigningKeysCount) = _getNodeOperator(nodeOperatorId); // the node operator has no available signing keys if (depositedSigningKeysCount == maxSigningKeysCount) continue; @@ -820,11 +847,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { assert(loadedKeysCount == _keysCountToLoad); - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); - totalSigningKeysStats.set( - DEPOSITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(uint64(loadedKeysCount)) + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); + summarySigningKeysStats.set( + SUMMARY_TOTAL_KEYS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET).add(uint64(loadedKeysCount)) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); } /// @notice Returns the node operator by id @@ -886,7 +914,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { recipients[idx] = _nodeOperators[operatorId].rewardAddress; // prefill shares array with 'key share' for recipient, see below shares[idx] = activeValidatorsCount; - penalized[idx] = isOperatorPenalized(operatorId, false); + penalized[idx] = isOperatorPenalized(operatorId); ++idx; } @@ -942,7 +970,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _requireValidRange(totalSigningKeysCount.add(_keysCount) <= UINT64_MAX); - // totalSigningKeysCount = SIGNING_KEYS_MAPPING_NAME.addKeysSigs(_nodeOperatorId, _keysCount, totalSigningKeysCount, _publicKeys, _signatures); @@ -952,11 +979,11 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); // upd totals - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); - totalSigningKeysStats.set( - TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).add(uint64(_keysCount)) + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); + summarySigningKeysStats.set( + TOTAL_KEYS_COUNT_OFFSET, summarySigningKeysStats.get(SUMMARY_TOTAL_KEYS_COUNT_OFFSET).add(uint64(_keysCount)) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); _increaseValidatorsKeysNonce(); } @@ -1024,11 +1051,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); // upd totals - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); - totalSigningKeysStats.set( - TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).sub(uint64(_keysCount)) + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); + summarySigningKeysStats.set( + SUMMARY_TOTAL_KEYS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_TOTAL_KEYS_COUNT_OFFSET).sub(uint64(_keysCount)) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); _updateTotalMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); @@ -1102,13 +1130,16 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { view returns (uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount) { - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); - totalExitedValidators = totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET); - totalDepositedValidators = totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); - depositableValidatorsCount = totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET) - totalDepositedValidators; + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); + totalExitedValidators = summarySigningKeysStats.get(SUMMARY_EXITED_KEYS_COUNT_OFFSET); + totalDepositedValidators = summarySigningKeysStats.get(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET); + depositableValidatorsCount = summarySigningKeysStats.get(SUMMARY_MAX_VALIDATORS_COUNT_OFFSET) - totalDepositedValidators; } - function getNodeOperatorSummary(uint256 _nodeOperatorId) external view returns ( + function getNodeOperatorSummary(uint256 _nodeOperatorId) + external + view + returns ( bool isTargetLimitActive, uint256 targetValidatorsCount, uint256 stuckValidatorsCount, @@ -1139,22 +1170,37 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 depositableValidatorsCount ) { uint256 totalMaxValidators; - (totalMaxValidators, totalExitedValidators, totalDepositedValidators) = - _getNodeOperatorWithLimitApplied(_nodeOperatorId); + (totalMaxValidators, totalExitedValidators, totalDepositedValidators) = _getNodeOperator(_nodeOperatorId); depositableValidatorsCount = totalMaxValidators - totalDepositedValidators; } - function isOperatorPenalized(uint256 _nodeOperatorId, bool _withClearedPenalty) public view returns (bool) { - Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); + // добавить в distributerewards вызов + + // комент по чтению calldata и смещениям + // передавать параметром penalty delay и эмитить событие + + function _isOperatorPenalized(Packed64x4.Packed memory stuckPenaltyStats) internal view returns (bool) { return stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET) < stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET) - || block.timestamp <= stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) - || (_withClearedPenalty && stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) != 0); + || block.timestamp <= stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET); + } + + function isOperatorPenalized(uint256 _nodeOperatorId) public view returns (bool) { + Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); + return _isOperatorPenalized(stuckPenaltyStats); } - function clearNodeOperatorPenalty(uint256 _nodeOperatorId) external returns (bool) { - require(!isOperatorPenalized(_nodeOperatorId, false), "CANT_CLEAR_PANLTY"); + function isOperatorPenaltyCleared(uint256 _nodeOperatorId) public view returns (bool) { Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); + return !_isOperatorPenalized(stuckPenaltyStats) && stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) == 0; + } + + function clearNodeOperatorPenalty(uint256 _nodeOperatorId) public returns (bool) { + Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); + require( + !_isOperatorPenalized(stuckPenaltyStats) && stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) != 0, + "CANT_CLEAR_PENALTY" + ); stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, 0); _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); _updateTotalMaxValidatorsCount(_nodeOperatorId); @@ -1256,8 +1302,10 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _setStuckPenaltyDelay(_delay); } + /// @dev set new stuck penalty delay, duration in sec function _setStuckPenaltyDelay(uint256 _delay) internal { STUCK_PENALTY_DELAY_POSITION.setStorageUint256(_delay); + emit StuckPenaltyDelayChanged(_delay); } function _increaseValidatorsKeysNonce() internal { @@ -1268,12 +1316,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit NonceChanged(keysOpIndex); } - function _loadTotalSigningKeysStats() internal view returns (Packed64x4.Packed memory) { - return _nodeOperatorTotals.signingKeysStats; + function _loadSummarySigningKeysStats() internal view returns (Packed64x4.Packed memory) { + return _nodeOperatorSummary.summarySigningKeysStats; } - function _saveTotalSigningKeysStats(Packed64x4.Packed memory _val) internal { - _nodeOperatorTotals.signingKeysStats = _val; + function _saveSummarySigningKeysStats(Packed64x4.Packed memory _val) internal { + _nodeOperatorSummary.summarySigningKeysStats = _val; } function _loadOperatorTargetValidatorsStats(uint256 _nodeOperatorId) internal view returns (Packed64x4.Packed memory) { diff --git a/contracts/0.4.24/template/LidoTemplate.sol b/contracts/0.4.24/template/LidoTemplate.sol index 7045fd720..4ca6bb5eb 100644 --- a/contracts/0.4.24/template/LidoTemplate.sol +++ b/contracts/0.4.24/template/LidoTemplate.sol @@ -328,7 +328,7 @@ contract LidoTemplate is IsContract { ); - state.operators.initialize(state.lido, bytes32(0x1)); + state.operators.initialize(state.lido, bytes32(0x1), 2 days); // used for issuing vested tokens in the next step _createTokenManagerPermissionsForTemplate(state.acl, state.tokenManager); diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index 055bc7160..52a346143 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -12,11 +12,11 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { signingKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) + _keysCount); _nodeOperators[_nodeOperatorId].signingKeysStats = signingKeysStats; - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + Packed64x4.Packed memory totalSigningKeysStats = _loadSummarySigningKeysStats(); totalSigningKeysStats.set( DEPOSITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(_keysCount) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(totalSigningKeysStats); _updateTotalMaxValidatorsCount(_nodeOperatorId); } @@ -100,12 +100,12 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { emit NodeOperatorAdded(id, _name, _rewardAddress, 0); - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + Packed64x4.Packed memory totalSigningKeysStats = _loadSummarySigningKeysStats(); totalSigningKeysStats.set(VETTED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET).add(vettedSigningKeysCount)); totalSigningKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(depositedSigningKeysCount)); totalSigningKeysStats.set(EXITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET).add(exitedSigningKeysCount)); totalSigningKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).add(totalSigningKeysCount)); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(totalSigningKeysStats); } function testing_setNodeOperatorLimits( @@ -190,10 +190,10 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { return false; } - function testing_getNodeOperatorWithLimitApplied(uint256 operatorId) external view + function testing_getNodeOperator(uint256 operatorId) external view returns (uint64 maxSigningKeysCount, uint64 exitedSigningKeysCount, uint64 depositedSigningKeysCount) { - return _getNodeOperatorWithLimitApplied(operatorId); + return _getNodeOperator(operatorId); } event ValidatorsKeysLoaded(uint256 count, bytes publicKeys, bytes signatures); diff --git a/lib/abi/NodeOperatorsRegistry.json b/lib/abi/NodeOperatorsRegistry.json index d5ae3cc15..a9f084984 100644 --- a/lib/abi/NodeOperatorsRegistry.json +++ b/lib/abi/NodeOperatorsRegistry.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_withClearedPenalty","type":"bool"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file diff --git a/test/0.4.24/node-operators-registry-penalty.test.js b/test/0.4.24/node-operators-registry-penalty.test.js index 5868b4c8b..22a2a41ba 100644 --- a/test/0.4.24/node-operators-registry-penalty.test.js +++ b/test/0.4.24/node-operators-registry-penalty.test.js @@ -63,6 +63,7 @@ const NODE_OPERATORS = [ // bytes32 0x63757261746564 const CURATED_TYPE = padRight(web3.utils.fromAscii('curated'), 32) +const PENALTY_DELAY = 2 * 24 * 60 * 60 // 2 days const pad = (hex, bytesLength) => { const absentZeroes = bytesLength * 2 + 2 - hex.length @@ -124,15 +125,15 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use // app = await NodeOperatorsRegistry.at(proxyAddress) // Initialize the app's proxy. - const tx = await app.initialize(locator.address, CURATED_TYPE) + const tx = await app.initialize(locator.address, CURATED_TYPE, PENALTY_DELAY) //set stuck penalty voting - await app.setStuckPenaltyDelay(60*60*24*2, { from: voting }) + // await app.setStuckPenaltyDelay(PENALTY_DELAY, { from: voting }) // Implementation initializer reverts because initialization block was set to max(uint256) // in the Autopetrified base contract // await assert.reverts(appBase.initialize(steth.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') - await assert.reverts(appBase.initialize(locator.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') + await assert.reverts(appBase.initialize(locator.address, CURATED_TYPE, PENALTY_DELAY), 'INIT_ALREADY_INITIALIZED') const moduleType = await app.getType() assert.emits(tx, 'ContractVersionSet', { version: 2 }) diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index c9706deb9..615503997 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -61,6 +61,7 @@ const NODE_OPERATORS = [ // bytes32 0x63757261746564 const CURATED_TYPE = padRight(web3.utils.fromAscii('curated'), 32) +const PENALTY_DELAY = 2 * 24 * 60 * 60 // 2 days const pad = (hex, bytesLength) => { const absentZeroes = bytesLength * 2 + 2 - hex.length @@ -112,14 +113,17 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob // const proxyAddress = await newApp(newDAO.dao, 'node-operators-registry', appBase.address, appManager) // app = await NodeOperatorsRegistry.at(proxyAddress) - await assert.reverts(app.finalizeUpgrade_v2(locator.address, CURATED_TYPE), 'CONTRACT_NOT_INITIALIZED_OR_PETRIFIED') + await assert.reverts( + app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY), + 'CONTRACT_NOT_INITIALIZED' + ) // Initialize the app's proxy. - const tx = await app.initialize(locator.address, CURATED_TYPE) + const tx = await app.initialize(locator.address, CURATED_TYPE, PENALTY_DELAY) // Implementation initializer reverts because initialization block was set to max(uint256) // in the Autopetrified base contract - await assertRevert(appBase.initialize(locator.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') + await assertRevert(appBase.initialize(locator.address, CURATED_TYPE, PENALTY_DELAY), 'INIT_ALREADY_INITIALIZED') const moduleType = await app.getType() assert.emits(tx, 'ContractVersionSet', { version: 2 }) @@ -154,18 +158,18 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it("can't be initialized second time", async () => { - await assert.reverts(app.initialize(steth.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') + await assert.reverts(app.initialize(steth.address, CURATED_TYPE, PENALTY_DELAY), 'INIT_ALREADY_INITIALIZED') }) it('reverts with error "ZERO_ADDRESS" when stETH is zero address', async () => { const registry = await dao.newAppInstance({ name: 'new-node-operators-registry', base: appBase }) - await assert.reverts(registry.initialize(ZERO_ADDRESS, CURATED_TYPE), 'ZERO_ADDRESS') + await assert.reverts(registry.initialize(ZERO_ADDRESS, CURATED_TYPE, PENALTY_DELAY), 'ZERO_ADDRESS') }) it('call on implementation reverts with error "INIT_ALREADY_INITIALIZED"', async () => { // Implementation initializer reverts because initialization block was set to max(uint256) // in the Autopetrified base contract - await assert.reverts(appBase.initialize(steth.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') + await assert.reverts(appBase.initialize(steth.address, CURATED_TYPE, PENALTY_DELAY), 'INIT_ALREADY_INITIALIZED') }) }) @@ -175,22 +179,22 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await app.testing_setBaseVersion(0) }) - it('fails with PETRIFIED error when called on implementation', async () => { + it('fails with CONTRACT_NOT_INITIALIZED error when called on implementation', async () => { await assert.reverts( - appBase.finalizeUpgrade_v2(locator.address, CURATED_TYPE), - 'CONTRACT_NOT_INITIALIZED_OR_PETRIFIED' + appBase.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY), + 'CONTRACT_NOT_INITIALIZED' ) }) it('sets correct contract version', async () => { - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) assert.equals(await app.getContractVersion(), 2) }) it('reverts with error WRONG_BASE_VERSION when called on already initialized contract', async () => { - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) assert.equals(await app.getContractVersion(), 2) - assert.reverts(app.finalizeUpgrade_v2(locator.address, CURATED_TYPE), 'WRONG_BASE_VERSION') + assert.reverts(app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY), 'WRONG_BASE_VERSION') }) it('sets total signing keys stats correctly', async () => { @@ -228,7 +232,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equal(nodeOperatorLimits.stuckPenaltyEndTimestamp.toNumber(), NODE_OPERATORS[i].stuckPenaltyEndAt) } - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) const totalSigningKeysStatsAfter = await app.testing_getTotalSigningKeysStats() @@ -279,7 +283,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equal(nodeOperator.stakingLimit.toNumber(), config.vettedSigningKeysCount) assert.equal(nodeOperator.totalSigningKeys.toNumber(), config.totalSigningKeysCount) - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) nodeOperator = await app.getNodeOperator(0, false) assert.equal(nodeOperator.stakingLimit.toNumber(), config.totalSigningKeysCount) @@ -319,7 +323,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equal(nodeOperator.stakingLimit.toNumber(), config.vettedSigningKeysCount) assert.equal(nodeOperator.totalSigningKeys.toNumber(), config.totalSigningKeysCount) - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) nodeOperator = await app.getNodeOperator(0, false) @@ -328,24 +332,24 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('emits ContractVersionSet event with correct params', async () => { - const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) assert.emits(receipt, 'ContractVersionSet', { version: 2 }) }) it('emits LocatorContractSet event with correct params', async () => { - const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) assert.emits(receipt, 'LocatorContractSet', { locatorAddress: locator.address }) }) it('emits StakingModuleTypeSet event with correct params', async () => { - const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) const moduleType = await app.getType() assert.emits(receipt, 'StakingModuleTypeSet', { moduleType }) }) it('increases keysOpIndex & changes nonce', async () => { const [keysOpIndexBefore, nonceBefore] = await Promise.all([app.getKeysOpIndex(), app.getNonce()]) - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) const [keysOpIndexAfter, nonceAfter] = await Promise.all([app.getKeysOpIndex(), app.getNonce()]) assert.equals(keysOpIndexAfter, keysOpIndexBefore.toNumber() + 1) assert.notEquals(nonceAfter, nonceBefore) @@ -353,7 +357,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits KeysOpIndexSet & NonceChanged', async () => { const keysOpIndexBefore = await app.getKeysOpIndex() - const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) const nonceAfter = await app.getNonce() assert.emits(receipt, 'KeysOpIndexSet', { keysOpIndex: keysOpIndexBefore.toNumber() + 1 }) assert.emits(receipt, 'NonceChanged', { nonce: nonceAfter }) @@ -689,7 +693,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob 'invariant failed: readyToDepositValidatorsKeysCountBefore <= depositedSigningKeysCount' ) assert.isTrue(nodeOperator.active, 'Invariant Failed: not active') - assert.isTrue(+operatorReportBefore.totalDepositedValidators > 0, 'Invariant Failed: vettedSigningKeysCount === 0') + assert.isTrue( + +operatorReportBefore.totalDepositedValidators > 0, + 'Invariant Failed: vettedSigningKeysCount === 0' + ) await app.deactivateNodeOperator(activeNodeOperatorId, { from: voting }) const [operatorReportAfter, allValidatorsReportAfter] = await Promise.all([ @@ -743,7 +750,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob ]) assert.equals(operatorReportBefore.totalDepositedValidators, operatorReportAfter.totalDepositedValidators) - assert.equals(allValidatorsReportBefore.totalDepositedValidators, allValidatorsReportAfter.totalDepositedValidators) + assert.equals( + allValidatorsReportBefore.totalDepositedValidators, + allValidatorsReportAfter.totalDepositedValidators + ) }) it('emits NodeOperatorActiveSet(deactivate) event with correct params', async () => { @@ -1073,19 +1083,31 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const hasPermission = await dao.hasPermission(nobody, app, 'STAKING_ROUTER_ROLE') assert.isFalse(hasPermission) const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, 40) - await assert.reverts(app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: nobody }), 'APP_AUTH_FAILED') + await assert.reverts( + app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: nobody }), + 'APP_AUTH_FAILED' + ) }) it("doesn't change the state when new value is equal to the previous one", async () => { - const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator(firstNodeOperatorId, false) + const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, exitedValidatorsKeysCountBefore) await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) - const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(firstNodeOperatorId, false) + const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) assert.equals(exitedValidatorsKeysCountBefore, exitedValidatorsKeysCountAfter) }) it("doesn't emit ExitedSigningKeysCountChanged event when new value is equal to the previous one", async () => { - const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator(firstNodeOperatorId, false) + const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, exitedValidatorsKeysCountBefore) const receipt = await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) assert.notEmits(receipt, 'ExitedSigningKeysCountChanged') @@ -1119,7 +1141,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.notEquals(exitedValidatorsKeysCountBefore, newExitedValidatorsCount) const { operatorIds, keysCounts } = prepIdsCountsPayload(secondNodeOperatorId, newExitedValidatorsCount) await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) - const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(secondNodeOperatorId, false) + const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( + secondNodeOperatorId, + false + ) assert.equals(exitedValidatorsKeysCountAfter, newExitedValidatorsCount) }) @@ -1154,7 +1179,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it("doesn't change the exited signing keys count of other node operators", async () => { const newExitedValidatorsCount = 4 - const { stakingLimit: secondNodeOperatorStakingLimitBefore } = await app.getNodeOperator(firstNodeOperatorId, true) + const { stakingLimit: secondNodeOperatorStakingLimitBefore } = await app.getNodeOperator( + firstNodeOperatorId, + true + ) const { operatorIds, keysCounts } = prepIdsCountsPayload(secondNodeOperatorId, newExitedValidatorsCount) await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) const { stakingLimit: secondNodeOperatorStakingLimitAfter } = await app.getNodeOperator(firstNodeOperatorId, true) @@ -1191,7 +1219,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('increases the stuck validators count when new value is greater then previous one', async () => { const newStuckValidatorsCount = 3 - const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary(secondNodeOperatorId) + const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary( + secondNodeOperatorId + ) assert(newStuckValidatorsCount > stuckValidatorsCountBefore) await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, exitedValidatorsCount, newStuckValidatorsCount, { from: voting @@ -1216,14 +1246,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it("doesn't change the state when new stuck validators value is equal to the previous one", async () => { const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary(firstNodeOperatorId) - await app.unsafeUpdateValidatorsCount( - firstNodeOperatorId, - exitedValidatorsCount, - stuckValidatorsCountBefore, - { - from: voting - } - ) + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsCount, stuckValidatorsCountBefore, { + from: voting + }) const { stuckValidatorsCount: stuckValidatorsCountAfter } = await app.getNodeOperatorSummary(firstNodeOperatorId) assert.equals(stuckValidatorsCountBefore, stuckValidatorsCountAfter) @@ -1280,21 +1305,43 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('reverts with "APP_AUTH_FAILED" error when called by sender without STAKING_ROUTER_ROLE', async () => { const hasPermission = await dao.hasPermission(nobody, app, 'STAKING_ROUTER_ROLE') assert.isFalse(hasPermission) - await assert.reverts(app.unsafeUpdateValidatorsCount(firstNodeOperatorId, 40, stuckValidatorsCount, { from: nobody }), 'APP_AUTH_FAILED') + await assert.reverts( + app.unsafeUpdateValidatorsCount(firstNodeOperatorId, 40, stuckValidatorsCount, { from: nobody }), + 'APP_AUTH_FAILED' + ) }) it("doesn't change the state when new value is equal to the previous one", async () => { - const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator(firstNodeOperatorId, false) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsKeysCountBefore, stuckValidatorsCount, { from: voting }) - const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(firstNodeOperatorId, false) + const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) + await app.unsafeUpdateValidatorsCount( + firstNodeOperatorId, + exitedValidatorsKeysCountBefore, + stuckValidatorsCount, + { from: voting } + ) + const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) assert.equals(exitedValidatorsKeysCountBefore, exitedValidatorsKeysCountAfter) }) it("doesn't emit ExitedSigningKeysCountChanged event when new value is equal to the previous one", async () => { - const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator(firstNodeOperatorId, false) - const receipt = await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsKeysCountBefore, stuckValidatorsCount, { - from: voting - }) + const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) + const receipt = await app.unsafeUpdateValidatorsCount( + firstNodeOperatorId, + exitedValidatorsKeysCountBefore, + stuckValidatorsCount, + { + from: voting + } + ) assert.notEmits(receipt, 'ExitedSigningKeysCountChanged') }) @@ -1303,7 +1350,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const nodeOperator = await app.getNodeOperator(firstNodeOperatorId, false) assert(newExitedValidatorsCount > nodeOperator.usedSigningKeys.toNumber()) await assert.reverts( - app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }), + app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }), 'OUT_OF_RANGE' ) }) @@ -1315,8 +1364,13 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob false ) assert(newExitedValidatorsCount < exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }) - const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(firstNodeOperatorId, false) + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }) + const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) assert.equals(exitedValidatorsKeysCountAfter, newExitedValidatorsCount) }) @@ -1327,8 +1381,13 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob false ) assert(newExitedValidatorsCount > exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }) - const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(secondNodeOperatorId, false) + await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }) + const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( + secondNodeOperatorId, + false + ) assert.equals(exitedValidatorsKeysCountAfter, newExitedValidatorsCount) }) @@ -1342,7 +1401,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob app.testing_getTotalSigningKeysStats() ]) assert(newExitedValidatorsCount < exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }) + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }) const exitedSigningKeysCountIncrement = exitedValidatorsKeysCountBefore.toNumber() - newExitedValidatorsCount const { exitedSigningKeysCount: exitedSigningKeysCountAfter } = await app.testing_getTotalSigningKeysStats() assert.equals( @@ -1361,7 +1422,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob app.testing_getTotalSigningKeysStats() ]) assert(newExitedValidatorsCount > exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }) + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }) const exitedSigningKeysCountIncrement = newExitedValidatorsCount - exitedValidatorsKeysCountBefore.toNumber() const { exitedSigningKeysCount: exitedSigningKeysCountAfter } = await app.testing_getTotalSigningKeysStats() assert.equals( @@ -1373,7 +1436,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits ExitedSigningKeysCountChanged event with correct params', async () => { const newExitedValidatorsCount = 2 const receipt = await app.unsafeUpdateValidatorsCount( - firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting } + firstNodeOperatorId, + newExitedValidatorsCount, + stuckValidatorsCount, + { from: voting } ) assert.emits(receipt, 'ExitedSigningKeysCountChanged', { nodeOperatorId: firstNodeOperatorId, @@ -1383,13 +1449,16 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it("doesn't change the exited signing keys count of other node operators", async () => { const newExitedValidatorsCount = 4 - const { stakingLimit: secondNodeOperatorStakingLimitBefore } = await app.getNodeOperator(firstNodeOperatorId, true) - await app.unsafeUpdateValidatorsCount( - secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting } + const { stakingLimit: secondNodeOperatorStakingLimitBefore } = await app.getNodeOperator( + firstNodeOperatorId, + true ) await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }) + await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }) const { stakingLimit: secondNodeOperatorStakingLimitAfter } = await app.getNodeOperator(firstNodeOperatorId, true) assert.equals(secondNodeOperatorStakingLimitAfter, secondNodeOperatorStakingLimitBefore) }) @@ -1473,8 +1542,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('sets total vetted signing keys count & total signing keys count values to deposited signing keys count', async () => { const totalSigningKeysStatsBefore = await app.testing_getTotalSigningKeysStats() - assert.notEquals(totalSigningKeysStatsBefore.vettedSigningKeysCount, totalSigningKeysStatsBefore.depositedSigningKeysCount) - assert.notEquals(totalSigningKeysStatsBefore.totalSigningKeysCount, totalSigningKeysStatsBefore.depositedSigningKeysCount) + assert.notEquals( + totalSigningKeysStatsBefore.vettedSigningKeysCount, + totalSigningKeysStatsBefore.depositedSigningKeysCount + ) + assert.notEquals( + totalSigningKeysStatsBefore.totalSigningKeysCount, + totalSigningKeysStatsBefore.depositedSigningKeysCount + ) await app.onWithdrawalCredentialsChanged({ from: voting }) const totalSigningKeysStatsAfter = await app.testing_getTotalSigningKeysStats() assert.equals( @@ -1524,7 +1599,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('_getCorrectedNodeOperator() - deposited < exited+target < vetted', async () => { - let firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + let firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) @@ -1532,14 +1607,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await app.updateTargetValidatorsLimits(firstNodeOperatorId, true, 6, { from: voting }) - firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 7) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) assert.equals(+firstNodeOperatorKeysStats.exitedSigningKeysCount, 1) }) - it('_getNodeOperatorWithLimitApplied() - exited+target >= vetted', async () => { - let firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + it('_getNodeOperator() - exited+target >= vetted', async () => { + let firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) @@ -1547,14 +1622,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await app.updateTargetValidatorsLimits(firstNodeOperatorId, true, 1000, { from: voting }) - firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) assert.equals(+firstNodeOperatorKeysStats.exitedSigningKeysCount, 1) }) - it('_getNodeOperatorWithLimitApplied() - exited+target <= deposited', async () => { - let firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + it('_getNodeOperator() - exited+target <= deposited', async () => { + let firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) @@ -1562,7 +1637,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await app.updateTargetValidatorsLimits(firstNodeOperatorId, true, 4, { from: voting }) - firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals( +firstNodeOperatorKeysStats.maxSigningKeysCount, firstNodeOperatorKeysStats.depositedSigningKeysCount @@ -1964,7 +2039,8 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const keysToAllocate = 10 const keyIndex = NODE_OPERATORS[secondNodeOperatorId].depositedSigningKeysCount + 1 assert.isTrue(keyIndex <= NODE_OPERATORS[secondNodeOperatorId].totalSigningKeysCount) - const { depositedSigningKeysCount: depositedSigningKeysCountBefore } = await app.testing_getTotalSigningKeysStats() + const { depositedSigningKeysCount: depositedSigningKeysCountBefore } = + await app.testing_getTotalSigningKeysStats() await app.testing_obtainDepositData(keysToAllocate) const { depositedSigningKeysCount: depositedSigningKeysCountAfter } = await app.testing_getTotalSigningKeysStats() assert.equal(depositedSigningKeysCountAfter.toNumber(), depositedSigningKeysCountBefore.toNumber() + 4) @@ -2280,7 +2356,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('increases keysOpIndex & changes nonce', async () => { const [keysOpIndexBefore, nonceBefore] = await Promise.all([app.getKeysOpIndex(), app.getNonce()]) - await app.addSigningKeys(firstNodeOperatorId, firstNodeOperatorKeys.count, ...firstNodeOperatorKeys.slice(), { from: voting }) + await app.addSigningKeys(firstNodeOperatorId, firstNodeOperatorKeys.count, ...firstNodeOperatorKeys.slice(), { + from: voting + }) const [keysOpIndexAfter, nonceAfter] = await Promise.all([app.getKeysOpIndex(), app.getNonce()]) assert.equals(keysOpIndexAfter, keysOpIndexBefore.toNumber() + 1) assert.notEquals(nonceAfter, nonceBefore) @@ -2288,9 +2366,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits KeysOpIndexSet & NonceChanged', async () => { const keysOpIndexBefore = await app.getKeysOpIndex() - const receipt = await app.addSigningKeys(firstNodeOperatorId, firstNodeOperatorKeys.count, ...firstNodeOperatorKeys.slice(), { - from: voting - }) + const receipt = await app.addSigningKeys( + firstNodeOperatorId, + firstNodeOperatorKeys.count, + ...firstNodeOperatorKeys.slice(), + { + from: voting + } + ) const nonceAfter = await app.getNonce() assert.emits(receipt, 'KeysOpIndexSet', { keysOpIndex: keysOpIndexBefore.toNumber() + 1 }) assert.emits(receipt, 'NonceChanged', { nonce: nonceAfter }) @@ -2486,8 +2569,8 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const { isTargetLimitActive: isTargetLimitActiveBefore, targetValidatorsCount: targetValidatorsCountBefore, - excessValidatorsCount: excessValidatorsCountBefore, - } = await app.testing_getTotalTargetStats(); + excessValidatorsCount: excessValidatorsCountBefore + } = await app.testing_getTotalTargetStats() await app.removeSigningKey(secondNodeOperatorId, keyIndex, { from: voting }) @@ -2501,19 +2584,21 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const { isTargetLimitActive: isTargetLimitActiveAfter, targetValidatorsCount: targetValidatorsCountAfter, - excessValidatorsCount: excessValidatorsCountAfter, - } = await app.testing_getTotalTargetStats(); + excessValidatorsCount: excessValidatorsCountAfter + } = await app.testing_getTotalTargetStats() console.log({ targetValidatorsCountBefore: targetValidatorsCountBefore.toNumber(), targetValidatorsCountAfter: targetValidatorsCountAfter.toNumber(), - vettedSigningKeysCountBefore: vettedSigningKeysCountBefore.toNumber() , + vettedSigningKeysCountBefore: vettedSigningKeysCountBefore.toNumber(), vettedSigningKeysDecrement - }) assertBn(isTargetLimitActiveAfter, isTargetLimitActiveBefore) - assertBn(targetValidatorsCountAfter, targetValidatorsCountBefore.toNumber() - vettedSigningKeysCountBefore.toNumber() - vettedSigningKeysDecrement) + assertBn( + targetValidatorsCountAfter, + targetValidatorsCountBefore.toNumber() - vettedSigningKeysCountBefore.toNumber() - vettedSigningKeysDecrement + ) assertBn(excessValidatorsCountAfter, excessValidatorsCountBefore) }) From 9e333af98fa0234682811c269b8b2c3848e3b0f9 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 03:51:38 +0100 Subject: [PATCH 169/199] refactor: tests, events --- .../0.4.24/nos/NodeOperatorsRegistry.sol | 40 ++++++++-------- lib/abi/NodeOperatorsRegistry.json | 2 +- test/0.4.24/node-operators-registry.test.js | 46 ++++++++++--------- test/helpers/node-operators.js | 12 ++--- 4 files changed, 52 insertions(+), 48 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index ce28af1de..8b8a218bf 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -53,9 +53,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { event TotalSigningKeysCountChanged(uint256 indexed nodeOperatorId, uint256 totalValidatorsCount); event NonceChanged(uint256 nonce); - event StuckValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 stuckValidatorsCount); event StuckPenaltyDelayChanged(uint256 stuckPenaltyDelay); - event RefundedValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 RefundedValidatorsCount); + event StuckPenaltyStateChanged(uint256 indexed nodeOperatorId, uint256 stuckValidatorsCount, uint256 refundedValidatorsCount, uint256 stuckPenaltyEndTimestamp); event TargetValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 targetValidatorsCount); event NodeOperatorPenalized(address indexed recipientAddress, uint256 sharesPenalizedAmount); @@ -437,6 +436,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // see `onAllValidatorCountersUpdated()` } + + function _checkReportPayload(uint256 idsLength, uint256 countsLength) internal pure returns (uint256 count) { + count = idsLength / 8; + require(countsLength / 16 == count && idsLength % 8 == 0 && countsLength % 16 == 0, "INVALID_REPORT_DATA"); + } + /// @notice Called by StakingRouter to update the number of the validators of the given node /// operator that were requested to exit but failed to do so in the max allowed time /// @@ -444,10 +449,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// @param _stuckValidatorsCounts bytes packed array of the new number of stuck validators for the node operators function updateStuckValidatorsCount(bytes _nodeOperatorIds, bytes _stuckValidatorsCounts) external { _auth(STAKING_ROUTER_ROLE); - _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _stuckValidatorsCounts.length % 16 == 0); - - uint256 nodeOperatorsCount = _nodeOperatorIds.length / 8; - _requireValidReportData(_stuckValidatorsCounts.length / 16 == nodeOperatorsCount); + uint256 nodeOperatorsCount = _checkReportPayload(_nodeOperatorIds.length, _stuckValidatorsCounts.length); uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); uint256 nodeOperatorId; @@ -490,10 +492,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { external { _auth(STAKING_ROUTER_ROLE); - _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _exitedValidatorsCounts.length % 16 == 0); - - uint256 nodeOperatorsCount = _nodeOperatorIds.length / 8; - _requireValidReportData(_exitedValidatorsCounts.length / 16 == nodeOperatorsCount); + uint256 nodeOperatorsCount = _checkReportPayload(_nodeOperatorIds.length, _exitedValidatorsCounts.length); uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); uint256 nodeOperatorId; @@ -608,14 +607,19 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { if (_stuckValidatorsCount == stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET)) return; Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); - _requireValidRange(_stuckValidatorsCount <= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET)); + _requireValidRange(_stuckValidatorsCount <= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) - signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET)); stuckPenaltyStats.set(STUCK_VALIDATORS_COUNT_OFFSET, _stuckValidatorsCount); if (_stuckValidatorsCount <= stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET)) { stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, uint64(block.timestamp + getStuckPenaltyDelay())); } _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); - emit StuckValidatorsCountChanged(_nodeOperatorId, _stuckValidatorsCount); + emit StuckPenaltyStateChanged( + _nodeOperatorId, + _stuckValidatorsCount, + stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET), + stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) + ); _updateTotalMaxValidatorsCount(_nodeOperatorId); } @@ -632,8 +636,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, uint64(block.timestamp + getStuckPenaltyDelay())); } _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); - emit RefundedValidatorsCountChanged(_nodeOperatorId, _refundedValidatorsCount); - + emit StuckPenaltyStateChanged( + _nodeOperatorId, + stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET), + _refundedValidatorsCount, + stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) + ); _updateTotalMaxValidatorsCount(_nodeOperatorId); } @@ -1360,10 +1368,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { require(_pass, "OUT_OF_RANGE"); } - function _requireValidReportData(bool _pass) internal pure { - require(_pass, "INVALID_REPORT_DATA"); - } - function _onlyCorrectNodeOperatorState(bool _pass) internal pure { require(_pass, "WRONG_OPERATOR_ACTIVE_STATE"); } diff --git a/lib/abi/NodeOperatorsRegistry.json b/lib/abi/NodeOperatorsRegistry.json index a9f084984..231d6ea35 100644 --- a/lib/abi/NodeOperatorsRegistry.json +++ b/lib/abi/NodeOperatorsRegistry.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"},{"indexed":false,"name":"refundedValidatorsCount","type":"uint256"},{"indexed":false,"name":"stuckPenaltyEndTimestamp","type":"uint256"}],"name":"StuckPenaltyStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index 615503997..b428fc2ac 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -1194,23 +1194,23 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const firstNodeOperatorId = 0 const secondNodeOperatorId = 1 const notExistedNodeOperatorId = 2 - const exitedValidatorsCount = 4 + const exitedSigningKeysCount = 3 const stuckValidatorsCount = 2 beforeEach(async () => { - await nodeOperators.addNodeOperator(app, { ...NODE_OPERATORS[0], exitedSigningKeysCount: 4 }, { from: voting }) + await nodeOperators.addNodeOperator(app, { ...NODE_OPERATORS[0], exitedSigningKeysCount }, { from: voting }) await nodeOperators.addNodeOperator(app, NODE_OPERATORS[1], { from: voting }) }) it('decreases the stuck validators count when new value is less then previous one', async () => { const newStuckValidatorsCount = 1 - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsCount, stuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedSigningKeysCount, stuckValidatorsCount, { from: voting }) const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary(firstNodeOperatorId) assert(newStuckValidatorsCount < stuckValidatorsCountBefore) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsCount, newStuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedSigningKeysCount, newStuckValidatorsCount, { from: voting }) const { stuckValidatorsCount: stuckValidatorsCountAfter } = await app.getNodeOperatorSummary(firstNodeOperatorId) @@ -1223,22 +1223,22 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob secondNodeOperatorId ) assert(newStuckValidatorsCount > stuckValidatorsCountBefore) - await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, exitedValidatorsCount, newStuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, exitedSigningKeysCount, newStuckValidatorsCount, { from: voting }) const { stuckValidatorsCount: stuckValidatorsCountAfter } = await app.getNodeOperatorSummary(secondNodeOperatorId) assert.equals(stuckValidatorsCountAfter, newStuckValidatorsCount) }) - it('emits StuckValidatorsCountChanged event with correct params', async () => { - const newStuckValidatorsCount = 3 + it('emits StuckPenaltyStateChanged event with correct params', async () => { + const newStuckValidatorsCount = 2 const receipt = await app.unsafeUpdateValidatorsCount( firstNodeOperatorId, - exitedValidatorsCount, + exitedSigningKeysCount, newStuckValidatorsCount, { from: voting } ) - assert.emits(receipt, 'StuckValidatorsCountChanged', { + assert.emits(receipt, 'StuckPenaltyStateChanged', { nodeOperatorId: firstNodeOperatorId, stuckValidatorsCount: newStuckValidatorsCount }) @@ -1246,7 +1246,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it("doesn't change the state when new stuck validators value is equal to the previous one", async () => { const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary(firstNodeOperatorId) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsCount, stuckValidatorsCountBefore, { + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedSigningKeysCount, stuckValidatorsCountBefore, { from: voting }) @@ -1254,17 +1254,17 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals(stuckValidatorsCountBefore, stuckValidatorsCountAfter) }) - it("doesn't emit StuckValidatorsCountChanged event when new value is equal to the previous one", async () => { + it("doesn't emit StuckPenaltyStateChanged event when new value is equal to the previous one", async () => { const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary(firstNodeOperatorId) const receipt = await app.unsafeUpdateValidatorsCount( firstNodeOperatorId, - exitedValidatorsCount, + exitedSigningKeysCount, stuckValidatorsCountBefore, { from: voting } ) - assert.notEmits(receipt, 'StuckValidatorsCountChanged') + assert.notEmits(receipt, 'StuckPenaltyStateChanged') }) it("doesn't change the stuck validators count of other node operators", async () => { @@ -1272,7 +1272,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const { stuckValidatorsCount: secondNodeOperatorStuckValidatorsCountBefore } = await app.getNodeOperatorSummary( firstNodeOperatorId ) - await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, exitedValidatorsCount, newStuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, exitedSigningKeysCount, newStuckValidatorsCount, { from: voting }) const { stuckValidatorsCount: secondNodeOperatorStuckValidatorsCountAfter } = await app.getNodeOperatorSummary( @@ -1281,12 +1281,12 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals(secondNodeOperatorStuckValidatorsCountAfter, secondNodeOperatorStuckValidatorsCountBefore) }) - it('reverts with "OUT_OF_RANGE" error when new exitedValidatorsKeysCount < stuckValidatorsCount', async () => { + it('reverts with "OUT_OF_RANGE" error when new stuckValidatorsCount > depositedValidatorsKeysCount - exitedValidatorsKeysCount', async () => { const newStuckValidatorsCount = 1000 const { stuckValidatorsCount } = await app.getNodeOperatorSummary(firstNodeOperatorId) assert(newStuckValidatorsCount > stuckValidatorsCount) await assert.reverts( - app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsCount, newStuckValidatorsCount, { + app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedSigningKeysCount, newStuckValidatorsCount, { from: voting }), 'OUT_OF_RANGE' @@ -1358,13 +1358,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('decreases the exited validators count when new value is less then previous one', async () => { - const newExitedValidatorsCount = 2 + const newExitedValidatorsCount = 1 + const newStuckValidatorsCount = 0 const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator( firstNodeOperatorId, false ) assert(newExitedValidatorsCount < exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, newStuckValidatorsCount, { from: voting }) const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( @@ -1392,7 +1393,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('decreases the total exited signing keys count when new value is less then previous one', async () => { - const newExitedValidatorsCount = 3 + const newExitedValidatorsCount = 1 const [ { stoppedValidators: exitedValidatorsKeysCountBefore }, { exitedSigningKeysCount: exitedSigningKeysCountBefore } @@ -1414,6 +1415,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('increases the total exited signing keys count when new value is greater then previous one', async () => { const newExitedValidatorsCount = 5 + const newStuckValidatorsCount = 0 const [ { stoppedValidators: exitedValidatorsKeysCountBefore }, { exitedSigningKeysCount: exitedSigningKeysCountBefore } @@ -1422,7 +1424,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob app.testing_getTotalSigningKeysStats() ]) assert(newExitedValidatorsCount > exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, newStuckValidatorsCount, { from: voting }) const exitedSigningKeysCountIncrement = newExitedValidatorsCount - exitedValidatorsKeysCountBefore.toNumber() @@ -1436,13 +1438,13 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits ExitedSigningKeysCountChanged event with correct params', async () => { const newExitedValidatorsCount = 2 const receipt = await app.unsafeUpdateValidatorsCount( - firstNodeOperatorId, + secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting } ) assert.emits(receipt, 'ExitedSigningKeysCountChanged', { - nodeOperatorId: firstNodeOperatorId, + nodeOperatorId: secondNodeOperatorId, exitedValidatorsCount: newExitedValidatorsCount }) }) diff --git a/test/helpers/node-operators.js b/test/helpers/node-operators.js index a54c10f59..76dd4b44b 100644 --- a/test/helpers/node-operators.js +++ b/test/helpers/node-operators.js @@ -1,8 +1,7 @@ const hre = require('hardhat') -const { assert } = require('chai') const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') const { FakeValidatorKeys } = require('./signing-keys') -const { hex } = require('./utils') +const { prepIdsCountsPayload } = require('./utils') /*** * Adds new Node Operator to the registry and configures it @@ -45,8 +44,8 @@ async function addNodeOperator(registry, config, txOptions) { throw new Error('Invalid keys config: depositedSigningKeysCount < exitedSigningKeysCount') } - if (exitedSigningKeysCount < stuckValidatorsCount) { - throw new Error('Invalid keys config: exitedSigningKeysCount < stuckValidatorsCount') + if (stuckValidatorsCount > depositedSigningKeysCount - exitedSigningKeysCount) { + throw new Error('Invalid keys config: stuckValidatorsCount > depositedSigningKeysCount - exitedSigningKeysCount') } if (totalSigningKeysCount < exitedSigningKeysCount + depositedSigningKeysCount) { @@ -68,9 +67,8 @@ async function addNodeOperator(registry, config, txOptions) { } if (exitedSigningKeysCount > 0) { - const operatorIdsPayload = '0x' + [newOperatorId].map((id) => hex(id, 8)).join('') - const keysCountsPayload = '0x' + [exitedSigningKeysCount].map((count) => hex(count, 16)).join('') - await registry.updateExitedValidatorsCount(operatorIdsPayload, keysCountsPayload, txOptions) + const { operatorIds, keysCounts } = prepIdsCountsPayload(newOperatorId, exitedSigningKeysCount) + await registry.updateExitedValidatorsCount(operatorIds, keysCounts, txOptions) } if (!isActive) { From 43b9cb852df2802f918e626f5875e91e8d417bf0 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 09:29:03 +0100 Subject: [PATCH 170/199] feat: signing keys lib refactor --- contracts/0.4.24/lib/SigningKeys.sol | 175 ++++-------------- .../0.4.24/nos/NodeOperatorsRegistry.sol | 51 ++--- .../0.4.24/test_helpers/SiginigKyesMock.sol | 38 +++- test/0.4.24/node-operators-registry.test.js | 10 +- test/0.4.24/signingkey-lib.test.js | 58 +++++- test/helpers/staking-modules.js | 4 +- 6 files changed, 149 insertions(+), 187 deletions(-) diff --git a/contracts/0.4.24/lib/SigningKeys.sol b/contracts/0.4.24/lib/SigningKeys.sol index 793f68f89..346dbcbea 100644 --- a/contracts/0.4.24/lib/SigningKeys.sol +++ b/contracts/0.4.24/lib/SigningKeys.sol @@ -6,51 +6,44 @@ pragma solidity 0.4.24; import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol"; import {SafeMath64} from "@aragon/os/contracts/lib/math/SafeMath64.sol"; -// import {MemUtils} from "../../common/lib/MemUtils.sol"; - -import "hardhat/console.sol"; +/// @title Library for manage operator keys in storage +/// @author KRogLA library SigningKeys { using SafeMath for uint256; using SafeMath64 for uint64; - using SigningKeys for bytes32; uint64 internal constant PUBKEY_LENGTH = 48; uint64 internal constant SIGNATURE_LENGTH = 96; - uint256 internal constant UINT64_MAX = uint256(~uint64(0)); + uint256 internal constant UINT64_MAX = 0xFFFFFFFFFFFFFFFF; event SigningKeyAdded(uint256 indexed nodeOperatorId, bytes pubkey); event SigningKeyRemoved(uint256 indexed nodeOperatorId, bytes pubkey); - function isKeyEmpty(bytes memory _key) internal pure returns (bool) { - assert(_key.length == PUBKEY_LENGTH); - - uint256 k1; - uint256 k2; - assembly { - k1 := mload(add(_key, 0x20)) - k2 := mload(add(_key, 0x40)) - } - - return 0 == k1 && 0 == (k2 >> ((2 * 32 - PUBKEY_LENGTH) * 8)); - } - function getKeyOffset(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal pure returns (uint256) { return uint256(keccak256(abi.encodePacked(_position, _nodeOperatorId, _keyIndex))); } + /// @dev store opeartor keys to storage + /// @param _position storage slot + /// @param _nodeOperatorId operator id + /// @param _startIndex start index + /// @param _keysCount keys count to load + /// @param _pubkeys kes buffer to read from + /// @param _signatures signatures buffer to read from + /// @return new total keys count function saveKeysSigs( bytes32 _position, uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount, - bytes _publicKeys, + bytes _pubkeys, bytes _signatures ) internal returns (uint256) { require(_keysCount > 0 && _startIndex.add(_keysCount - 1) <= UINT64_MAX, "INVALID_KEYS_COUNT"); require( - _publicKeys.length == _keysCount.mul(PUBKEY_LENGTH) && _signatures.length == _keysCount.mul(SIGNATURE_LENGTH), + _pubkeys.length == _keysCount.mul(PUBKEY_LENGTH) && _signatures.length == _keysCount.mul(SIGNATURE_LENGTH), "LENGTH_MISMATCH" ); @@ -61,20 +54,10 @@ library SigningKeys { for (uint256 i; i < _keysCount;) { curOffset = _position.getKeyOffset(_nodeOperatorId, _startIndex); assembly { - let _ofs := add(add(_publicKeys, 0x20), mul(i, 48)) //PUBKEY_LENGTH = 48 + let _ofs := add(add(_pubkeys, 0x20), mul(i, 48)) //PUBKEY_LENGTH = 48 let _part1 := mload(_ofs) // bytes 0..31 let _part2 := mload(add(_ofs, 0x10)) // bytes 16..47 isEmpty := iszero(or(_part1, _part2)) - - /// @dev custom revert error - // if iszero(or(_part1, _part2)) { - // let ptrError := mload(0x40) - // mstore(ptrError, shl(224, 0x08c379a0)) // selector of `Error(string)` - // mstore(add(ptrError, 4), 0x20) // offset of the abi.encoded `string` - // mstore(add(ptrError, 0x24), 9) // error text length - // mstore(add(ptrError, 0x44), "EMPTY_KEY") // error text 0x454d5054595f4b4559 - // revert(ptrError, 0x64) // revert data length is 4 bytes for selector and 3 slots of 0x20 bytes - // } mstore(add(tmpKey, 0x30), _part2) // store 2nd part first mstore(add(tmpKey, 0x20), _part1) // store 1st part with overwrite bytes 16-31 } @@ -94,32 +77,35 @@ library SigningKeys { } emit SigningKeyAdded(_nodeOperatorId, tmpKey); } - return _startIndex; + return _startIndex; } + /// @dev remove opeartor keys from storage + /// @param _position storage slot + /// @param _nodeOperatorId operator id + /// @param _startIndex start index + /// @param _keysCount keys count to load + /// @param _totalKeysCount current total keys count for operator + /// @return new _totalKeysCount function removeKeysSigs( bytes32 _position, uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount, uint256 _totalKeysCount - ) internal { - require(_keysCount > 0 && _startIndex.add(_keysCount) <= _totalKeysCount && _totalKeysCount <= UINT64_MAX, "INVALID_KEYS_COUNT"); + ) internal returns (uint256) { + require( + _keysCount > 0 && _startIndex.add(_keysCount) <= _totalKeysCount && _totalKeysCount <= UINT64_MAX, + "INVALID_KEYS_COUNT" + ); uint256 curOffset; uint256 lastOffset; uint256 j; bytes memory tmpKey = new bytes(48); - - console.log("_nodeOperatorId", _nodeOperatorId); - console.log("_startIndex", _startIndex); - console.log("_keysCount", _keysCount); - console.log("_totalKeysCount", _totalKeysCount); - + // removing from the last index for (uint256 i = _startIndex + _keysCount; i > _startIndex;) { curOffset = _position.getKeyOffset(_nodeOperatorId, i - 1); - console.log("curOffset", curOffset); - assembly { // read key mstore(add(tmpKey, 0x30), shr(128, sload(add(curOffset, 1)))) // bytes 16..47 @@ -127,11 +113,7 @@ library SigningKeys { } if (i < _totalKeysCount) { lastOffset = _position.getKeyOffset(_nodeOperatorId, _totalKeysCount - 1); - assembly { - // read key - mstore(add(tmpKey, 0x30), shr(128, sload(add(lastOffset, 1)))) // bytes 16..47 - mstore(add(tmpKey, 0x20), sload(lastOffset)) // bytes 0..31 - } + // move last key to deleted key index for (j = 0; j < 5;) { assembly { sstore(add(curOffset, j), sload(add(lastOffset, j))) @@ -140,76 +122,30 @@ library SigningKeys { } curOffset = lastOffset; } + // clear storage for (j = 0; j < 5;) { assembly { sstore(add(curOffset, j), 0) j := add(j, 1) } } - assembly { _totalKeysCount := sub(_totalKeysCount, 1) i := sub(i, 1) } emit SigningKeyRemoved(_nodeOperatorId, tmpKey); - console.logBytes(tmpKey); } + return _totalKeysCount; } - // function removeUnusedKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _index, uint256 _lastIndex) - // internal - // returns (uint256) - // { - // (bytes memory removedKey,) = _position.loadKeySig(_nodeOperatorId, _index); - - // if (_index < _lastIndex) { - // (bytes memory key, bytes memory signature) = _position.loadKeySig(_nodeOperatorId, _lastIndex); - // _position.storeKeySig(_nodeOperatorId, _index, key, signature); - // } - - // _position.deleteKeySig(_nodeOperatorId, _lastIndex); - // emit SigningKeyRemoved(_nodeOperatorId, removedKey); - - // return _lastIndex; - // } - - // function storeKeySig( - // bytes32 _position, - // uint256 _nodeOperatorId, - // uint256 _keyIndex, - // bytes memory _pubkey, - // bytes memory _signature - // ) internal { - // // assert(_pubkey.length == PUBKEY_LENGTH); - // // assert(_signature.length == SIGNATURE_LENGTH); - - // // key - // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - // uint256 keyExcessBits = (2 * 32 - PUBKEY_LENGTH) * 8; - // assembly { - // sstore(offset, mload(add(_pubkey, 0x20))) - // sstore(add(offset, 1), shl(keyExcessBits, shr(keyExcessBits, mload(add(_pubkey, 0x40))))) - // } - // offset += 2; - - // // signature - // for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { - // assembly { - // sstore(offset, mload(add(_signature, add(0x20, i)))) - // } - // offset++; - // } - // } - - // function deleteKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal { - // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - // for (uint256 i = 0; i < (PUBKEY_LENGTH + SIGNATURE_LENGTH) / 32 + 1; ++i) { - // assembly { - // sstore(add(offset, i), 0) - // } - // } - // } - + /// @dev laod opeartor keys from storage + /// @param _position storage slot + /// @param _nodeOperatorId operator id + /// @param _startIndex start index + /// @param _keysCount keys count to load + /// @param _pubkeys preallocated kes buffer to read in + /// @param _signatures preallocated signatures buffer to read in + /// @param _bufOffset start offset in `_pubkeys`/`_signatures` buffer to place values (in number of keys) function loadKeysSigs( bytes32 _position, uint256 _nodeOperatorId, @@ -217,7 +153,7 @@ library SigningKeys { uint256 _keysCount, bytes memory _pubkeys, bytes memory _signatures, - uint256 _bufOffset // key offset inside _pubkeys/_signatures buffers + uint256 _bufOffset ) internal view { uint256 curOffset; for (uint256 i; i < _keysCount;) { @@ -237,36 +173,7 @@ library SigningKeys { } } - // function loadKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) - // internal - // view - // returns (bytes memory pubkey, bytes memory signature) - // { - // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - - // // key - // bytes memory tmpKey = MemUtils.unsafeAllocateBytes(64); - // assembly { - // mstore(add(tmpKey, 0x20), sload(offset)) - // mstore(add(tmpKey, 0x40), sload(add(offset, 1))) - // } - // offset += 2; - // pubkey = MemUtils.unsafeAllocateBytes(PUBKEY_LENGTH); - // MemUtils.copyBytes(tmpKey, pubkey, 0, 0, PUBKEY_LENGTH); - // // signature - // signature = MemUtils.unsafeAllocateBytes(SIGNATURE_LENGTH); - // for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { - // assembly { - // mstore(add(signature, add(0x20, i)), sload(offset)) - // } - // offset++; - // } - // } - function initKeysSigsBuf(uint256 _count) internal pure returns (bytes memory, bytes memory) { - return ( - new bytes(_count.mul(PUBKEY_LENGTH)), new bytes(_count.mul(SIGNATURE_LENGTH)) - // MemUtils.unsafeAllocateBytes(_count.mul(PUBKEY_LENGTH)), MemUtils.unsafeAllocateBytes(_count.mul(SIGNATURE_LENGTH)) - ); + return (new bytes(_count.mul(PUBKEY_LENGTH)), new bytes(_count.mul(SIGNATURE_LENGTH))); } } diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 66632e3c3..efd58af48 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -54,7 +54,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { event NonceChanged(uint256 nonce); event StuckPenaltyDelayChanged(uint256 stuckPenaltyDelay); - event StuckPenaltyStateChanged(uint256 indexed nodeOperatorId, uint256 stuckValidatorsCount, uint256 refundedValidatorsCount, uint256 stuckPenaltyEndTimestamp); + event StuckPenaltyStateChanged( + uint256 indexed nodeOperatorId, + uint256 stuckValidatorsCount, + uint256 refundedValidatorsCount, + uint256 stuckPenaltyEndTimestamp + ); event TargetValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 targetValidatorsCount); event NodeOperatorPenalized(address indexed recipientAddress, uint256 sharesPenalizedAmount); @@ -436,7 +441,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // see `onAllValidatorCountersUpdated()` } - function _checkReportPayload(uint256 idsLength, uint256 countsLength) internal pure returns (uint256 count) { count = idsLength / 8; require(countsLength / 16 == count && idsLength % 8 == 0 && countsLength % 16 == 0, "INVALID_REPORT_DATA"); @@ -527,8 +531,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { } /// @notice Called by StakingRouter after oracle finishes updating validators counters for all node operators - function onAllValidatorCountersUpdated() external - { + function onAllValidatorCountersUpdated() external { _auth(STAKING_ROUTER_ROLE); // for the permissioned module, we're distributing rewards within oracle operation // since the number of node ops won't be high and thus gas costs are limited @@ -607,7 +610,10 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { if (_stuckValidatorsCount == stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET)) return; Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); - _requireValidRange(_stuckValidatorsCount <= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) - signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET)); + _requireValidRange( + _stuckValidatorsCount + <= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) - signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET) + ); stuckPenaltyStats.set(STUCK_VALIDATORS_COUNT_OFFSET, _stuckValidatorsCount); if (_stuckValidatorsCount <= stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET)) { @@ -831,7 +837,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 loadedKeysCount = 0; uint64 depositedSigningKeysCountBefore; uint64 depositedSigningKeysCountAfter; - // uint256 keyIndex; uint256 keysCount; Packed64x4.Packed memory signingKeysStats; for (uint256 i; i < _nodeOperatorIds.length; ++i) { @@ -848,12 +853,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { ); loadedKeysCount += keysCount; - // for (keyIndex = depositedSigningKeysCountBefore; keyIndex < depositedSigningKeysCountAfter; ++keyIndex) { - // SIGNING_KEYS_MAPPING_NAME.loadKeysSigs( - // _nodeOperatorIds[i], keyIndex, loadedKeysCount, pubkeys, signatures - // ); - // ++loadedKeysCount; - // } emit DepositedSigningKeysCountChanged(_nodeOperatorIds[i], depositedSigningKeysCountAfter); signingKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, depositedSigningKeysCountAfter); _saveOperatorSigningKeysStats(_nodeOperatorIds[i], signingKeysStats); @@ -864,7 +863,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); summarySigningKeysStats.set( - SUMMARY_TOTAL_KEYS_COUNT_OFFSET, + SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET, summarySigningKeysStats.get(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET).add(uint64(loadedKeysCount)) ); _saveSummarySigningKeysStats(summarySigningKeysStats); @@ -985,9 +984,9 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _requireValidRange(totalSigningKeysCount.add(_keysCount) <= UINT64_MAX); - SIGNING_KEYS_MAPPING_NAME.saveKeysSigs(_nodeOperatorId, totalSigningKeysCount, _keysCount, _publicKeys, _signatures); + totalSigningKeysCount = + SIGNING_KEYS_MAPPING_NAME.saveKeysSigs(_nodeOperatorId, totalSigningKeysCount, _keysCount, _publicKeys, _signatures); - totalSigningKeysCount += _keysCount; emit TotalSigningKeysCountChanged(_nodeOperatorId, totalSigningKeysCount); signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, uint64(totalSigningKeysCount)); @@ -1045,19 +1044,13 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); uint256 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); - // uint256 _toIndex = _fromIndex.add(_keysCount); - // comapring _toIndex <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than MAX_UINT64 - _requireValidRange(_fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) && _fromIndex.add(_keysCount) <= totalSigningKeysCount); - - // removing from the last index to the highest one, so we won't get outside the array - - SIGNING_KEYS_MAPPING_NAME.removeKeysSigs(_nodeOperatorId, _fromIndex, _keysCount, totalSigningKeysCount); + _requireValidRange( + _fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) + && _fromIndex.add(_keysCount) <= totalSigningKeysCount + ); - // for (uint256 i = _toIndex; i > _fromIndex; --i) { - // totalSigningKeysCount = - // SIGNING_KEYS_MAPPING_NAME.removeUnusedKeySig(_nodeOperatorId, i - 1, totalSigningKeysCount.sub(1)); - // } - totalSigningKeysCount -= _keysCount; + totalSigningKeysCount = + SIGNING_KEYS_MAPPING_NAME.removeKeysSigs(_nodeOperatorId, _fromIndex, _keysCount, totalSigningKeysCount); signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, uint64(totalSigningKeysCount)); emit TotalSigningKeysCountChanged(_nodeOperatorId, totalSigningKeysCount); @@ -1137,10 +1130,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { for (uint256 i; i < _limit; ++i) { used[i] = (_offset + i) < depositedSigningKeysCount; } - // for (uint256 i; i < _limit; ++i) { - // SIGNING_KEYS_MAPPING_NAME.loadKeySigAndAppend(_nodeOperatorId, _offset + i, i, pubkeys, signatures); - // used[i] = (_offset + i) < depositedSigningKeysCount; - // } } /// @notice Returns the type of the staking module diff --git a/contracts/0.4.24/test_helpers/SiginigKyesMock.sol b/contracts/0.4.24/test_helpers/SiginigKyesMock.sol index 0b379e137..4b2da4ab8 100644 --- a/contracts/0.4.24/test_helpers/SiginigKyesMock.sol +++ b/contracts/0.4.24/test_helpers/SiginigKyesMock.sol @@ -33,13 +33,11 @@ contract SigningKeysMock { return KEYSSIGS_POSITION.saveKeysSigs(_nodeOperatorId, _startIndex, _keysCount, _publicKeys, _signatures); } - function removeKeysSigs( - uint256 _nodeOperatorId, - uint256 _startIndex, - uint256 _keysCount, - uint256 _lastIndex - ) external { - KEYSSIGS_POSITION.removeKeysSigs(_nodeOperatorId, _startIndex, _keysCount, _lastIndex); + function removeKeysSigs(uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount, uint256 _lastIndex) + external + returns (uint256) + { + return KEYSSIGS_POSITION.removeKeysSigs(_nodeOperatorId, _startIndex, _keysCount, _lastIndex); } function loadKeysSigs(uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount) @@ -57,4 +55,30 @@ contract SigningKeysMock { 0 // key offset inside _pubkeys/_signatures buffers ); } + + function loadKeysSigsBatch(uint256[] _nodeOpIds, uint256[] _startIndexes, uint256[] _keysCounts) + external + view + returns (bytes memory pubkeys, bytes memory signatures) + { + require(_nodeOpIds.length == _startIndexes.length && _startIndexes.length == _keysCounts.length, "LENGTH_MISMATCH"); + uint256 totalKeysCount; + uint256 i; + for (i = 0; i < _nodeOpIds.length; ++i) { + totalKeysCount += _keysCounts[i]; + } + (pubkeys, signatures) = SigningKeys.initKeysSigsBuf(totalKeysCount); + uint256 loadedKeysCount; + for (i = 0; i < _nodeOpIds.length; ++i) { + KEYSSIGS_POSITION.loadKeysSigs( + _nodeOpIds[i], + _startIndexes[i], + _keysCounts[i], + pubkeys, + signatures, + loadedKeysCount // key offset inside _pubkeys/_signatures buffers + ); + loadedKeysCount += _keysCounts[i]; + } + } } diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index b14b425d1..57d9b92e6 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -2464,7 +2464,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) }) - describe.only('removeSigningKey()', async () => { + describe('removeSigningKey()', async () => { const firstNodeOperatorId = 0 const secondNodeOperatorId = 1 const nonExistentNodeOperatorId = 3 @@ -2768,14 +2768,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob ) }) - it.only('emits SigningKeyRemoved event with correct params', async () => { + it('emits SigningKeyRemoved event with correct params', async () => { const keyIndex = NODE_OPERATORS[firstNodeOperatorId].depositedSigningKeysCount - assert.isTrue(keyIndex <= NODE_OPERATORS[firstNodeOperatorId].totalSigningKeysCount) + assert.isTrue(keyIndex < NODE_OPERATORS[firstNodeOperatorId].totalSigningKeysCount) const receipt = await app.removeSigningKey(firstNodeOperatorId, keyIndex, { from: voting }) - console.log('AAAA', { - keyIndex, - kkk: firstNodeOperatorKeys.slice() - }); assert.emits( receipt, 'SigningKeyRemoved', diff --git a/test/0.4.24/signingkey-lib.test.js b/test/0.4.24/signingkey-lib.test.js index 4d8adcc73..8f2e42990 100644 --- a/test/0.4.24/signingkey-lib.test.js +++ b/test/0.4.24/signingkey-lib.test.js @@ -168,6 +168,49 @@ contract('SigningKeys', ([appManager, voting, user1, user2, user3, nobody]) => { assert.equal(signatures, expectedSignature) } }) + + it('read keys batch correctly', async () => { + await app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + ...firstNodeOperatorKeys.slice() + ) + + await app.saveKeysSigs( + secondNodeOperatorId, + secondNodeOperatorStartIndex, + secondNodeOperatorKeys.count, + ...secondNodeOperatorKeys.slice() + ) + + const { pubkeys, signatures } = await app.loadKeysSigsBatch( + [secondNodeOperatorId, firstNodeOperatorId], + [secondNodeOperatorStartIndex + 2, firstNodeOperatorStartIndex + 1], + [secondNodeOperatorKeys.count - 4, firstNodeOperatorKeys.count - 2] + ) + + let expectedPublicKeys = '' + let expectedSignatures = '' + let startIndex = secondNodeOperatorStartIndex + 2 + let endIndex = startIndex + secondNodeOperatorKeys.count - 4 + for (let i = startIndex; i < endIndex; ++i) { + const [key, sig] = secondNodeOperatorKeys.get(i) + expectedPublicKeys += key.substring(2) + expectedSignatures += sig.substring(2) + } + + startIndex = firstNodeOperatorStartIndex + 1 + endIndex = startIndex + firstNodeOperatorKeys.count - 2 + for (let i = startIndex; i < endIndex; ++i) { + const [key, sig] = firstNodeOperatorKeys.get(i) + expectedPublicKeys += key.substring(2) + expectedSignatures += sig.substring(2) + } + + assert.equal(pubkeys, '0x' + expectedPublicKeys) + assert.equal(signatures, '0x' + expectedSignatures) + }) }) describe('removeKeysSigs()', async () => { @@ -211,12 +254,12 @@ contract('SigningKeys', ([appManager, voting, user1, user2, user3, nobody]) => { ) }) - it.only('emits SigningKeyAdded with correct params for every added key', async () => { + it('emits SigningKeyAdded with correct params for every added key', async () => { const receipt = await app.removeKeysSigs( firstNodeOperatorId, firstNodeOperatorStartIndex, firstNodeOperatorKeys.count, - firstNodeOperatorLastIndex + firstNodeOperatorKeys.count ) for (let i = firstNodeOperatorStartIndex; i < firstNodeOperatorKeys.count; ++i) { @@ -229,12 +272,12 @@ contract('SigningKeys', ([appManager, voting, user1, user2, user3, nobody]) => { } }) - it.only('removes keys correctly (clear storage)', async () => { + it('removes keys correctly (clear storage)', async () => { await app.removeKeysSigs( firstNodeOperatorId, firstNodeOperatorStartIndex, firstNodeOperatorKeys.count, - firstNodeOperatorLastIndex + firstNodeOperatorKeys.count ) for (let i = firstNodeOperatorStartIndex; i < firstNodeOperatorKeys.count; ++i) { @@ -244,9 +287,10 @@ contract('SigningKeys', ([appManager, voting, user1, user2, user3, nobody]) => { } }) - it.only('removes keys correctly (move last to deleted position)', async () => { - await app.removeKeysSigs(firstNodeOperatorId, 0, 1, firstNodeOperatorLastIndex) - const { pubkeys, signatures } = await app.loadKeysSigs(firstNodeOperatorId, 0, 1) + it('removes keys correctly (move last to deleted position)', async () => { + const keyIndex = 0 + await app.removeKeysSigs(firstNodeOperatorId, keyIndex, 1, firstNodeOperatorKeys.count) + const { pubkeys, signatures } = await app.loadKeysSigs(firstNodeOperatorId, keyIndex, 1) const [expectedPublicKey, expectedSignature] = firstNodeOperatorKeys.get(firstNodeOperatorLastIndex) assert.equal(pubkeys, expectedPublicKey) assert.equal(signatures, expectedSignature) diff --git a/test/helpers/staking-modules.js b/test/helpers/staking-modules.js index 85e08e404..a6b645266 100644 --- a/test/helpers/staking-modules.js +++ b/test/helpers/staking-modules.js @@ -2,6 +2,8 @@ const { newApp } = require('./dao') const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistry') const NodeOperatorsRegistryMock = artifacts.require('NodeOperatorsRegistryMock') +const PENALTY_DELAY = 2 * 24 * 60 * 60 // 2 days + async function setupNodeOperatorsRegistry({ dao, acl, lidoLocator, stakingRouter, voting, appManager }, mock = false) { const nodeOperatorsRegistryBase = mock ? await NodeOperatorsRegistryMock.new() : await NodeOperatorsRegistry.new() const name = 'node-operators-registry-' + Math.random().toString(36).slice(2, 6) @@ -16,7 +18,7 @@ async function setupNodeOperatorsRegistry({ dao, acl, lidoLocator, stakingRouter ? await NodeOperatorsRegistryMock.at(nodeOperatorsRegistryProxyAddress) : await NodeOperatorsRegistry.at(nodeOperatorsRegistryProxyAddress) - await nodeOperatorsRegistry.initialize(lidoLocator.address, '0x01') + await nodeOperatorsRegistry.initialize(lidoLocator.address, '0x01', PENALTY_DELAY) const [ NODE_OPERATOR_REGISTRY_MANAGE_SIGNING_KEYS, From ef4d11455c5479d9b8206af7f24849adc74c26ba Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 09:35:52 +0100 Subject: [PATCH 171/199] test: fix --- test/0.4.24/node-operators-registry-penalty.test.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/0.4.24/node-operators-registry-penalty.test.js b/test/0.4.24/node-operators-registry-penalty.test.js index 22a2a41ba..71e79b836 100644 --- a/test/0.4.24/node-operators-registry-penalty.test.js +++ b/test/0.4.24/node-operators-registry-penalty.test.js @@ -305,7 +305,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use await steth.setTotalPooledEther(ETH(100)) await steth.mintShares(app.address, ETH(10)) - //update [operator, exited, stuck] + // update [operator, exited, stuck] await app.unsafeUpdateValidatorsCount(firstNodeOperator, 1, 1, { from: voting }) await app.unsafeUpdateValidatorsCount(secondNodeOperator, 1, 0, { from: voting }) @@ -316,9 +316,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use await steth.setTotalPooledEther(ETH(100)) await steth.mintShares(app.address, ETH(10)) - //update [operator, exited, stuck] - await app.unsafeUpdateValidatorsCount(firstNodeOperator, 2, 2 , { from: voting }) - await app.unsafeUpdateValidatorsCount(secondNodeOperator, 3, 0 , { from: voting }) + // update [operator, exited, stuck] + await app.unsafeUpdateValidatorsCount(firstNodeOperator, 2, 1, { from: voting }) + await app.unsafeUpdateValidatorsCount(secondNodeOperator, 3, 0, { from: voting }) // perValidator = ETH(10) / 5 = 2 eth @@ -326,7 +326,6 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use // calls distributeRewards() inside receipt = await app.testing__distributeRewards({ from: voting }) - assert.emits(receipt, 'RewardsDistributed', { rewardAddress: user1, sharesAmount: ETH(1) }) assert.emits(receipt, 'RewardsDistributed', { rewardAddress: user2, sharesAmount: ETH(4*2) }) assert.notEmits(receipt, 'RewardsDistributed', { rewardAddress: user3, sharesAmount: 0 }) From 14a0cf085d054863ea08e5a12373f56724aeb953 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 09:59:58 +0100 Subject: [PATCH 172/199] fix: summary deposited counter --- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 8b8a218bf..99bc161b7 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -857,7 +857,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); summarySigningKeysStats.set( - SUMMARY_TOTAL_KEYS_COUNT_OFFSET, + SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET, summarySigningKeysStats.get(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET).add(uint64(loadedKeysCount)) ); _saveSummarySigningKeysStats(summarySigningKeysStats); From 68585ff1a8ef623d45d944fdfd9f5d4712daa679 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 10:29:14 +0100 Subject: [PATCH 173/199] fix: tests, update summary method rename --- .../0.4.24/nos/NodeOperatorsRegistry.sol | 28 +++++++++---------- .../NodeOperatorsRegistryMock.sol | 4 +-- .../node-operators-registry-penalty.test.js | 8 +++--- test/helpers/staking-modules.js | 4 ++- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 99bc161b7..47d9e4811 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -362,7 +362,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit VettedSigningKeysCountChanged(_nodeOperatorId, depositedSigningKeysCount); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } _increaseValidatorsKeysNonce(); } @@ -424,7 +424,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit VettedSigningKeysCountChanged(_nodeOperatorId, vettedSigningKeysCountAfter); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); } @@ -577,7 +577,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { ); _saveSummarySigningKeysStats(summarySigningKeysStats); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } } @@ -596,7 +596,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit TargetValidatorsCountChanged(_nodeOperatorId, _targetLimit); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } /** @@ -621,7 +621,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) ); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } function _updateRefundValidatorsKeysCount(uint256 _nodeOperatorId, uint64 _refundedValidatorsCount) internal { @@ -642,18 +642,18 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _refundedValidatorsCount, stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) ); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } - // upd op limits and totals - function _updateTotalMaxValidatorsCount(uint256 _nodeOperatorId) internal returns (int64 maxSigningKeysDelta) { + // @dev Recalculate and update the max validoator count for operator and summary stats + function _updateSummaryMaxValidatorsCount(uint256 _nodeOperatorId) internal returns (int64 maxSigningKeysDelta) { maxSigningKeysDelta = _applyNodeOperatorLimits(_nodeOperatorId); if (maxSigningKeysDelta != 0) { Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); summarySigningKeysStats.set( - VETTED_KEYS_COUNT_OFFSET, - uint64(int64(summarySigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET)) + maxSigningKeysDelta) + SUMMARY_MAX_VALIDATORS_COUNT_OFFSET, + uint64(int64(summarySigningKeysStats.get(SUMMARY_MAX_VALIDATORS_COUNT_OFFSET)) + maxSigningKeysDelta) ); _saveSummarySigningKeysStats(summarySigningKeysStats); } @@ -688,7 +688,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { signingKeysStats.set(VETTED_KEYS_COUNT_OFFSET, depositedSigningKeysCount); _saveOperatorSigningKeysStats(nodeOperatorId, signingKeysStats); - _updateTotalMaxValidatorsCount(nodeOperatorId); + _updateSummaryMaxValidatorsCount(nodeOperatorId); emit TotalSigningKeysCountChanged(nodeOperatorId, depositedSigningKeysCount); emit VettedSigningKeysCountChanged(nodeOperatorId, depositedSigningKeysCount); @@ -850,7 +850,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit DepositedSigningKeysCountChanged(_nodeOperatorIds[i], depositedSigningKeysCountAfter); signingKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, depositedSigningKeysCountAfter); _saveOperatorSigningKeysStats(_nodeOperatorIds[i], signingKeysStats); - _updateTotalMaxValidatorsCount(_nodeOperatorIds[i]); + _updateSummaryMaxValidatorsCount(_nodeOperatorIds[i]); } assert(loadedKeysCount == _keysCountToLoad); @@ -1065,7 +1065,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { summarySigningKeysStats.get(SUMMARY_TOTAL_KEYS_COUNT_OFFSET).sub(uint64(_keysCount)) ); _saveSummarySigningKeysStats(summarySigningKeysStats); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); } @@ -1211,7 +1211,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { ); stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, 0); _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } /// @notice Returns total number of node operators diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index 52a346143..dd2b0c35e 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -18,7 +18,7 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { ); _saveSummarySigningKeysStats(totalSigningKeysStats); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } function testing_markAllKeysDeposited() external { @@ -119,7 +119,7 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { stuckPenaltyStats.set(REFUNDED_VALIDATORS_COUNT_OFFSET, refundedValidatorsCount); stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, stuckPenaltyEndAt); _nodeOperators[_nodeOperatorId].stuckPenaltyStats = stuckPenaltyStats; - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } function testing_getTotalSigningKeysStats() diff --git a/test/0.4.24/node-operators-registry-penalty.test.js b/test/0.4.24/node-operators-registry-penalty.test.js index 22a2a41ba..c53298e99 100644 --- a/test/0.4.24/node-operators-registry-penalty.test.js +++ b/test/0.4.24/node-operators-registry-penalty.test.js @@ -305,7 +305,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use await steth.setTotalPooledEther(ETH(100)) await steth.mintShares(app.address, ETH(10)) - //update [operator, exited, stuck] + // update [operator, exited, stuck] await app.unsafeUpdateValidatorsCount(firstNodeOperator, 1, 1, { from: voting }) await app.unsafeUpdateValidatorsCount(secondNodeOperator, 1, 0, { from: voting }) @@ -316,9 +316,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use await steth.setTotalPooledEther(ETH(100)) await steth.mintShares(app.address, ETH(10)) - //update [operator, exited, stuck] - await app.unsafeUpdateValidatorsCount(firstNodeOperator, 2, 2 , { from: voting }) - await app.unsafeUpdateValidatorsCount(secondNodeOperator, 3, 0 , { from: voting }) + // update [operator, exited, stuck] + await app.unsafeUpdateValidatorsCount(firstNodeOperator, 2, 1, { from: voting }) + await app.unsafeUpdateValidatorsCount(secondNodeOperator, 3, 0, { from: voting }) // perValidator = ETH(10) / 5 = 2 eth diff --git a/test/helpers/staking-modules.js b/test/helpers/staking-modules.js index 85e08e404..a6b645266 100644 --- a/test/helpers/staking-modules.js +++ b/test/helpers/staking-modules.js @@ -2,6 +2,8 @@ const { newApp } = require('./dao') const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistry') const NodeOperatorsRegistryMock = artifacts.require('NodeOperatorsRegistryMock') +const PENALTY_DELAY = 2 * 24 * 60 * 60 // 2 days + async function setupNodeOperatorsRegistry({ dao, acl, lidoLocator, stakingRouter, voting, appManager }, mock = false) { const nodeOperatorsRegistryBase = mock ? await NodeOperatorsRegistryMock.new() : await NodeOperatorsRegistry.new() const name = 'node-operators-registry-' + Math.random().toString(36).slice(2, 6) @@ -16,7 +18,7 @@ async function setupNodeOperatorsRegistry({ dao, acl, lidoLocator, stakingRouter ? await NodeOperatorsRegistryMock.at(nodeOperatorsRegistryProxyAddress) : await NodeOperatorsRegistry.at(nodeOperatorsRegistryProxyAddress) - await nodeOperatorsRegistry.initialize(lidoLocator.address, '0x01') + await nodeOperatorsRegistry.initialize(lidoLocator.address, '0x01', PENALTY_DELAY) const [ NODE_OPERATOR_REGISTRY_MANAGE_SIGNING_KEYS, From 987e35c8520d4ee01c43b8b0bece57fdfc8b6a68 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 21 Feb 2023 12:48:23 +0200 Subject: [PATCH 174/199] =?UTF-8?q?=F0=9F=92=85:=20wq=20fomatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/0.8.9/WithdrawalQueueERC721.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueueERC721.sol b/contracts/0.8.9/WithdrawalQueueERC721.sol index 52c3b648a..5d95cdfd4 100644 --- a/contracts/0.8.9/WithdrawalQueueERC721.sol +++ b/contracts/0.8.9/WithdrawalQueueERC721.sol @@ -72,7 +72,7 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { public view virtual - override (IERC165, AccessControlEnumerable) + override(IERC165, AccessControlEnumerable) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId @@ -188,7 +188,9 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { if (_from != request.owner) revert TransferFromIncorrectOwner(_from, request.owner); // here and below we are sure that `_from` is the owner of the request address msgSender = msg.sender; - if (!(_from == msgSender || isApprovedForAll(_from, msgSender) || _getTokenApprovals()[_requestId] == msgSender)) revert NotOwnerOrApproved(msgSender); + if ( + !(_from == msgSender || isApprovedForAll(_from, msgSender) || _getTokenApprovals()[_requestId] == msgSender) + ) revert NotOwnerOrApproved(msgSender); delete _getTokenApprovals()[_requestId]; request.owner = payable(_to); From 44154d709f32fa64a6c897556cf8f0d0fbad3154 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 12:21:13 +0100 Subject: [PATCH 175/199] chore: comments --- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 47d9e4811..ee056142c 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -79,6 +79,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 internal constant UINT64_MAX = 0xFFFFFFFFFFFFFFFF; // SigningKeysStats + /// @dev Operator's max validator keys count approved for deposit by the DAO uint8 internal constant VETTED_KEYS_COUNT_OFFSET = 0; /// @dev Number of keys in the EXITED state for this operator for all time uint8 internal constant EXITED_KEYS_COUNT_OFFSET = 1; @@ -88,15 +89,10 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint8 internal constant DEPOSITED_KEYS_COUNT_OFFSET = 3; // TargetValidatorsStats - /// @dev DAO target limit, used to check how many keys should go to exit - /// UINT64_MAX - unlimited - /// 0 - all deposited keys - /// N < deposited keys - (deposited-N) keys - /// deposited < N < vetted - use (N-deposited) as available + /// @dev Flag enable/disable limiting target active validators count for operator uint8 internal constant IS_TARGET_LIMIT_ACTIVE_OFFSET = 0; - /// @dev relative target active validators limit for operator, set by DAO, UINT64_MAX === 'no limit' - /// @notice stores value +1 based, so 0 is means target count is unlimited (i.e. = -1), - /// and 1 is means target count = 0 (i.e. all validators should be exited) + /// @dev relative target active validators limit for operator, set by DAO + /// @notice used to check how many keys should go to exit, 0 - means all deposited keys would be exited uint8 internal constant TARGET_VALIDATORS_COUNT_OFFSET = 1; /// @dev actual operators's number of keys which could be deposited uint8 internal constant MAX_VALIDATORS_COUNT_OFFSET = 2; @@ -1183,11 +1179,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { depositableValidatorsCount = totalMaxValidators - totalDepositedValidators; } - // добавить в distributerewards вызов - - // комент по чтению calldata и смещениям - // передавать параметром penalty delay и эмитить событие - function _isOperatorPenalized(Packed64x4.Packed memory stuckPenaltyStats) internal view returns (bool) { return stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET) < stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET) || block.timestamp <= stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET); From a60d007deba35eba1af71f40517c076d16f7c9e7 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Mon, 20 Feb 2023 18:20:10 +0100 Subject: [PATCH 176/199] fix: nor test mock --- contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index a6e2519b3..2f74e6cb5 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -94,6 +94,10 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { operator.signingKeysStats = signingKeysStats; + Packed64x4.Packed memory operatorTargetStats; + operatorTargetStats.set(MAX_VALIDATORS_COUNT_OFFSET, vettedSigningKeysCount); + operator.targetValidatorsStats = operatorTargetStats; + emit NodeOperatorAdded(id, _name, _rewardAddress, 0); Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); @@ -115,7 +119,7 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { stuckPenaltyStats.set(REFUNDED_VALIDATORS_COUNT_OFFSET, refundedValidatorsCount); stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, stuckPenaltyEndAt); _nodeOperators[_nodeOperatorId].stuckPenaltyStats = stuckPenaltyStats; - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateTotalMaxValidatorsCount(_nodeOperatorId); } function testing_getTotalSigningKeysStats() From 87ceae0f17bff6da06d18c614b87c642f009c05c Mon Sep 17 00:00:00 2001 From: KRogLA Date: Mon, 20 Feb 2023 18:28:42 +0100 Subject: [PATCH 177/199] refactor: remove comments --- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 6 ------ 1 file changed, 6 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 8bb75897e..6766e6f8f 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -550,7 +550,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { ); _saveTotalSigningKeysStats(totalSigningKeysStats); - /// @todo optimize: reuse totalSigningKeysStats _updateTotalMaxValidatorsCount(_nodeOperatorId); } } @@ -715,7 +714,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint64 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); uint64 vettedSigningKeysCount = signingKeysStats.get(VETTED_KEYS_COUNT_OFFSET); - /// @todo check for MAX_VALIDATORS_COUNT_OFFSET < MAX_UINT64 - 1 uint64 oldMaxSigningKeysCount = operatorTargetStats.get(MAX_VALIDATORS_COUNT_OFFSET); uint64 newMaxSigningKeysCount = depositedSigningKeysCount; @@ -754,8 +752,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 depositedSigningKeysCount; uint256 exitedSigningKeysCount; - /// @todo check for MAX_VALIDATORS_COUNT_OFFSET < MAX_UINT64 - 1 - for (uint256 nodeOperatorId; nodeOperatorId < nodeOperatorsCount; ++nodeOperatorId) { (maxSigningKeysCount, exitedSigningKeysCount, depositedSigningKeysCount) = _getNodeOperatorWithLimitApplied(nodeOperatorId); @@ -1008,7 +1004,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // comparing _toIndex <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than MAX_UINT64 _requireValidRange(_fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) && _toIndex <= totalSigningKeysCount); - /// @todo: move to lib // removing from the last index to the highest one, so we won't get outside the array for (uint256 i = _toIndex; i > _fromIndex; --i) { totalSigningKeysCount = @@ -1031,7 +1026,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).sub(uint64(_keysCount)) ); _saveTotalSigningKeysStats(totalSigningKeysStats); - /// @todo optimize: reuse totalSigningKeysStats _updateTotalMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); From 16b226959d39b49e857896180e571909308b22ae Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 02:00:58 +0100 Subject: [PATCH 178/199] refactor: fixes, comments --- .../0.4.24/nos/NodeOperatorsRegistry.sol | 234 ++++++++++------- contracts/0.4.24/template/LidoTemplate.sol | 2 +- .../NodeOperatorsRegistryMock.sol | 12 +- lib/abi/NodeOperatorsRegistry.json | 2 +- .../node-operators-registry-penalty.test.js | 12 +- test/0.4.24/node-operators-registry.test.js | 248 ++++++++++++------ 6 files changed, 323 insertions(+), 187 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 6766e6f8f..2c1a2dfde 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -44,7 +44,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { event NodeOperatorRewardAddressSet(uint256 indexed nodeOperatorId, address rewardAddress); event NodeOperatorTotalKeysTrimmed(uint256 indexed nodeOperatorId, uint64 totalKeysTrimmed); event KeysOpIndexSet(uint256 keysOpIndex); - event ContractVersionSet(uint256 version); event StakingModuleTypeSet(bytes32 moduleType); event RewardsDistributed(address indexed rewardAddress, uint256 sharesAmount); event LocatorContractSet(address locatorAddress); @@ -55,6 +54,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { event NonceChanged(uint256 nonce); event StuckValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 stuckValidatorsCount); + event StuckPenaltyDelayChanged(uint256 stuckPenaltyDelay); event RefundedValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 RefundedValidatorsCount); event TargetValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 targetValidatorsCount); event NodeOperatorPenalized(address indexed recipientAddress, uint256 sharesPenalizedAmount); @@ -108,8 +108,22 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// @dev refunded keys count from dao uint8 internal constant REFUNDED_VALIDATORS_COUNT_OFFSET = 1; /// @dev extra penalty time after stuck keys resolved (refunded and/or exited) + /// @notice field is also used as flag for "half-cleaned" panlty status + /// Operator is PENALIZED if `STUCK_VALIDATORS_COUNT > REFUNDED_VALIDATORS_COUNT` or + /// `STUCK_VALIDATORS_COUNT <= REFUNDED_VALIDATORS_COUNT && STUCK_PENALTY_END_TIMESTAMP <= refund timastamp + STUCK_PENALTY_DELAY` + /// When operator refund all stuck validators and time has pass STUCK_PENALTY_DELAY, but STUCK_PENALTY_END_TIMESTAMP not zeroed, + /// then Operator can receive reawards but can't get new deposits until the new Oracle report or `clearNodeOperatorPenalty` is called. uint8 internal constant STUCK_PENALTY_END_TIMESTAMP_OFFSET = 2; + // Summary SigningKeysStats + uint8 internal constant SUMMARY_MAX_VALIDATORS_COUNT_OFFSET = 0; + /// @dev Number of keys in the EXITED state for this operator for all time + uint8 internal constant SUMMARY_EXITED_KEYS_COUNT_OFFSET = 1; + /// @dev Total number of keys of this operator for all time + uint8 internal constant SUMMARY_TOTAL_KEYS_COUNT_OFFSET = 2; + /// @dev Number of keys of this operator which were in DEPOSITED state for all time + uint8 internal constant SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET = 3; + // // UNSTRUCTURED STORAGE POSITIONS // @@ -175,9 +189,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { Packed64x4.Packed targetValidatorsStats; } - struct NodeOperatorTotals { - Packed64x4.Packed signingKeysStats; - // Packed64x4.Packed targetValidatorsStats; + struct NodeOperatorSummary { + Packed64x4.Packed summarySigningKeysStats; } // @@ -186,28 +199,28 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// @dev Mapping of all node operators. Mapping is used to be able to extend the struct. mapping(uint256 => NodeOperator) internal _nodeOperators; - NodeOperatorTotals internal _nodeOperatorTotals; + NodeOperatorSummary internal _nodeOperatorSummary; // // METHODS // - function initialize(address _locator, bytes32 _type) public onlyInit { + function initialize(address _locator, bytes32 _type, uint256 _stuckPenaltyDelay) public onlyInit { // Initializations for v1 --> v2 - _initialize_v2(_locator, _type); + _initialize_v2(_locator, _type, _stuckPenaltyDelay); initialized(); } /// @notice A function to finalize upgrade to v2 (from v1). Can be called only once /// For more details see https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-10.md - function finalizeUpgrade_v2(address _locator, bytes32 _type) external { - require(hasInitialized() && !isPetrified(), "CONTRACT_NOT_INITIALIZED_OR_PETRIFIED"); + function finalizeUpgrade_v2(address _locator, bytes32 _type, uint256 _stuckPenaltyDelay) external { + require(hasInitialized(), "CONTRACT_NOT_INITIALIZED"); _checkContractVersion(0); - _initialize_v2(_locator, _type); + _initialize_v2(_locator, _type, _stuckPenaltyDelay); uint256 totalOperators = getNodeOperatorsCount(); Packed64x4.Packed memory signingKeysStats; Packed64x4.Packed memory operatorTargetStats; - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); uint64 vettedSigningKeysCountBefore; uint64 totalSigningKeysCount; uint64 depositedSigningKeysCount; @@ -222,55 +235,62 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // trim vetted signing keys count when node operator is not active vettedSigningKeysCountAfter = depositedSigningKeysCount; } else { - vettedSigningKeysCountAfter = uint64(Math256.min(totalSigningKeysCount, Math256.max(uint256(depositedSigningKeysCount), uint256(vettedSigningKeysCountBefore)))); + vettedSigningKeysCountAfter = uint64( + Math256.min( + totalSigningKeysCount, + Math256.max(uint256(depositedSigningKeysCount), uint256(vettedSigningKeysCountBefore)) + ) + ); } if (vettedSigningKeysCountBefore != vettedSigningKeysCountAfter) { signingKeysStats.set(VETTED_KEYS_COUNT_OFFSET, vettedSigningKeysCountAfter); _saveOperatorSigningKeysStats(nodeOperatorId, signingKeysStats); - - operatorTargetStats = _loadOperatorTargetValidatorsStats(nodeOperatorId); - operatorTargetStats.set(MAX_VALIDATORS_COUNT_OFFSET, vettedSigningKeysCountAfter); - _saveOperatorTargetValidatorsStats(nodeOperatorId, operatorTargetStats); - emit VettedSigningKeysCountChanged(nodeOperatorId, vettedSigningKeysCountAfter); } - totalSigningKeysStats.set( - VETTED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET).add(vettedSigningKeysCountAfter) + operatorTargetStats = _loadOperatorTargetValidatorsStats(nodeOperatorId); + operatorTargetStats.set(MAX_VALIDATORS_COUNT_OFFSET, vettedSigningKeysCountAfter); + _saveOperatorTargetValidatorsStats(nodeOperatorId, operatorTargetStats); + + summarySigningKeysStats.set( + SUMMARY_MAX_VALIDATORS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_MAX_VALIDATORS_COUNT_OFFSET).add(vettedSigningKeysCountAfter) ); - totalSigningKeysStats.set( - DEPOSITED_KEYS_COUNT_OFFSET, - totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(depositedSigningKeysCount) + summarySigningKeysStats.set( + SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET).add(depositedSigningKeysCount) ); - totalSigningKeysStats.set( - EXITED_KEYS_COUNT_OFFSET, - totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET).add(signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET)) + summarySigningKeysStats.set( + SUMMARY_EXITED_KEYS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_EXITED_KEYS_COUNT_OFFSET).add( + signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET) + ) ); - totalSigningKeysStats.set( - TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).add(totalSigningKeysCount) + summarySigningKeysStats.set( + SUMMARY_TOTAL_KEYS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_TOTAL_KEYS_COUNT_OFFSET).add(totalSigningKeysCount) ); } - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); _increaseValidatorsKeysNonce(); } - function _initialize_v2(address _locator, bytes32 _type) internal { + function _initialize_v2(address _locator, bytes32 _type, uint256 _stuckPenaltyDelay) internal { _onlyNonZeroAddress(_locator); LIDO_LOCATOR_POSITION.setStorageAddress(_locator); TYPE_POSITION.setStorageBytes32(_type); _setContractVersion(2); - _setStuckPenaltyDelay(2 days); + _setStuckPenaltyDelay(_stuckPenaltyDelay); // set unlimited allowance for burner from staking router // to burn stuck keys penalized shares IStETH(getLocator().lido()).approve(getLocator().burner(), ~uint256(0)); - emit ContractVersionSet(2); emit LocatorContractSet(_locator); emit StakingModuleTypeSet(_type); } @@ -390,7 +410,11 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint64 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); uint64 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); - uint64 vettedSigningKeysCountAfter = uint64(Math256.min(totalSigningKeysCount, Math256.max(uint256(_vettedSigningKeysCount), uint256(depositedSigningKeysCount)))); + uint64 vettedSigningKeysCountAfter = uint64( + Math256.min( + totalSigningKeysCount, Math256.max(uint256(_vettedSigningKeysCount), uint256(depositedSigningKeysCount)) + ) + ); if (vettedSigningKeysCountAfter == vettedSigningKeysCountBefore) { return; @@ -418,12 +442,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// /// @param _nodeOperatorIds bytes packed array of the node operators id /// @param _stuckValidatorsCounts bytes packed array of the new number of stuck validators for the node operators - function updateStuckValidatorsCount( - bytes _nodeOperatorIds, - bytes _stuckValidatorsCounts - ) - external - { + function updateStuckValidatorsCount(bytes _nodeOperatorIds, bytes _stuckValidatorsCounts) external { _auth(STAKING_ROUTER_ROLE); _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _stuckValidatorsCounts.length % 16 == 0); @@ -435,11 +454,19 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint64 validatorsCount; uint256 _nodeOperatorIdsOffset; uint256 _stuckValidatorsCountsOffset; + + /// @dev calldata layout: + /// | func sig (4 bytes) | ABI-enc data | + /// + /// ABI-enc data: + /// + /// | 32 bytes | 32 bytes | 32 bytes | ... | 32 bytes | ...... | + /// | ids len offset | counts len offset | ids len | ids | counts len | counts | assembly { _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) - _stuckValidatorsCountsOffset := add(calldataload(36), 36) // signature_bytes4 + arg2_bytes calldata offset + 32 (length slot)) + _stuckValidatorsCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot)) } - for (uint256 i; i < nodeOperatorsCount; ) { + for (uint256 i; i < nodeOperatorsCount;) { /// @solidity memory-safe-assembly assembly { nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) @@ -455,33 +482,34 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// for node operator with given id /// /// @param _nodeOperatorIds bytes packed array of the node operators id - /// @param _stuckValidatorsCounts bytes packed array of the new number of EXITED validators for the node operators + /// @param _exitedValidatorsCounts bytes packed array of the new number of EXITED validators for the node operators function updateExitedValidatorsCount( bytes _nodeOperatorIds, - bytes _stuckValidatorsCounts + bytes _exitedValidatorsCounts ) external { _auth(STAKING_ROUTER_ROLE); - _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _stuckValidatorsCounts.length % 16 == 0); + _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _exitedValidatorsCounts.length % 16 == 0); uint256 nodeOperatorsCount = _nodeOperatorIds.length / 8; - _requireValidReportData(_stuckValidatorsCounts.length / 16 == nodeOperatorsCount); + _requireValidReportData(_exitedValidatorsCounts.length / 16 == nodeOperatorsCount); uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); uint256 nodeOperatorId; uint64 validatorsCount; uint256 _nodeOperatorIdsOffset; - uint256 _stuckValidatorsCountsOffset; + uint256 _exitedValidatorsCountsOffset; + /// @dev see comments for `updateStuckValidatorsCount` assembly { _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) - _stuckValidatorsCountsOffset := add(calldataload(36), 36) // signature_bytes4 + arg2_bytes calldata offset + 32 (length slot)) + _exitedValidatorsCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot)) } - for (uint256 i; i < nodeOperatorsCount; ) { + for (uint256 i; i < nodeOperatorsCount;) { /// @solidity memory-safe-assembly assembly { nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) - validatorsCount := shr(128, calldataload(add(_stuckValidatorsCountsOffset, mul(i, 16)))) + validatorsCount := shr(128, calldataload(add(_exitedValidatorsCountsOffset, mul(i, 16)))) i := add(i, 1) } _requireValidRange(nodeOperatorId < totalNodeOperatorsCount); @@ -521,7 +549,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _onlyExistedNodeOperator(_nodeOperatorId); _auth(STAKING_ROUTER_ROLE); - _updateExitedValidatorsCount(_nodeOperatorId, uint64(_exitedValidatorsCount), true /* _allowDecrease */); + _updateExitedValidatorsCount(_nodeOperatorId, uint64(_exitedValidatorsCount), true /* _allowDecrease */ ); _updateStuckValidatorsCount(_nodeOperatorId, uint64(_stuckValidatorsCount)); } @@ -543,12 +571,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit ExitedSigningKeysCountChanged(_nodeOperatorId, _exitedValidatorsKeysCount); // upd totals - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); - totalSigningKeysStats.set( - EXITED_KEYS_COUNT_OFFSET, - uint64(int64(totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET)) + totalExitedValidatorsDelta) + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); + summarySigningKeysStats.set( + SUMMARY_EXITED_KEYS_COUNT_OFFSET, + uint64(int64(summarySigningKeysStats.get(SUMMARY_EXITED_KEYS_COUNT_OFFSET)) + totalExitedValidatorsDelta) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); _updateTotalMaxValidatorsCount(_nodeOperatorId); } @@ -613,13 +641,13 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { function _updateTotalMaxValidatorsCount(uint256 _nodeOperatorId) internal returns (int64 maxSigningKeysDelta) { maxSigningKeysDelta = _applyNodeOperatorLimits(_nodeOperatorId); if (maxSigningKeysDelta != 0) { - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); - totalSigningKeysStats.set( + summarySigningKeysStats.set( VETTED_KEYS_COUNT_OFFSET, - uint64(int64(totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET)) + maxSigningKeysDelta) + uint64(int64(summarySigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET)) + maxSigningKeysDelta) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); } } @@ -693,7 +721,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _increaseValidatorsKeysNonce(); } - function _getNodeOperatorWithLimitApplied(uint256 _nodeOperatorId) + function _getNodeOperator(uint256 _nodeOperatorId) internal view returns (uint64 maxSigningKeysCount, uint64 exitedSigningKeysCount, uint64 depositedSigningKeysCount) @@ -717,7 +745,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint64 oldMaxSigningKeysCount = operatorTargetStats.get(MAX_VALIDATORS_COUNT_OFFSET); uint64 newMaxSigningKeysCount = depositedSigningKeysCount; - if (!isOperatorPenalized(_nodeOperatorId, true)) { + if (isOperatorPenaltyCleared(_nodeOperatorId)) { if (operatorTargetStats.get(IS_TARGET_LIMIT_ACTIVE_OFFSET) == 0) { newMaxSigningKeysCount = vettedSigningKeysCount; } else { @@ -753,8 +781,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 exitedSigningKeysCount; for (uint256 nodeOperatorId; nodeOperatorId < nodeOperatorsCount; ++nodeOperatorId) { - (maxSigningKeysCount, exitedSigningKeysCount, depositedSigningKeysCount) = - _getNodeOperatorWithLimitApplied(nodeOperatorId); + (maxSigningKeysCount, exitedSigningKeysCount, depositedSigningKeysCount) = _getNodeOperator(nodeOperatorId); // the node operator has no available signing keys if (depositedSigningKeysCount == maxSigningKeysCount) continue; @@ -817,11 +844,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { assert(loadedKeysCount == _keysCountToLoad); - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); - totalSigningKeysStats.set( - DEPOSITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(uint64(loadedKeysCount)) + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); + summarySigningKeysStats.set( + SUMMARY_TOTAL_KEYS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET).add(uint64(loadedKeysCount)) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); } /// @notice Returns the node operator by id @@ -883,7 +911,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { recipients[idx] = _nodeOperators[operatorId].rewardAddress; // prefill shares array with 'key share' for recipient, see below shares[idx] = activeValidatorsCount; - penalized[idx] = isOperatorPenalized(operatorId, false); + penalized[idx] = isOperatorPenalized(operatorId); ++idx; } @@ -939,7 +967,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _requireValidRange(totalSigningKeysCount.add(_keysCount) <= UINT64_MAX); - // totalSigningKeysCount = SIGNING_KEYS_MAPPING_NAME.addKeysSigs(_nodeOperatorId, _keysCount, totalSigningKeysCount, _publicKeys, _signatures); @@ -949,11 +976,11 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); // upd totals - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); - totalSigningKeysStats.set( - TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).add(uint64(_keysCount)) + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); + summarySigningKeysStats.set( + TOTAL_KEYS_COUNT_OFFSET, summarySigningKeysStats.get(SUMMARY_TOTAL_KEYS_COUNT_OFFSET).add(uint64(_keysCount)) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); _increaseValidatorsKeysNonce(); } @@ -1021,11 +1048,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); // upd totals - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); - totalSigningKeysStats.set( - TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).sub(uint64(_keysCount)) + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); + summarySigningKeysStats.set( + SUMMARY_TOTAL_KEYS_COUNT_OFFSET, + summarySigningKeysStats.get(SUMMARY_TOTAL_KEYS_COUNT_OFFSET).sub(uint64(_keysCount)) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(summarySigningKeysStats); _updateTotalMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); @@ -1099,13 +1127,16 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { view returns (uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount) { - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); - totalExitedValidators = totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET); - totalDepositedValidators = totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); - depositableValidatorsCount = totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET) - totalDepositedValidators; + Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); + totalExitedValidators = summarySigningKeysStats.get(SUMMARY_EXITED_KEYS_COUNT_OFFSET); + totalDepositedValidators = summarySigningKeysStats.get(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET); + depositableValidatorsCount = summarySigningKeysStats.get(SUMMARY_MAX_VALIDATORS_COUNT_OFFSET) - totalDepositedValidators; } - function getNodeOperatorSummary(uint256 _nodeOperatorId) external view returns ( + function getNodeOperatorSummary(uint256 _nodeOperatorId) + external + view + returns ( bool isTargetLimitActive, uint256 targetValidatorsCount, uint256 stuckValidatorsCount, @@ -1136,22 +1167,37 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 depositableValidatorsCount ) { uint256 totalMaxValidators; - (totalMaxValidators, totalExitedValidators, totalDepositedValidators) = - _getNodeOperatorWithLimitApplied(_nodeOperatorId); + (totalMaxValidators, totalExitedValidators, totalDepositedValidators) = _getNodeOperator(_nodeOperatorId); depositableValidatorsCount = totalMaxValidators - totalDepositedValidators; } - function isOperatorPenalized(uint256 _nodeOperatorId, bool _withClearedPenalty) public view returns (bool) { - Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); + // добавить в distributerewards вызов + + // комент по чтению calldata и смещениям + // передавать параметром penalty delay и эмитить событие + + function _isOperatorPenalized(Packed64x4.Packed memory stuckPenaltyStats) internal view returns (bool) { return stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET) < stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET) - || block.timestamp <= stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) - || (_withClearedPenalty && stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) != 0); + || block.timestamp <= stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET); + } + + function isOperatorPenalized(uint256 _nodeOperatorId) public view returns (bool) { + Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); + return _isOperatorPenalized(stuckPenaltyStats); } - function clearNodeOperatorPenalty(uint256 _nodeOperatorId) external returns (bool) { - require(!isOperatorPenalized(_nodeOperatorId, false), "CANT_CLEAR_PANLTY"); + function isOperatorPenaltyCleared(uint256 _nodeOperatorId) public view returns (bool) { Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); + return !_isOperatorPenalized(stuckPenaltyStats) && stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) == 0; + } + + function clearNodeOperatorPenalty(uint256 _nodeOperatorId) public returns (bool) { + Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); + require( + !_isOperatorPenalized(stuckPenaltyStats) && stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) != 0, + "CANT_CLEAR_PENALTY" + ); stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, 0); _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); _updateTotalMaxValidatorsCount(_nodeOperatorId); @@ -1253,8 +1299,10 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _setStuckPenaltyDelay(_delay); } + /// @dev set new stuck penalty delay, duration in sec function _setStuckPenaltyDelay(uint256 _delay) internal { STUCK_PENALTY_DELAY_POSITION.setStorageUint256(_delay); + emit StuckPenaltyDelayChanged(_delay); } function _increaseValidatorsKeysNonce() internal { @@ -1265,12 +1313,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit NonceChanged(keysOpIndex); } - function _loadTotalSigningKeysStats() internal view returns (Packed64x4.Packed memory) { - return _nodeOperatorTotals.signingKeysStats; + function _loadSummarySigningKeysStats() internal view returns (Packed64x4.Packed memory) { + return _nodeOperatorSummary.summarySigningKeysStats; } - function _saveTotalSigningKeysStats(Packed64x4.Packed memory _val) internal { - _nodeOperatorTotals.signingKeysStats = _val; + function _saveSummarySigningKeysStats(Packed64x4.Packed memory _val) internal { + _nodeOperatorSummary.summarySigningKeysStats = _val; } function _loadOperatorTargetValidatorsStats(uint256 _nodeOperatorId) internal view returns (Packed64x4.Packed memory) { diff --git a/contracts/0.4.24/template/LidoTemplate.sol b/contracts/0.4.24/template/LidoTemplate.sol index 7045fd720..4ca6bb5eb 100644 --- a/contracts/0.4.24/template/LidoTemplate.sol +++ b/contracts/0.4.24/template/LidoTemplate.sol @@ -328,7 +328,7 @@ contract LidoTemplate is IsContract { ); - state.operators.initialize(state.lido, bytes32(0x1)); + state.operators.initialize(state.lido, bytes32(0x1), 2 days); // used for issuing vested tokens in the next step _createTokenManagerPermissionsForTemplate(state.acl, state.tokenManager); diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index 2f74e6cb5..9f7defec7 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -12,11 +12,11 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { signingKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) + _keysCount); _nodeOperators[_nodeOperatorId].signingKeysStats = signingKeysStats; - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + Packed64x4.Packed memory totalSigningKeysStats = _loadSummarySigningKeysStats(); totalSigningKeysStats.set( DEPOSITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(_keysCount) ); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(totalSigningKeysStats); _updateTotalMaxValidatorsCount(_nodeOperatorId); } @@ -100,12 +100,12 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { emit NodeOperatorAdded(id, _name, _rewardAddress, 0); - Packed64x4.Packed memory totalSigningKeysStats = _loadTotalSigningKeysStats(); + Packed64x4.Packed memory totalSigningKeysStats = _loadSummarySigningKeysStats(); totalSigningKeysStats.set(VETTED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET).add(vettedSigningKeysCount)); totalSigningKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET).add(depositedSigningKeysCount)); totalSigningKeysStats.set(EXITED_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(EXITED_KEYS_COUNT_OFFSET).add(exitedSigningKeysCount)); totalSigningKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).add(totalSigningKeysCount)); - _saveTotalSigningKeysStats(totalSigningKeysStats); + _saveSummarySigningKeysStats(totalSigningKeysStats); } function testing_setNodeOperatorLimits( @@ -194,10 +194,10 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { return false; } - function testing_getNodeOperatorWithLimitApplied(uint256 operatorId) external view + function testing_getNodeOperator(uint256 operatorId) external view returns (uint64 maxSigningKeysCount, uint64 exitedSigningKeysCount, uint64 depositedSigningKeysCount) { - return _getNodeOperatorWithLimitApplied(operatorId); + return _getNodeOperator(operatorId); } event ValidatorsKeysLoaded(bytes publicKeys, bytes signatures); diff --git a/lib/abi/NodeOperatorsRegistry.json b/lib/abi/NodeOperatorsRegistry.json index 1aa817468..2792ce39d 100644 --- a/lib/abi/NodeOperatorsRegistry.json +++ b/lib/abi/NodeOperatorsRegistry.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_withClearedPenalty","type":"bool"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_withClearedPenalty","type":"bool"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] diff --git a/test/0.4.24/node-operators-registry-penalty.test.js b/test/0.4.24/node-operators-registry-penalty.test.js index 7871c474e..bc4fcfed1 100644 --- a/test/0.4.24/node-operators-registry-penalty.test.js +++ b/test/0.4.24/node-operators-registry-penalty.test.js @@ -63,6 +63,8 @@ const NODE_OPERATORS = [ // bytes32 0x63757261746564 const CURATED_TYPE = padRight(web3.utils.fromAscii('curated'), 32) +const PENALTY_DELAY = 2 * 24 * 60 * 60 // 2 days + const StETH = artifacts.require('StETHMock') contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, user4, no1, treasury]) => { @@ -74,9 +76,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use appBase = await NodeOperatorsRegistry.new() steth = await StETH.new({ value: ETH(1) }) - burner = await Burner.new( - voting, treasury, steth.address, bn(0), bn(0), { from: appManager } - ) + burner = await Burner.new(voting, treasury, steth.address, bn(0), bn(0), { from: appManager }) const locatorConfig = getRandomLocatorConfig({ lido: steth.address, @@ -108,15 +108,15 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use // app = await NodeOperatorsRegistry.at(proxyAddress) // Initialize the app's proxy. - const tx = await app.initialize(locator.address, CURATED_TYPE) + const tx = await app.initialize(locator.address, CURATED_TYPE, PENALTY_DELAY) //set stuck penalty voting - await app.setStuckPenaltyDelay(60*60*24*2, { from: voting }) + // await app.setStuckPenaltyDelay(PENALTY_DELAY, { from: voting }) // Implementation initializer reverts because initialization block was set to max(uint256) // in the Autopetrified base contract // await assert.reverts(appBase.initialize(steth.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') - await assert.reverts(appBase.initialize(locator.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') + await assert.reverts(appBase.initialize(locator.address, CURATED_TYPE, PENALTY_DELAY), 'INIT_ALREADY_INITIALIZED') const moduleType = await app.getType() assert.emits(tx, 'ContractVersionSet', { version: 2 }) diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index 55056f221..7b114dca7 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -61,6 +61,7 @@ const NODE_OPERATORS = [ // bytes32 0x63757261746564 const CURATED_TYPE = padRight(web3.utils.fromAscii('curated'), 32) +const PENALTY_DELAY = 2 * 24 * 60 * 60 // 2 days const pad = (hex, bytesLength) => { const absentZeroes = bytesLength * 2 + 2 - hex.length @@ -112,14 +113,17 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob // const proxyAddress = await newApp(newDAO.dao, 'node-operators-registry', appBase.address, appManager) // app = await NodeOperatorsRegistry.at(proxyAddress) - await assert.reverts(app.finalizeUpgrade_v2(locator.address, CURATED_TYPE), 'CONTRACT_NOT_INITIALIZED_OR_PETRIFIED') + await assert.reverts( + app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY), + 'CONTRACT_NOT_INITIALIZED' + ) // Initialize the app's proxy. - const tx = await app.initialize(locator.address, CURATED_TYPE) + const tx = await app.initialize(locator.address, CURATED_TYPE, PENALTY_DELAY) // Implementation initializer reverts because initialization block was set to max(uint256) // in the Autopetrified base contract - await assertRevert(appBase.initialize(locator.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') + await assertRevert(appBase.initialize(locator.address, CURATED_TYPE, PENALTY_DELAY), 'INIT_ALREADY_INITIALIZED') const moduleType = await app.getType() assert.emits(tx, 'ContractVersionSet', { version: 2 }) @@ -154,18 +158,18 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it("can't be initialized second time", async () => { - await assert.reverts(app.initialize(steth.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') + await assert.reverts(app.initialize(steth.address, CURATED_TYPE, PENALTY_DELAY), 'INIT_ALREADY_INITIALIZED') }) it('reverts with error "ZERO_ADDRESS" when stETH is zero address', async () => { const registry = await dao.newAppInstance({ name: 'new-node-operators-registry', base: appBase }) - await assert.reverts(registry.initialize(ZERO_ADDRESS, CURATED_TYPE), 'ZERO_ADDRESS') + await assert.reverts(registry.initialize(ZERO_ADDRESS, CURATED_TYPE, PENALTY_DELAY), 'ZERO_ADDRESS') }) it('call on implementation reverts with error "INIT_ALREADY_INITIALIZED"', async () => { // Implementation initializer reverts because initialization block was set to max(uint256) // in the Autopetrified base contract - await assert.reverts(appBase.initialize(steth.address, CURATED_TYPE), 'INIT_ALREADY_INITIALIZED') + await assert.reverts(appBase.initialize(steth.address, CURATED_TYPE, PENALTY_DELAY), 'INIT_ALREADY_INITIALIZED') }) }) @@ -175,22 +179,25 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await app.testing_setBaseVersion(0) }) - it('fails with PETRIFIED error when called on implementation', async () => { + it('fails with CONTRACT_NOT_INITIALIZED error when called on implementation', async () => { await assert.reverts( - appBase.finalizeUpgrade_v2(locator.address, CURATED_TYPE), - 'CONTRACT_NOT_INITIALIZED_OR_PETRIFIED' + appBase.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY), + 'CONTRACT_NOT_INITIALIZED' ) }) it('sets correct contract version', async () => { - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) assert.equals(await app.getContractVersion(), 2) }) it('reverts with error UNEXPECTED_CONTRACT_VERSION when called on already initialized contract', async () => { - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) assert.equals(await app.getContractVersion(), 2) - await assert.reverts(app.finalizeUpgrade_v2(locator.address, CURATED_TYPE), 'UNEXPECTED_CONTRACT_VERSION') + await assert.reverts( + app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY), + 'UNEXPECTED_CONTRACT_VERSION' + ) }) it('sets total signing keys stats correctly', async () => { @@ -228,7 +235,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals(nodeOperatorLimits.stuckPenaltyEndTimestamp.toNumber(), NODE_OPERATORS[i].stuckPenaltyEndAt) } - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) const totalSigningKeysStatsAfter = await app.testing_getTotalSigningKeysStats() @@ -279,7 +286,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals(nodeOperator.stakingLimit.toNumber(), config.vettedSigningKeysCount) assert.equals(nodeOperator.totalSigningKeys.toNumber(), config.totalSigningKeysCount) - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) nodeOperator = await app.getNodeOperator(0, false) assert.equals(nodeOperator.stakingLimit.toNumber(), config.totalSigningKeysCount) @@ -319,7 +326,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals(nodeOperator.stakingLimit.toNumber(), config.vettedSigningKeysCount) assert.equals(nodeOperator.totalSigningKeys.toNumber(), config.totalSigningKeysCount) - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) nodeOperator = await app.getNodeOperator(0, false) @@ -328,24 +335,24 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('emits ContractVersionSet event with correct params', async () => { - const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) assert.emits(receipt, 'ContractVersionSet', { version: 2 }) }) it('emits LocatorContractSet event with correct params', async () => { - const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) assert.emits(receipt, 'LocatorContractSet', { locatorAddress: locator.address }) }) it('emits StakingModuleTypeSet event with correct params', async () => { - const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) const moduleType = await app.getType() assert.emits(receipt, 'StakingModuleTypeSet', { moduleType }) }) it('increases keysOpIndex & changes nonce', async () => { const [keysOpIndexBefore, nonceBefore] = await Promise.all([app.getKeysOpIndex(), app.getNonce()]) - await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) const [keysOpIndexAfter, nonceAfter] = await Promise.all([app.getKeysOpIndex(), app.getNonce()]) assert.equals(keysOpIndexAfter, keysOpIndexBefore.toNumber() + 1) assert.notEquals(nonceAfter, nonceBefore) @@ -353,7 +360,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits KeysOpIndexSet & NonceChanged', async () => { const keysOpIndexBefore = await app.getKeysOpIndex() - const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE) + const receipt = await app.finalizeUpgrade_v2(locator.address, CURATED_TYPE, PENALTY_DELAY) const nonceAfter = await app.getNonce() assert.emits(receipt, 'KeysOpIndexSet', { keysOpIndex: keysOpIndexBefore.toNumber() + 1 }) assert.emits(receipt, 'NonceChanged', { nonce: nonceAfter }) @@ -689,7 +696,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob 'invariant failed: readyToDepositValidatorsKeysCountBefore <= depositedSigningKeysCount' ) assert.isTrue(nodeOperator.active, 'Invariant Failed: not active') - assert.isTrue(+operatorReportBefore.totalDepositedValidators > 0, 'Invariant Failed: vettedSigningKeysCount === 0') + assert.isTrue( + +operatorReportBefore.totalDepositedValidators > 0, + 'Invariant Failed: vettedSigningKeysCount === 0' + ) await app.deactivateNodeOperator(activeNodeOperatorId, { from: voting }) const [operatorReportAfter, allValidatorsReportAfter] = await Promise.all([ @@ -743,7 +753,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob ]) assert.equals(operatorReportBefore.totalDepositedValidators, operatorReportAfter.totalDepositedValidators) - assert.equals(allValidatorsReportBefore.totalDepositedValidators, allValidatorsReportAfter.totalDepositedValidators) + assert.equals( + allValidatorsReportBefore.totalDepositedValidators, + allValidatorsReportAfter.totalDepositedValidators + ) }) it('emits NodeOperatorActiveSet(deactivate) event with correct params', async () => { @@ -1073,19 +1086,31 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const hasPermission = await dao.hasPermission(nobody, app, 'STAKING_ROUTER_ROLE') assert.isFalse(hasPermission) const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, 40) - await assert.reverts(app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: nobody }), 'APP_AUTH_FAILED') + await assert.reverts( + app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: nobody }), + 'APP_AUTH_FAILED' + ) }) it("doesn't change the state when new value is equal to the previous one", async () => { - const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator(firstNodeOperatorId, false) + const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, exitedValidatorsKeysCountBefore) await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) - const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(firstNodeOperatorId, false) + const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) assert.equals(exitedValidatorsKeysCountBefore, exitedValidatorsKeysCountAfter) }) it("doesn't emit ExitedSigningKeysCountChanged event when new value is equal to the previous one", async () => { - const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator(firstNodeOperatorId, false) + const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) const { operatorIds, keysCounts } = prepIdsCountsPayload(firstNodeOperatorId, exitedValidatorsKeysCountBefore) const receipt = await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) assert.notEmits(receipt, 'ExitedSigningKeysCountChanged') @@ -1119,7 +1144,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.notEquals(exitedValidatorsKeysCountBefore, newExitedValidatorsCount) const { operatorIds, keysCounts } = prepIdsCountsPayload(secondNodeOperatorId, newExitedValidatorsCount) await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) - const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(secondNodeOperatorId, false) + const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( + secondNodeOperatorId, + false + ) assert.equals(exitedValidatorsKeysCountAfter, newExitedValidatorsCount) }) @@ -1154,7 +1182,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it("doesn't change the exited signing keys count of other node operators", async () => { const newExitedValidatorsCount = 4 - const { stakingLimit: secondNodeOperatorStakingLimitBefore } = await app.getNodeOperator(firstNodeOperatorId, true) + const { stakingLimit: secondNodeOperatorStakingLimitBefore } = await app.getNodeOperator( + firstNodeOperatorId, + true + ) const { operatorIds, keysCounts } = prepIdsCountsPayload(secondNodeOperatorId, newExitedValidatorsCount) await app.updateExitedValidatorsCount(operatorIds, keysCounts, { from: voting }) const { stakingLimit: secondNodeOperatorStakingLimitAfter } = await app.getNodeOperator(firstNodeOperatorId, true) @@ -1191,7 +1222,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('increases the stuck validators count when new value is greater then previous one', async () => { const newStuckValidatorsCount = 3 - const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary(secondNodeOperatorId) + const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary( + secondNodeOperatorId + ) assert(newStuckValidatorsCount > stuckValidatorsCountBefore) await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, exitedValidatorsCount, newStuckValidatorsCount, { from: voting @@ -1216,14 +1249,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it("doesn't change the state when new stuck validators value is equal to the previous one", async () => { const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary(firstNodeOperatorId) - await app.unsafeUpdateValidatorsCount( - firstNodeOperatorId, - exitedValidatorsCount, - stuckValidatorsCountBefore, - { - from: voting - } - ) + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsCount, stuckValidatorsCountBefore, { + from: voting + }) const { stuckValidatorsCount: stuckValidatorsCountAfter } = await app.getNodeOperatorSummary(firstNodeOperatorId) assert.equals(stuckValidatorsCountBefore, stuckValidatorsCountAfter) @@ -1280,21 +1308,43 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('reverts with "APP_AUTH_FAILED" error when called by sender without STAKING_ROUTER_ROLE', async () => { const hasPermission = await dao.hasPermission(nobody, app, 'STAKING_ROUTER_ROLE') assert.isFalse(hasPermission) - await assert.reverts(app.unsafeUpdateValidatorsCount(firstNodeOperatorId, 40, stuckValidatorsCount, { from: nobody }), 'APP_AUTH_FAILED') + await assert.reverts( + app.unsafeUpdateValidatorsCount(firstNodeOperatorId, 40, stuckValidatorsCount, { from: nobody }), + 'APP_AUTH_FAILED' + ) }) it("doesn't change the state when new value is equal to the previous one", async () => { - const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator(firstNodeOperatorId, false) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsKeysCountBefore, stuckValidatorsCount, { from: voting }) - const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(firstNodeOperatorId, false) + const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) + await app.unsafeUpdateValidatorsCount( + firstNodeOperatorId, + exitedValidatorsKeysCountBefore, + stuckValidatorsCount, + { from: voting } + ) + const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) assert.equals(exitedValidatorsKeysCountBefore, exitedValidatorsKeysCountAfter) }) it("doesn't emit ExitedSigningKeysCountChanged event when new value is equal to the previous one", async () => { - const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator(firstNodeOperatorId, false) - const receipt = await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsKeysCountBefore, stuckValidatorsCount, { - from: voting - }) + const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) + const receipt = await app.unsafeUpdateValidatorsCount( + firstNodeOperatorId, + exitedValidatorsKeysCountBefore, + stuckValidatorsCount, + { + from: voting + } + ) assert.notEmits(receipt, 'ExitedSigningKeysCountChanged') }) @@ -1303,7 +1353,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const nodeOperator = await app.getNodeOperator(firstNodeOperatorId, false) assert(newExitedValidatorsCount > nodeOperator.usedSigningKeys.toNumber()) await assert.reverts( - app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }), + app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }), 'OUT_OF_RANGE' ) }) @@ -1315,8 +1367,13 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob false ) assert(newExitedValidatorsCount < exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }) - const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(firstNodeOperatorId, false) + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }) + const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( + firstNodeOperatorId, + false + ) assert.equals(exitedValidatorsKeysCountAfter, newExitedValidatorsCount) }) @@ -1327,8 +1384,13 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob false ) assert(newExitedValidatorsCount > exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }) - const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator(secondNodeOperatorId, false) + await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }) + const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( + secondNodeOperatorId, + false + ) assert.equals(exitedValidatorsKeysCountAfter, newExitedValidatorsCount) }) @@ -1342,7 +1404,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob app.testing_getTotalSigningKeysStats() ]) assert(newExitedValidatorsCount < exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }) + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }) const exitedSigningKeysCountIncrement = exitedValidatorsKeysCountBefore.toNumber() - newExitedValidatorsCount const { exitedSigningKeysCount: exitedSigningKeysCountAfter } = await app.testing_getTotalSigningKeysStats() assert.equals( @@ -1361,7 +1425,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob app.testing_getTotalSigningKeysStats() ]) assert(newExitedValidatorsCount > exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }) + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }) const exitedSigningKeysCountIncrement = newExitedValidatorsCount - exitedValidatorsKeysCountBefore.toNumber() const { exitedSigningKeysCount: exitedSigningKeysCountAfter } = await app.testing_getTotalSigningKeysStats() assert.equals( @@ -1373,7 +1439,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits ExitedSigningKeysCountChanged event with correct params', async () => { const newExitedValidatorsCount = 2 const receipt = await app.unsafeUpdateValidatorsCount( - firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting } + firstNodeOperatorId, + newExitedValidatorsCount, + stuckValidatorsCount, + { from: voting } ) assert.emits(receipt, 'ExitedSigningKeysCountChanged', { nodeOperatorId: firstNodeOperatorId, @@ -1383,13 +1452,16 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it("doesn't change the exited signing keys count of other node operators", async () => { const newExitedValidatorsCount = 4 - const { stakingLimit: secondNodeOperatorStakingLimitBefore } = await app.getNodeOperator(firstNodeOperatorId, true) - await app.unsafeUpdateValidatorsCount( - secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting } + const { stakingLimit: secondNodeOperatorStakingLimitBefore } = await app.getNodeOperator( + firstNodeOperatorId, + true ) await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting }) + await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + from: voting + }) const { stakingLimit: secondNodeOperatorStakingLimitAfter } = await app.getNodeOperator(firstNodeOperatorId, true) assert.equals(secondNodeOperatorStakingLimitAfter, secondNodeOperatorStakingLimitBefore) }) @@ -1473,8 +1545,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('sets total vetted signing keys count & total signing keys count values to deposited signing keys count', async () => { const totalSigningKeysStatsBefore = await app.testing_getTotalSigningKeysStats() - assert.notEquals(totalSigningKeysStatsBefore.vettedSigningKeysCount, totalSigningKeysStatsBefore.depositedSigningKeysCount) - assert.notEquals(totalSigningKeysStatsBefore.totalSigningKeysCount, totalSigningKeysStatsBefore.depositedSigningKeysCount) + assert.notEquals( + totalSigningKeysStatsBefore.vettedSigningKeysCount, + totalSigningKeysStatsBefore.depositedSigningKeysCount + ) + assert.notEquals( + totalSigningKeysStatsBefore.totalSigningKeysCount, + totalSigningKeysStatsBefore.depositedSigningKeysCount + ) await app.onWithdrawalCredentialsChanged({ from: voting }) const totalSigningKeysStatsAfter = await app.testing_getTotalSigningKeysStats() assert.equals( @@ -1524,7 +1602,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('_getCorrectedNodeOperator() - deposited < exited+target < vetted', async () => { - let firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + let firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) @@ -1532,14 +1610,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await app.updateTargetValidatorsLimits(firstNodeOperatorId, true, 6, { from: voting }) - firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 7) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) assert.equals(+firstNodeOperatorKeysStats.exitedSigningKeysCount, 1) }) - it('_getNodeOperatorWithLimitApplied() - exited+target >= vetted', async () => { - let firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + it('_getNodeOperator() - exited+target >= vetted', async () => { + let firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) @@ -1547,14 +1625,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await app.updateTargetValidatorsLimits(firstNodeOperatorId, true, 1000, { from: voting }) - firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) assert.equals(+firstNodeOperatorKeysStats.exitedSigningKeysCount, 1) }) - it('_getNodeOperatorWithLimitApplied() - exited+target <= deposited', async () => { - let firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + it('_getNodeOperator() - exited+target <= deposited', async () => { + let firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals(+firstNodeOperatorKeysStats.maxSigningKeysCount, 8) assert.equals(+firstNodeOperatorKeysStats.depositedSigningKeysCount, 5) @@ -1562,7 +1640,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await app.updateTargetValidatorsLimits(firstNodeOperatorId, true, 4, { from: voting }) - firstNodeOperatorKeysStats = await app.testing_getNodeOperatorWithLimitApplied(firstNodeOperatorId) + firstNodeOperatorKeysStats = await app.testing_getNodeOperator(firstNodeOperatorId) assert.equals( +firstNodeOperatorKeysStats.maxSigningKeysCount, firstNodeOperatorKeysStats.depositedSigningKeysCount @@ -1963,7 +2041,8 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const { depositableValidatorsCount: keysToAllocate } = await app.getStakingModuleSummary() const keyIndex = NODE_OPERATORS[secondNodeOperatorId].depositedSigningKeysCount + 1 assert.isTrue(keyIndex <= NODE_OPERATORS[secondNodeOperatorId].totalSigningKeysCount) - const { depositedSigningKeysCount: depositedSigningKeysCountBefore } = await app.testing_getTotalSigningKeysStats() + const { depositedSigningKeysCount: depositedSigningKeysCountBefore } = + await app.testing_getTotalSigningKeysStats() await app.testing_obtainDepositData(keysToAllocate) const { depositedSigningKeysCount: depositedSigningKeysCountAfter } = await app.testing_getTotalSigningKeysStats() assert.equals(depositedSigningKeysCountAfter.toNumber(), depositedSigningKeysCountBefore.toNumber() + 4) @@ -2280,7 +2359,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('increases keysOpIndex & changes nonce', async () => { const [keysOpIndexBefore, nonceBefore] = await Promise.all([app.getKeysOpIndex(), app.getNonce()]) - await app.addSigningKeys(firstNodeOperatorId, firstNodeOperatorKeys.count, ...firstNodeOperatorKeys.slice(), { from: voting }) + await app.addSigningKeys(firstNodeOperatorId, firstNodeOperatorKeys.count, ...firstNodeOperatorKeys.slice(), { + from: voting + }) const [keysOpIndexAfter, nonceAfter] = await Promise.all([app.getKeysOpIndex(), app.getNonce()]) assert.equals(keysOpIndexAfter, keysOpIndexBefore.toNumber() + 1) assert.notEquals(nonceAfter, nonceBefore) @@ -2288,9 +2369,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits KeysOpIndexSet & NonceChanged', async () => { const keysOpIndexBefore = await app.getKeysOpIndex() - const receipt = await app.addSigningKeys(firstNodeOperatorId, firstNodeOperatorKeys.count, ...firstNodeOperatorKeys.slice(), { - from: voting - }) + const receipt = await app.addSigningKeys( + firstNodeOperatorId, + firstNodeOperatorKeys.count, + ...firstNodeOperatorKeys.slice(), + { + from: voting + } + ) const nonceAfter = await app.getNonce() assert.emits(receipt, 'KeysOpIndexSet', { keysOpIndex: keysOpIndexBefore.toNumber() + 1 }) assert.emits(receipt, 'NonceChanged', { nonce: nonceAfter }) @@ -2486,8 +2572,8 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const { isTargetLimitActive: isTargetLimitActiveBefore, targetValidatorsCount: targetValidatorsCountBefore, - excessValidatorsCount: excessValidatorsCountBefore, - } = await app.testing_getTotalTargetStats(); + excessValidatorsCount: excessValidatorsCountBefore + } = await app.testing_getTotalTargetStats() await app.removeSigningKey(secondNodeOperatorId, keyIndex, { from: voting }) @@ -2501,20 +2587,22 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const { isTargetLimitActive: isTargetLimitActiveAfter, targetValidatorsCount: targetValidatorsCountAfter, - excessValidatorsCount: excessValidatorsCountAfter, - } = await app.testing_getTotalTargetStats(); + excessValidatorsCount: excessValidatorsCountAfter + } = await app.testing_getTotalTargetStats() console.log({ targetValidatorsCountBefore: targetValidatorsCountBefore.toNumber(), targetValidatorsCountAfter: targetValidatorsCountAfter.toNumber(), - vettedSigningKeysCountBefore: vettedSigningKeysCountBefore.toNumber() , + vettedSigningKeysCountBefore: vettedSigningKeysCountBefore.toNumber(), vettedSigningKeysDecrement - }) - assert.equals(isTargetLimitActiveAfter, isTargetLimitActiveBefore) - assert.equals(targetValidatorsCountAfter, targetValidatorsCountBefore.toNumber() - vettedSigningKeysCountBefore.toNumber() - vettedSigningKeysDecrement) - assert.equals(excessValidatorsCountAfter, excessValidatorsCountBefore) + assertBn(isTargetLimitActiveAfter, isTargetLimitActiveBefore) + assertBn( + targetValidatorsCountAfter, + targetValidatorsCountBefore.toNumber() - vettedSigningKeysCountBefore.toNumber() - vettedSigningKeysDecrement + ) + assertBn(excessValidatorsCountAfter, excessValidatorsCountBefore) }) it("doesn't modify global vetted signing keys count if key index is equal to vettedSigningKeysCount", async () => { From 067411181f15d7dbe34b87467fcf2c9903e0ff32 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 03:51:38 +0100 Subject: [PATCH 179/199] refactor: tests, events --- .../0.4.24/nos/NodeOperatorsRegistry.sol | 40 ++++++++-------- lib/abi/NodeOperatorsRegistry.json | 2 +- test/0.4.24/node-operators-registry.test.js | 46 ++++++++++--------- test/helpers/node-operators.js | 12 ++--- 4 files changed, 52 insertions(+), 48 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 2c1a2dfde..1e9249382 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -53,9 +53,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { event TotalSigningKeysCountChanged(uint256 indexed nodeOperatorId, uint256 totalValidatorsCount); event NonceChanged(uint256 nonce); - event StuckValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 stuckValidatorsCount); event StuckPenaltyDelayChanged(uint256 stuckPenaltyDelay); - event RefundedValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 RefundedValidatorsCount); + event StuckPenaltyStateChanged(uint256 indexed nodeOperatorId, uint256 stuckValidatorsCount, uint256 refundedValidatorsCount, uint256 stuckPenaltyEndTimestamp); event TargetValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 targetValidatorsCount); event NodeOperatorPenalized(address indexed recipientAddress, uint256 sharesPenalizedAmount); @@ -437,6 +436,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // see `onAllValidatorCountersUpdated()` } + + function _checkReportPayload(uint256 idsLength, uint256 countsLength) internal pure returns (uint256 count) { + count = idsLength / 8; + require(countsLength / 16 == count && idsLength % 8 == 0 && countsLength % 16 == 0, "INVALID_REPORT_DATA"); + } + /// @notice Called by StakingRouter to update the number of the validators of the given node /// operator that were requested to exit but failed to do so in the max allowed time /// @@ -444,10 +449,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// @param _stuckValidatorsCounts bytes packed array of the new number of stuck validators for the node operators function updateStuckValidatorsCount(bytes _nodeOperatorIds, bytes _stuckValidatorsCounts) external { _auth(STAKING_ROUTER_ROLE); - _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _stuckValidatorsCounts.length % 16 == 0); - - uint256 nodeOperatorsCount = _nodeOperatorIds.length / 8; - _requireValidReportData(_stuckValidatorsCounts.length / 16 == nodeOperatorsCount); + uint256 nodeOperatorsCount = _checkReportPayload(_nodeOperatorIds.length, _stuckValidatorsCounts.length); uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); uint256 nodeOperatorId; @@ -490,10 +492,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { external { _auth(STAKING_ROUTER_ROLE); - _requireValidReportData(_nodeOperatorIds.length % 8 == 0 && _exitedValidatorsCounts.length % 16 == 0); - - uint256 nodeOperatorsCount = _nodeOperatorIds.length / 8; - _requireValidReportData(_exitedValidatorsCounts.length / 16 == nodeOperatorsCount); + uint256 nodeOperatorsCount = _checkReportPayload(_nodeOperatorIds.length, _exitedValidatorsCounts.length); uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); uint256 nodeOperatorId; @@ -608,14 +607,19 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { if (_stuckValidatorsCount == stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET)) return; Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); - _requireValidRange(_stuckValidatorsCount <= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET)); + _requireValidRange(_stuckValidatorsCount <= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) - signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET)); stuckPenaltyStats.set(STUCK_VALIDATORS_COUNT_OFFSET, _stuckValidatorsCount); if (_stuckValidatorsCount <= stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET)) { stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, uint64(block.timestamp + getStuckPenaltyDelay())); } _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); - emit StuckValidatorsCountChanged(_nodeOperatorId, _stuckValidatorsCount); + emit StuckPenaltyStateChanged( + _nodeOperatorId, + _stuckValidatorsCount, + stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET), + stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) + ); _updateTotalMaxValidatorsCount(_nodeOperatorId); } @@ -632,8 +636,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, uint64(block.timestamp + getStuckPenaltyDelay())); } _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); - emit RefundedValidatorsCountChanged(_nodeOperatorId, _refundedValidatorsCount); - + emit StuckPenaltyStateChanged( + _nodeOperatorId, + stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET), + _refundedValidatorsCount, + stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) + ); _updateTotalMaxValidatorsCount(_nodeOperatorId); } @@ -1357,10 +1365,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { require(_pass, "OUT_OF_RANGE"); } - function _requireValidReportData(bool _pass) internal pure { - require(_pass, "INVALID_REPORT_DATA"); - } - function _onlyCorrectNodeOperatorState(bool _pass) internal pure { require(_pass, "WRONG_OPERATOR_ACTIVE_STATE"); } diff --git a/lib/abi/NodeOperatorsRegistry.json b/lib/abi/NodeOperatorsRegistry.json index 2792ce39d..0c5d9263d 100644 --- a/lib/abi/NodeOperatorsRegistry.json +++ b/lib/abi/NodeOperatorsRegistry.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_withClearedPenalty","type":"bool"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"}],"name":"StuckValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"RefundedValidatorsCount","type":"uint256"}],"name":"RefundedValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"},{"indexed":false,"name":"refundedValidatorsCount","type":"uint256"},{"indexed":false,"name":"stuckPenaltyEndTimestamp","type":"uint256"}],"name":"StuckPenaltyStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index 7b114dca7..53f8c6027 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -1197,23 +1197,23 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const firstNodeOperatorId = 0 const secondNodeOperatorId = 1 const notExistedNodeOperatorId = 2 - const exitedValidatorsCount = 4 + const exitedSigningKeysCount = 3 const stuckValidatorsCount = 2 beforeEach(async () => { - await nodeOperators.addNodeOperator(app, { ...NODE_OPERATORS[0], exitedSigningKeysCount: 4 }, { from: voting }) + await nodeOperators.addNodeOperator(app, { ...NODE_OPERATORS[0], exitedSigningKeysCount }, { from: voting }) await nodeOperators.addNodeOperator(app, NODE_OPERATORS[1], { from: voting }) }) it('decreases the stuck validators count when new value is less then previous one', async () => { const newStuckValidatorsCount = 1 - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsCount, stuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedSigningKeysCount, stuckValidatorsCount, { from: voting }) const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary(firstNodeOperatorId) assert(newStuckValidatorsCount < stuckValidatorsCountBefore) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsCount, newStuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedSigningKeysCount, newStuckValidatorsCount, { from: voting }) const { stuckValidatorsCount: stuckValidatorsCountAfter } = await app.getNodeOperatorSummary(firstNodeOperatorId) @@ -1226,22 +1226,22 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob secondNodeOperatorId ) assert(newStuckValidatorsCount > stuckValidatorsCountBefore) - await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, exitedValidatorsCount, newStuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, exitedSigningKeysCount, newStuckValidatorsCount, { from: voting }) const { stuckValidatorsCount: stuckValidatorsCountAfter } = await app.getNodeOperatorSummary(secondNodeOperatorId) assert.equals(stuckValidatorsCountAfter, newStuckValidatorsCount) }) - it('emits StuckValidatorsCountChanged event with correct params', async () => { - const newStuckValidatorsCount = 3 + it('emits StuckPenaltyStateChanged event with correct params', async () => { + const newStuckValidatorsCount = 2 const receipt = await app.unsafeUpdateValidatorsCount( firstNodeOperatorId, - exitedValidatorsCount, + exitedSigningKeysCount, newStuckValidatorsCount, { from: voting } ) - assert.emits(receipt, 'StuckValidatorsCountChanged', { + assert.emits(receipt, 'StuckPenaltyStateChanged', { nodeOperatorId: firstNodeOperatorId, stuckValidatorsCount: newStuckValidatorsCount }) @@ -1249,7 +1249,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it("doesn't change the state when new stuck validators value is equal to the previous one", async () => { const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary(firstNodeOperatorId) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsCount, stuckValidatorsCountBefore, { + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedSigningKeysCount, stuckValidatorsCountBefore, { from: voting }) @@ -1257,17 +1257,17 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals(stuckValidatorsCountBefore, stuckValidatorsCountAfter) }) - it("doesn't emit StuckValidatorsCountChanged event when new value is equal to the previous one", async () => { + it("doesn't emit StuckPenaltyStateChanged event when new value is equal to the previous one", async () => { const { stuckValidatorsCount: stuckValidatorsCountBefore } = await app.getNodeOperatorSummary(firstNodeOperatorId) const receipt = await app.unsafeUpdateValidatorsCount( firstNodeOperatorId, - exitedValidatorsCount, + exitedSigningKeysCount, stuckValidatorsCountBefore, { from: voting } ) - assert.notEmits(receipt, 'StuckValidatorsCountChanged') + assert.notEmits(receipt, 'StuckPenaltyStateChanged') }) it("doesn't change the stuck validators count of other node operators", async () => { @@ -1275,7 +1275,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob const { stuckValidatorsCount: secondNodeOperatorStuckValidatorsCountBefore } = await app.getNodeOperatorSummary( firstNodeOperatorId ) - await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, exitedValidatorsCount, newStuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(secondNodeOperatorId, exitedSigningKeysCount, newStuckValidatorsCount, { from: voting }) const { stuckValidatorsCount: secondNodeOperatorStuckValidatorsCountAfter } = await app.getNodeOperatorSummary( @@ -1284,12 +1284,12 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob assert.equals(secondNodeOperatorStuckValidatorsCountAfter, secondNodeOperatorStuckValidatorsCountBefore) }) - it('reverts with "OUT_OF_RANGE" error when new exitedValidatorsKeysCount < stuckValidatorsCount', async () => { + it('reverts with "OUT_OF_RANGE" error when new stuckValidatorsCount > depositedValidatorsKeysCount - exitedValidatorsKeysCount', async () => { const newStuckValidatorsCount = 1000 const { stuckValidatorsCount } = await app.getNodeOperatorSummary(firstNodeOperatorId) assert(newStuckValidatorsCount > stuckValidatorsCount) await assert.reverts( - app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedValidatorsCount, newStuckValidatorsCount, { + app.unsafeUpdateValidatorsCount(firstNodeOperatorId, exitedSigningKeysCount, newStuckValidatorsCount, { from: voting }), 'OUT_OF_RANGE' @@ -1361,13 +1361,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('decreases the exited validators count when new value is less then previous one', async () => { - const newExitedValidatorsCount = 2 + const newExitedValidatorsCount = 1 + const newStuckValidatorsCount = 0 const { stoppedValidators: exitedValidatorsKeysCountBefore } = await app.getNodeOperator( firstNodeOperatorId, false ) assert(newExitedValidatorsCount < exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, newStuckValidatorsCount, { from: voting }) const { stoppedValidators: exitedValidatorsKeysCountAfter } = await app.getNodeOperator( @@ -1395,7 +1396,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('decreases the total exited signing keys count when new value is less then previous one', async () => { - const newExitedValidatorsCount = 3 + const newExitedValidatorsCount = 1 const [ { stoppedValidators: exitedValidatorsKeysCountBefore }, { exitedSigningKeysCount: exitedSigningKeysCountBefore } @@ -1417,6 +1418,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('increases the total exited signing keys count when new value is greater then previous one', async () => { const newExitedValidatorsCount = 5 + const newStuckValidatorsCount = 0 const [ { stoppedValidators: exitedValidatorsKeysCountBefore }, { exitedSigningKeysCount: exitedSigningKeysCountBefore } @@ -1425,7 +1427,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob app.testing_getTotalSigningKeysStats() ]) assert(newExitedValidatorsCount > exitedValidatorsKeysCountBefore.toNumber()) - await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { + await app.unsafeUpdateValidatorsCount(firstNodeOperatorId, newExitedValidatorsCount, newStuckValidatorsCount, { from: voting }) const exitedSigningKeysCountIncrement = newExitedValidatorsCount - exitedValidatorsKeysCountBefore.toNumber() @@ -1439,13 +1441,13 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob it('emits ExitedSigningKeysCountChanged event with correct params', async () => { const newExitedValidatorsCount = 2 const receipt = await app.unsafeUpdateValidatorsCount( - firstNodeOperatorId, + secondNodeOperatorId, newExitedValidatorsCount, stuckValidatorsCount, { from: voting } ) assert.emits(receipt, 'ExitedSigningKeysCountChanged', { - nodeOperatorId: firstNodeOperatorId, + nodeOperatorId: secondNodeOperatorId, exitedValidatorsCount: newExitedValidatorsCount }) }) diff --git a/test/helpers/node-operators.js b/test/helpers/node-operators.js index a54c10f59..76dd4b44b 100644 --- a/test/helpers/node-operators.js +++ b/test/helpers/node-operators.js @@ -1,8 +1,7 @@ const hre = require('hardhat') -const { assert } = require('chai') const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') const { FakeValidatorKeys } = require('./signing-keys') -const { hex } = require('./utils') +const { prepIdsCountsPayload } = require('./utils') /*** * Adds new Node Operator to the registry and configures it @@ -45,8 +44,8 @@ async function addNodeOperator(registry, config, txOptions) { throw new Error('Invalid keys config: depositedSigningKeysCount < exitedSigningKeysCount') } - if (exitedSigningKeysCount < stuckValidatorsCount) { - throw new Error('Invalid keys config: exitedSigningKeysCount < stuckValidatorsCount') + if (stuckValidatorsCount > depositedSigningKeysCount - exitedSigningKeysCount) { + throw new Error('Invalid keys config: stuckValidatorsCount > depositedSigningKeysCount - exitedSigningKeysCount') } if (totalSigningKeysCount < exitedSigningKeysCount + depositedSigningKeysCount) { @@ -68,9 +67,8 @@ async function addNodeOperator(registry, config, txOptions) { } if (exitedSigningKeysCount > 0) { - const operatorIdsPayload = '0x' + [newOperatorId].map((id) => hex(id, 8)).join('') - const keysCountsPayload = '0x' + [exitedSigningKeysCount].map((count) => hex(count, 16)).join('') - await registry.updateExitedValidatorsCount(operatorIdsPayload, keysCountsPayload, txOptions) + const { operatorIds, keysCounts } = prepIdsCountsPayload(newOperatorId, exitedSigningKeysCount) + await registry.updateExitedValidatorsCount(operatorIds, keysCounts, txOptions) } if (!isActive) { From a82063aa6bfc90167dbbc7b85236a9ddcca6dfb1 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 09:59:58 +0100 Subject: [PATCH 180/199] fix: summary deposited counter --- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 1e9249382..fb7a2afbe 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -854,7 +854,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); summarySigningKeysStats.set( - SUMMARY_TOTAL_KEYS_COUNT_OFFSET, + SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET, summarySigningKeysStats.get(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET).add(uint64(loadedKeysCount)) ); _saveSummarySigningKeysStats(summarySigningKeysStats); From c85c1065b735376febdd165683dc2085205d75e5 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 10:29:14 +0100 Subject: [PATCH 181/199] fix: tests, update summary method rename --- .../0.4.24/nos/NodeOperatorsRegistry.sol | 28 +++++++++---------- .../NodeOperatorsRegistryMock.sol | 4 +-- .../node-operators-registry-penalty.test.js | 8 +++--- test/helpers/staking-modules.js | 4 ++- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index fb7a2afbe..a51d27d3a 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -362,7 +362,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit VettedSigningKeysCountChanged(_nodeOperatorId, depositedSigningKeysCount); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } _increaseValidatorsKeysNonce(); } @@ -424,7 +424,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit VettedSigningKeysCountChanged(_nodeOperatorId, vettedSigningKeysCountAfter); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); } @@ -577,7 +577,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { ); _saveSummarySigningKeysStats(summarySigningKeysStats); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } } @@ -596,7 +596,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit TargetValidatorsCountChanged(_nodeOperatorId, _targetLimit); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } /** @@ -621,7 +621,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) ); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } function _updateRefundValidatorsKeysCount(uint256 _nodeOperatorId, uint64 _refundedValidatorsCount) internal { @@ -642,18 +642,18 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _refundedValidatorsCount, stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) ); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } - // upd op limits and totals - function _updateTotalMaxValidatorsCount(uint256 _nodeOperatorId) internal returns (int64 maxSigningKeysDelta) { + // @dev Recalculate and update the max validoator count for operator and summary stats + function _updateSummaryMaxValidatorsCount(uint256 _nodeOperatorId) internal returns (int64 maxSigningKeysDelta) { maxSigningKeysDelta = _applyNodeOperatorLimits(_nodeOperatorId); if (maxSigningKeysDelta != 0) { Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); summarySigningKeysStats.set( - VETTED_KEYS_COUNT_OFFSET, - uint64(int64(summarySigningKeysStats.get(VETTED_KEYS_COUNT_OFFSET)) + maxSigningKeysDelta) + SUMMARY_MAX_VALIDATORS_COUNT_OFFSET, + uint64(int64(summarySigningKeysStats.get(SUMMARY_MAX_VALIDATORS_COUNT_OFFSET)) + maxSigningKeysDelta) ); _saveSummarySigningKeysStats(summarySigningKeysStats); } @@ -688,7 +688,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { signingKeysStats.set(VETTED_KEYS_COUNT_OFFSET, depositedSigningKeysCount); _saveOperatorSigningKeysStats(nodeOperatorId, signingKeysStats); - _updateTotalMaxValidatorsCount(nodeOperatorId); + _updateSummaryMaxValidatorsCount(nodeOperatorId); emit TotalSigningKeysCountChanged(nodeOperatorId, depositedSigningKeysCount); emit VettedSigningKeysCountChanged(nodeOperatorId, depositedSigningKeysCount); @@ -847,7 +847,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { emit DepositedSigningKeysCountChanged(_nodeOperatorIds[i], depositedSigningKeysCountAfter); signingKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, depositedSigningKeysCountAfter); _saveOperatorSigningKeysStats(_nodeOperatorIds[i], signingKeysStats); - _updateTotalMaxValidatorsCount(_nodeOperatorIds[i]); + _updateSummaryMaxValidatorsCount(_nodeOperatorIds[i]); } assert(loadedKeysCount == _keysCountToLoad); @@ -1062,7 +1062,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { summarySigningKeysStats.get(SUMMARY_TOTAL_KEYS_COUNT_OFFSET).sub(uint64(_keysCount)) ); _saveSummarySigningKeysStats(summarySigningKeysStats); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); } @@ -1208,7 +1208,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { ); stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, 0); _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } /// @notice Returns total number of node operators diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index 9f7defec7..fd0f16126 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -18,7 +18,7 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { ); _saveSummarySigningKeysStats(totalSigningKeysStats); - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } function testing_markAllKeysDeposited() external { @@ -119,7 +119,7 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { stuckPenaltyStats.set(REFUNDED_VALIDATORS_COUNT_OFFSET, refundedValidatorsCount); stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, stuckPenaltyEndAt); _nodeOperators[_nodeOperatorId].stuckPenaltyStats = stuckPenaltyStats; - _updateTotalMaxValidatorsCount(_nodeOperatorId); + _updateSummaryMaxValidatorsCount(_nodeOperatorId); } function testing_getTotalSigningKeysStats() diff --git a/test/0.4.24/node-operators-registry-penalty.test.js b/test/0.4.24/node-operators-registry-penalty.test.js index bc4fcfed1..d5e272430 100644 --- a/test/0.4.24/node-operators-registry-penalty.test.js +++ b/test/0.4.24/node-operators-registry-penalty.test.js @@ -288,7 +288,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use await steth.setTotalPooledEther(ETH(100)) await steth.mintShares(app.address, ETH(10)) - //update [operator, exited, stuck] + // update [operator, exited, stuck] await app.unsafeUpdateValidatorsCount(firstNodeOperator, 1, 1, { from: voting }) await app.unsafeUpdateValidatorsCount(secondNodeOperator, 1, 0, { from: voting }) @@ -299,9 +299,9 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use await steth.setTotalPooledEther(ETH(100)) await steth.mintShares(app.address, ETH(10)) - //update [operator, exited, stuck] - await app.unsafeUpdateValidatorsCount(firstNodeOperator, 2, 2 , { from: voting }) - await app.unsafeUpdateValidatorsCount(secondNodeOperator, 3, 0 , { from: voting }) + // update [operator, exited, stuck] + await app.unsafeUpdateValidatorsCount(firstNodeOperator, 2, 1, { from: voting }) + await app.unsafeUpdateValidatorsCount(secondNodeOperator, 3, 0, { from: voting }) // perValidator = ETH(10) / 5 = 2 eth diff --git a/test/helpers/staking-modules.js b/test/helpers/staking-modules.js index 85e08e404..a6b645266 100644 --- a/test/helpers/staking-modules.js +++ b/test/helpers/staking-modules.js @@ -2,6 +2,8 @@ const { newApp } = require('./dao') const NodeOperatorsRegistry = artifacts.require('NodeOperatorsRegistry') const NodeOperatorsRegistryMock = artifacts.require('NodeOperatorsRegistryMock') +const PENALTY_DELAY = 2 * 24 * 60 * 60 // 2 days + async function setupNodeOperatorsRegistry({ dao, acl, lidoLocator, stakingRouter, voting, appManager }, mock = false) { const nodeOperatorsRegistryBase = mock ? await NodeOperatorsRegistryMock.new() : await NodeOperatorsRegistry.new() const name = 'node-operators-registry-' + Math.random().toString(36).slice(2, 6) @@ -16,7 +18,7 @@ async function setupNodeOperatorsRegistry({ dao, acl, lidoLocator, stakingRouter ? await NodeOperatorsRegistryMock.at(nodeOperatorsRegistryProxyAddress) : await NodeOperatorsRegistry.at(nodeOperatorsRegistryProxyAddress) - await nodeOperatorsRegistry.initialize(lidoLocator.address, '0x01') + await nodeOperatorsRegistry.initialize(lidoLocator.address, '0x01', PENALTY_DELAY) const [ NODE_OPERATOR_REGISTRY_MANAGE_SIGNING_KEYS, From 9afe1b248f339f6db6ee81c620f0e44272b346e1 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 12:21:13 +0100 Subject: [PATCH 182/199] chore: comments --- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index a51d27d3a..9d24a76e3 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -79,6 +79,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 internal constant UINT64_MAX = 0xFFFFFFFFFFFFFFFF; // SigningKeysStats + /// @dev Operator's max validator keys count approved for deposit by the DAO uint8 internal constant VETTED_KEYS_COUNT_OFFSET = 0; /// @dev Number of keys in the EXITED state for this operator for all time uint8 internal constant EXITED_KEYS_COUNT_OFFSET = 1; @@ -88,15 +89,10 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint8 internal constant DEPOSITED_KEYS_COUNT_OFFSET = 3; // TargetValidatorsStats - /// @dev DAO target limit, used to check how many keys should go to exit - /// UINT64_MAX - unlimited - /// 0 - all deposited keys - /// N < deposited keys - (deposited-N) keys - /// deposited < N < vetted - use (N-deposited) as available + /// @dev Flag enable/disable limiting target active validators count for operator uint8 internal constant IS_TARGET_LIMIT_ACTIVE_OFFSET = 0; - /// @dev relative target active validators limit for operator, set by DAO, UINT64_MAX === 'no limit' - /// @notice stores value +1 based, so 0 is means target count is unlimited (i.e. = -1), - /// and 1 is means target count = 0 (i.e. all validators should be exited) + /// @dev relative target active validators limit for operator, set by DAO + /// @notice used to check how many keys should go to exit, 0 - means all deposited keys would be exited uint8 internal constant TARGET_VALIDATORS_COUNT_OFFSET = 1; /// @dev actual operators's number of keys which could be deposited uint8 internal constant MAX_VALIDATORS_COUNT_OFFSET = 2; @@ -1180,11 +1176,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { depositableValidatorsCount = totalMaxValidators - totalDepositedValidators; } - // добавить в distributerewards вызов - - // комент по чтению calldata и смещениям - // передавать параметром penalty delay и эмитить событие - function _isOperatorPenalized(Packed64x4.Packed memory stuckPenaltyStats) internal view returns (bool) { return stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET) < stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET) || block.timestamp <= stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET); From 539a0faf33807d04444047d0905dce2b45260dfa Mon Sep 17 00:00:00 2001 From: KRogLA Date: Mon, 20 Feb 2023 18:04:05 +0100 Subject: [PATCH 183/199] refactor: sig keys lib --- contracts/0.4.24/lib/SigningKeys.sol | 290 ++++++++++++------ .../0.4.24/nos/NodeOperatorsRegistry.sol | 54 ++-- .../0.4.24/test_helpers/SiginigKyesMock.sol | 60 ++++ test/0.4.24/node-operators-registry.test.js | 20 +- test/0.4.24/signingkey-lib.test.js | 255 +++++++++++++++ test/helpers/signing-keys.js | 8 +- 6 files changed, 562 insertions(+), 125 deletions(-) create mode 100644 contracts/0.4.24/test_helpers/SiginigKyesMock.sol create mode 100644 test/0.4.24/signingkey-lib.test.js diff --git a/contracts/0.4.24/lib/SigningKeys.sol b/contracts/0.4.24/lib/SigningKeys.sol index b27d3a416..793f68f89 100644 --- a/contracts/0.4.24/lib/SigningKeys.sol +++ b/contracts/0.4.24/lib/SigningKeys.sol @@ -6,7 +6,9 @@ pragma solidity 0.4.24; import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol"; import {SafeMath64} from "@aragon/os/contracts/lib/math/SafeMath64.sol"; -import {MemUtils} from "../../common/lib/MemUtils.sol"; +// import {MemUtils} from "../../common/lib/MemUtils.sol"; + +import "hardhat/console.sol"; library SigningKeys { using SafeMath for uint256; @@ -34,137 +36,237 @@ library SigningKeys { return 0 == k1 && 0 == (k2 >> ((2 * 32 - PUBKEY_LENGTH) * 8)); } - function getKeyOffset(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) - internal - pure - returns (uint256) - { + function getKeyOffset(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal pure returns (uint256) { return uint256(keccak256(abi.encodePacked(_position, _nodeOperatorId, _keyIndex))); } - function addKeysSigs( + function saveKeysSigs( bytes32 _position, uint256 _nodeOperatorId, - uint256 _keysCount, uint256 _startIndex, + uint256 _keysCount, bytes _publicKeys, bytes _signatures ) internal returns (uint256) { - require(_keysCount != 0, "NO_KEYS"); - require(_keysCount <= UINT64_MAX, "KEYS_COUNT_TOO_LARGE"); - require(_publicKeys.length == _keysCount.mul(PUBKEY_LENGTH), "INVALID_LENGTH"); - require(_signatures.length == _keysCount.mul(SIGNATURE_LENGTH), "INVALID_LENGTH"); - - (bytes memory key, bytes memory sig) = initKeySig(1); - for (uint256 i = 0; i < _keysCount; ++i) { - MemUtils.copyBytes(_publicKeys, key, i * PUBKEY_LENGTH, 0, PUBKEY_LENGTH); - require(!isKeyEmpty(key), "EMPTY_KEY"); - MemUtils.copyBytes(_signatures, sig, i * SIGNATURE_LENGTH, 0, SIGNATURE_LENGTH); - - _position.storeKeySig(_nodeOperatorId, _startIndex, key, sig); - _startIndex = _startIndex.add(1); - emit SigningKeyAdded(_nodeOperatorId, key); - } - return _startIndex; - } + require(_keysCount > 0 && _startIndex.add(_keysCount - 1) <= UINT64_MAX, "INVALID_KEYS_COUNT"); + require( + _publicKeys.length == _keysCount.mul(PUBKEY_LENGTH) && _signatures.length == _keysCount.mul(SIGNATURE_LENGTH), + "LENGTH_MISMATCH" + ); - function removeUnusedKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _index, uint256 _lastIndex) - internal - returns (uint256) - { - (bytes memory removedKey,) = _position.loadKeySig(_nodeOperatorId, _index); + uint256 curOffset; + bool isEmpty; + bytes memory tmpKey = new bytes(48); - if (_index < _lastIndex) { - (bytes memory key, bytes memory signature) = _position.loadKeySig(_nodeOperatorId, _lastIndex); - _position.storeKeySig(_nodeOperatorId, _index, key, signature); - } + for (uint256 i; i < _keysCount;) { + curOffset = _position.getKeyOffset(_nodeOperatorId, _startIndex); + assembly { + let _ofs := add(add(_publicKeys, 0x20), mul(i, 48)) //PUBKEY_LENGTH = 48 + let _part1 := mload(_ofs) // bytes 0..31 + let _part2 := mload(add(_ofs, 0x10)) // bytes 16..47 + isEmpty := iszero(or(_part1, _part2)) - _position.deleteKeySig(_nodeOperatorId, _lastIndex); - emit SigningKeyRemoved(_nodeOperatorId, removedKey); + /// @dev custom revert error + // if iszero(or(_part1, _part2)) { + // let ptrError := mload(0x40) + // mstore(ptrError, shl(224, 0x08c379a0)) // selector of `Error(string)` + // mstore(add(ptrError, 4), 0x20) // offset of the abi.encoded `string` + // mstore(add(ptrError, 0x24), 9) // error text length + // mstore(add(ptrError, 0x44), "EMPTY_KEY") // error text 0x454d5054595f4b4559 + // revert(ptrError, 0x64) // revert data length is 4 bytes for selector and 3 slots of 0x20 bytes + // } + mstore(add(tmpKey, 0x30), _part2) // store 2nd part first + mstore(add(tmpKey, 0x20), _part1) // store 1st part with overwrite bytes 16-31 + } - return _lastIndex; + require(!isEmpty, "EMPTY_KEY"); + assembly { + // store key + sstore(curOffset, mload(add(tmpKey, 0x20))) // store bytes 0..31 + sstore(add(curOffset, 1), shl(128, mload(add(tmpKey, 0x30)))) // store bytes 32..47 + // store signature + let _ofs := add(add(_signatures, 0x20), mul(i, 96)) //SIGNATURE_LENGTH = 96 + sstore(add(curOffset, 2), mload(_ofs)) + sstore(add(curOffset, 3), mload(add(_ofs, 0x20))) + sstore(add(curOffset, 4), mload(add(_ofs, 0x40))) + i := add(i, 1) + _startIndex := add(_startIndex, 1) + } + emit SigningKeyAdded(_nodeOperatorId, tmpKey); + } + return _startIndex; } - function storeKeySig( + function removeKeysSigs( bytes32 _position, uint256 _nodeOperatorId, - uint256 _keyIndex, - bytes memory _pubkey, - bytes memory _signature + uint256 _startIndex, + uint256 _keysCount, + uint256 _totalKeysCount ) internal { - // assert(_pubkey.length == PUBKEY_LENGTH); - // assert(_signature.length == SIGNATURE_LENGTH); + require(_keysCount > 0 && _startIndex.add(_keysCount) <= _totalKeysCount && _totalKeysCount <= UINT64_MAX, "INVALID_KEYS_COUNT"); - // key - uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - uint256 keyExcessBits = (2 * 32 - PUBKEY_LENGTH) * 8; - assembly { - sstore(offset, mload(add(_pubkey, 0x20))) - sstore(add(offset, 1), shl(keyExcessBits, shr(keyExcessBits, mload(add(_pubkey, 0x40))))) - } - offset += 2; + uint256 curOffset; + uint256 lastOffset; + uint256 j; + bytes memory tmpKey = new bytes(48); + + console.log("_nodeOperatorId", _nodeOperatorId); + console.log("_startIndex", _startIndex); + console.log("_keysCount", _keysCount); + console.log("_totalKeysCount", _totalKeysCount); + + for (uint256 i = _startIndex + _keysCount; i > _startIndex;) { + curOffset = _position.getKeyOffset(_nodeOperatorId, i - 1); + console.log("curOffset", curOffset); - // signature - for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { assembly { - sstore(offset, mload(add(_signature, add(0x20, i)))) + // read key + mstore(add(tmpKey, 0x30), shr(128, sload(add(curOffset, 1)))) // bytes 16..47 + mstore(add(tmpKey, 0x20), sload(curOffset)) // bytes 0..31 + } + if (i < _totalKeysCount) { + lastOffset = _position.getKeyOffset(_nodeOperatorId, _totalKeysCount - 1); + assembly { + // read key + mstore(add(tmpKey, 0x30), shr(128, sload(add(lastOffset, 1)))) // bytes 16..47 + mstore(add(tmpKey, 0x20), sload(lastOffset)) // bytes 0..31 + } + for (j = 0; j < 5;) { + assembly { + sstore(add(curOffset, j), sload(add(lastOffset, j))) + j := add(j, 1) + } + } + curOffset = lastOffset; + } + for (j = 0; j < 5;) { + assembly { + sstore(add(curOffset, j), 0) + j := add(j, 1) + } } - offset++; - } - } - function deleteKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal { - uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - for (uint256 i = 0; i < (PUBKEY_LENGTH + SIGNATURE_LENGTH) / 32 + 1; ++i) { assembly { - sstore(add(offset, i), 0) + _totalKeysCount := sub(_totalKeysCount, 1) + i := sub(i, 1) } + emit SigningKeyRemoved(_nodeOperatorId, tmpKey); + console.logBytes(tmpKey); } } - function loadKeySigAndAppend( + // function removeUnusedKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _index, uint256 _lastIndex) + // internal + // returns (uint256) + // { + // (bytes memory removedKey,) = _position.loadKeySig(_nodeOperatorId, _index); + + // if (_index < _lastIndex) { + // (bytes memory key, bytes memory signature) = _position.loadKeySig(_nodeOperatorId, _lastIndex); + // _position.storeKeySig(_nodeOperatorId, _index, key, signature); + // } + + // _position.deleteKeySig(_nodeOperatorId, _lastIndex); + // emit SigningKeyRemoved(_nodeOperatorId, removedKey); + + // return _lastIndex; + // } + + // function storeKeySig( + // bytes32 _position, + // uint256 _nodeOperatorId, + // uint256 _keyIndex, + // bytes memory _pubkey, + // bytes memory _signature + // ) internal { + // // assert(_pubkey.length == PUBKEY_LENGTH); + // // assert(_signature.length == SIGNATURE_LENGTH); + + // // key + // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); + // uint256 keyExcessBits = (2 * 32 - PUBKEY_LENGTH) * 8; + // assembly { + // sstore(offset, mload(add(_pubkey, 0x20))) + // sstore(add(offset, 1), shl(keyExcessBits, shr(keyExcessBits, mload(add(_pubkey, 0x40))))) + // } + // offset += 2; + + // // signature + // for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { + // assembly { + // sstore(offset, mload(add(_signature, add(0x20, i)))) + // } + // offset++; + // } + // } + + // function deleteKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal { + // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); + // for (uint256 i = 0; i < (PUBKEY_LENGTH + SIGNATURE_LENGTH) / 32 + 1; ++i) { + // assembly { + // sstore(add(offset, i), 0) + // } + // } + // } + + function loadKeysSigs( bytes32 _position, uint256 _nodeOperatorId, - uint256 _keyIndex, - uint256 _offset, + uint256 _startIndex, + uint256 _keysCount, bytes memory _pubkeys, - bytes memory _signatures + bytes memory _signatures, + uint256 _bufOffset // key offset inside _pubkeys/_signatures buffers ) internal view { - (bytes memory pubkey, bytes memory signature) = _position.loadKeySig(_nodeOperatorId, _keyIndex); - MemUtils.copyBytes(pubkey, _pubkeys, _offset.mul(PUBKEY_LENGTH)); - MemUtils.copyBytes(signature, _signatures, _offset.mul(SIGNATURE_LENGTH)); - } - - function loadKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) - internal - view - returns (bytes memory pubkey, bytes memory signature) - { - uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - - // key - bytes memory tmpKey = MemUtils.unsafeAllocateBytes(64); - assembly { - mstore(add(tmpKey, 0x20), sload(offset)) - mstore(add(tmpKey, 0x40), sload(add(offset, 1))) - } - offset += 2; - pubkey = MemUtils.unsafeAllocateBytes(PUBKEY_LENGTH); - MemUtils.copyBytes(tmpKey, pubkey, 0, 0, PUBKEY_LENGTH); - // signature - signature = MemUtils.unsafeAllocateBytes(SIGNATURE_LENGTH); - for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { + uint256 curOffset; + for (uint256 i; i < _keysCount;) { + curOffset = _position.getKeyOffset(_nodeOperatorId, _startIndex + i); assembly { - mstore(add(signature, add(0x20, i)), sload(offset)) + // read key + let _ofs := add(add(_pubkeys, 0x20), mul(add(_bufOffset, i), 48)) //PUBKEY_LENGTH = 48 + mstore(add(_ofs, 0x10), shr(128, sload(add(curOffset, 1)))) // bytes 16..47 + mstore(_ofs, sload(curOffset)) // bytes 0..31 + // store signature + _ofs := add(add(_signatures, 0x20), mul(add(_bufOffset, i), 96)) //SIGNATURE_LENGTH = 96 + mstore(_ofs, sload(add(curOffset, 2))) + mstore(add(_ofs, 0x20), sload(add(curOffset, 3))) + mstore(add(_ofs, 0x40), sload(add(curOffset, 4))) + i := add(i, 1) } - offset++; } } - function initKeySig(uint256 _count) internal pure returns (bytes memory, bytes memory) { + // function loadKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) + // internal + // view + // returns (bytes memory pubkey, bytes memory signature) + // { + // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); + + // // key + // bytes memory tmpKey = MemUtils.unsafeAllocateBytes(64); + // assembly { + // mstore(add(tmpKey, 0x20), sload(offset)) + // mstore(add(tmpKey, 0x40), sload(add(offset, 1))) + // } + // offset += 2; + // pubkey = MemUtils.unsafeAllocateBytes(PUBKEY_LENGTH); + // MemUtils.copyBytes(tmpKey, pubkey, 0, 0, PUBKEY_LENGTH); + // // signature + // signature = MemUtils.unsafeAllocateBytes(SIGNATURE_LENGTH); + // for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { + // assembly { + // mstore(add(signature, add(0x20, i)), sload(offset)) + // } + // offset++; + // } + // } + + function initKeysSigsBuf(uint256 _count) internal pure returns (bytes memory, bytes memory) { return ( - MemUtils.unsafeAllocateBytes(_count.mul(PUBKEY_LENGTH)), - MemUtils.unsafeAllocateBytes(_count.mul(SIGNATURE_LENGTH)) + new bytes(_count.mul(PUBKEY_LENGTH)), new bytes(_count.mul(SIGNATURE_LENGTH)) + // MemUtils.unsafeAllocateBytes(_count.mul(PUBKEY_LENGTH)), MemUtils.unsafeAllocateBytes(_count.mul(SIGNATURE_LENGTH)) ); } } diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 9d24a76e3..9db936c1d 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -819,12 +819,13 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256[] memory _nodeOperatorIds, uint256[] memory _activeKeyCountsAfterAllocation ) internal returns (bytes memory pubkeys, bytes memory signatures) { - (pubkeys, signatures) = SigningKeys.initKeySig(_keysCountToLoad); + (pubkeys, signatures) = SigningKeys.initKeysSigsBuf(_keysCountToLoad); uint256 loadedKeysCount = 0; uint64 depositedSigningKeysCountBefore; uint64 depositedSigningKeysCountAfter; - uint256 keyIndex; + // uint256 keyIndex; + uint256 keysCount; Packed64x4.Packed memory signingKeysStats; for (uint256 i; i < _nodeOperatorIds.length; ++i) { signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorIds[i]); @@ -832,14 +833,20 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { depositedSigningKeysCountAfter = signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET) + uint64(_activeKeyCountsAfterAllocation[i]); - if (depositedSigningKeysCountBefore == depositedSigningKeysCountAfter) continue; + keysCount = depositedSigningKeysCountAfter.sub(depositedSigningKeysCountBefore); + if (keysCount == 0) continue; - for (keyIndex = depositedSigningKeysCountBefore; keyIndex < depositedSigningKeysCountAfter; ++keyIndex) { - SIGNING_KEYS_MAPPING_NAME.loadKeySigAndAppend( - _nodeOperatorIds[i], keyIndex, loadedKeysCount, pubkeys, signatures - ); - ++loadedKeysCount; - } + SIGNING_KEYS_MAPPING_NAME.loadKeysSigs( + _nodeOperatorIds[i], depositedSigningKeysCountBefore, keysCount, pubkeys, signatures, loadedKeysCount + ); + loadedKeysCount += keysCount; + + // for (keyIndex = depositedSigningKeysCountBefore; keyIndex < depositedSigningKeysCountAfter; ++keyIndex) { + // SIGNING_KEYS_MAPPING_NAME.loadKeysSigs( + // _nodeOperatorIds[i], keyIndex, loadedKeysCount, pubkeys, signatures + // ); + // ++loadedKeysCount; + // } emit DepositedSigningKeysCountChanged(_nodeOperatorIds[i], depositedSigningKeysCountAfter); signingKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, depositedSigningKeysCountAfter); _saveOperatorSigningKeysStats(_nodeOperatorIds[i], signingKeysStats); @@ -971,9 +978,9 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _requireValidRange(totalSigningKeysCount.add(_keysCount) <= UINT64_MAX); - totalSigningKeysCount = - SIGNING_KEYS_MAPPING_NAME.addKeysSigs(_nodeOperatorId, _keysCount, totalSigningKeysCount, _publicKeys, _signatures); + SIGNING_KEYS_MAPPING_NAME.saveKeysSigs(_nodeOperatorId, totalSigningKeysCount, _keysCount, _publicKeys, _signatures); + totalSigningKeysCount += _keysCount; emit TotalSigningKeysCountChanged(_nodeOperatorId, totalSigningKeysCount); signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, uint64(totalSigningKeysCount)); @@ -1031,15 +1038,18 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); uint256 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); - uint256 _toIndex = _fromIndex.add(_keysCount); - // comparing _toIndex <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than MAX_UINT64 - _requireValidRange(_fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) && _toIndex <= totalSigningKeysCount); + // comapring _fromIndex.add(_keysCount) <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than MAX_UINT64 + _requireValidRange(_fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) && _fromIndex.add(_keysCount) <= totalSigningKeysCount); // removing from the last index to the highest one, so we won't get outside the array - for (uint256 i = _toIndex; i > _fromIndex; --i) { - totalSigningKeysCount = - SIGNING_KEYS_MAPPING_NAME.removeUnusedKeySig(_nodeOperatorId, i - 1, totalSigningKeysCount.sub(1)); - } + + SIGNING_KEYS_MAPPING_NAME.removeKeysSigs(_nodeOperatorId, _fromIndex, _keysCount, totalSigningKeysCount); + + // for (uint256 i = _toIndex; i > _fromIndex; --i) { + // totalSigningKeysCount = + // SIGNING_KEYS_MAPPING_NAME.removeUnusedKeySig(_nodeOperatorId, i - 1, totalSigningKeysCount.sub(1)); + // } + totalSigningKeysCount -= _keysCount; signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, uint64(totalSigningKeysCount)); emit TotalSigningKeysCountChanged(_nodeOperatorId, totalSigningKeysCount); @@ -1112,13 +1122,17 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _requireValidRange(_offset.add(_limit) <= signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET)); uint256 depositedSigningKeysCount = signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET); - (pubkeys, signatures) = SigningKeys.initKeySig(_limit); + (pubkeys, signatures) = SigningKeys.initKeysSigsBuf(_limit); used = new bool[](_limit); + SIGNING_KEYS_MAPPING_NAME.loadKeysSigs(_nodeOperatorId, _offset, _limit, pubkeys, signatures, 0); for (uint256 i; i < _limit; ++i) { - SIGNING_KEYS_MAPPING_NAME.loadKeySigAndAppend(_nodeOperatorId, _offset + i, i, pubkeys, signatures); used[i] = (_offset + i) < depositedSigningKeysCount; } + // for (uint256 i; i < _limit; ++i) { + // SIGNING_KEYS_MAPPING_NAME.loadKeySigAndAppend(_nodeOperatorId, _offset + i, i, pubkeys, signatures); + // used[i] = (_offset + i) < depositedSigningKeysCount; + // } } /// @notice Returns the type of the staking module diff --git a/contracts/0.4.24/test_helpers/SiginigKyesMock.sol b/contracts/0.4.24/test_helpers/SiginigKyesMock.sol new file mode 100644 index 000000000..0b379e137 --- /dev/null +++ b/contracts/0.4.24/test_helpers/SiginigKyesMock.sol @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2023 Lido +// SPDX-License-Identifier: GPL-3.0 + +// See contracts/COMPILERS.md +pragma solidity 0.4.24; + +import {SigningKeys} from "../lib/SigningKeys.sol"; + +import "hardhat/console.sol"; + +contract SigningKeysMock { + using SigningKeys for bytes32; + + bytes32 public constant KEYSSIGS_POSITION = keccak256("KEYSSIGS_POSITION"); + + uint256[] public _nodeOperatorIds; + + constructor(uint256[] memory ids) public { + _nodeOperatorIds = ids; + } + + function getKeyOffset(uint256 _nodeOperatorId, uint256 _keyIndex) external pure returns (uint256) { + return KEYSSIGS_POSITION.getKeyOffset(_nodeOperatorId, _keyIndex); + } + + function saveKeysSigs( + uint256 _nodeOperatorId, + uint256 _startIndex, + uint256 _keysCount, + bytes _publicKeys, + bytes _signatures + ) external returns (uint256) { + return KEYSSIGS_POSITION.saveKeysSigs(_nodeOperatorId, _startIndex, _keysCount, _publicKeys, _signatures); + } + + function removeKeysSigs( + uint256 _nodeOperatorId, + uint256 _startIndex, + uint256 _keysCount, + uint256 _lastIndex + ) external { + KEYSSIGS_POSITION.removeKeysSigs(_nodeOperatorId, _startIndex, _keysCount, _lastIndex); + } + + function loadKeysSigs(uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount) + external + view + returns (bytes memory pubkeys, bytes memory signatures) + { + (pubkeys, signatures) = SigningKeys.initKeysSigsBuf(_keysCount); + KEYSSIGS_POSITION.loadKeysSigs( + _nodeOperatorId, + _startIndex, + _keysCount, + pubkeys, + signatures, + 0 // key offset inside _pubkeys/_signatures buffers + ); + } +} diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index 53f8c6027..e02a48da1 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -2238,31 +2238,31 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob ) }) - it('reverts with "INVALID_LENGTH" error when public keys batch has invalid length', async () => { + it('reverts with "LENGTH_MISMATCH" error when public keys batch has invalid length', async () => { const keysCount = 2 const [publicKeys, signatures] = secondNodeOperatorKeys.slice(0, keysCount) await assert.reverts( app.addSigningKeys(firstNodeOperatorId, keysCount, publicKeys + 'deadbeaf', signatures, { from: voting }), - 'INVALID_LENGTH' + 'LENGTH_MISMATCH' ) }) - it('reverts with "INVALID_LENGTH" error when signatures batch has invalid length', async () => { + it('reverts with "LENGTH_MISMATCH" error when signatures batch has invalid length', async () => { const keysCount = 2 const [publicKeys, signatures] = secondNodeOperatorKeys.slice(0, keysCount) await assert.reverts( app.addSigningKeys(firstNodeOperatorId, keysCount, publicKeys, signatures.slice(0, -2), { from: voting }), - 'INVALID_LENGTH' + 'LENGTH_MISMATCH' ) }) - it('reverts with "INVALID_LENGTH" error when public keys and signatures length mismatch', async () => { + it('reverts with "LENGTH_MISMATCH" error when public keys and signatures length mismatch', async () => { const keysCount = 2 const [publicKeys] = secondNodeOperatorKeys.slice(0, keysCount) const [, signatures] = secondNodeOperatorKeys.slice(0, keysCount + 1) await assert.reverts( app.addSigningKeys(firstNodeOperatorId, keysCount, publicKeys, signatures.slice(0, -2), { from: voting }), - 'INVALID_LENGTH' + 'LENGTH_MISMATCH' ) }) @@ -2467,7 +2467,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) }) - describe('removeSigningKey()', async () => { + describe.only('removeSigningKey()', async () => { const firstNodeOperatorId = 0 const secondNodeOperatorId = 1 const nonExistentNodeOperatorId = 3 @@ -2771,10 +2771,14 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob ) }) - it('emits SigningKeyRemoved event with correct params', async () => { + it.only('emits SigningKeyRemoved event with correct params', async () => { const keyIndex = NODE_OPERATORS[firstNodeOperatorId].depositedSigningKeysCount assert.isTrue(keyIndex <= NODE_OPERATORS[firstNodeOperatorId].totalSigningKeysCount) const receipt = await app.removeSigningKey(firstNodeOperatorId, keyIndex, { from: voting }) + console.log('AAAA', { + keyIndex, + kkk: firstNodeOperatorKeys.slice() + }); assert.emits( receipt, 'SigningKeyRemoved', diff --git a/test/0.4.24/signingkey-lib.test.js b/test/0.4.24/signingkey-lib.test.js new file mode 100644 index 000000000..4d8adcc73 --- /dev/null +++ b/test/0.4.24/signingkey-lib.test.js @@ -0,0 +1,255 @@ +const { assert } = require('../helpers/assert') +const { assertRevert } = require('../helpers/assertThrow') +const { EvmSnapshot } = require('../helpers/blockchain') +const { ZERO_ADDRESS, getEventAt } = require('@aragon/contract-helpers-test') +const { toBN, padRight } = require('../helpers/utils') +const signingKeys = require('../helpers/signing-keys') +const { prepIdsCountsPayload } = require('../helpers/utils') +const SigningKeysMock = artifacts.require('SigningKeysMock') +const SigningKeys = artifacts.require('SigningKeys') + +const nodeOpId1 = 1 +const nodeOpId2 = 2 + +contract('SigningKeys', ([appManager, voting, user1, user2, user3, nobody]) => { + let app + const snapshot = new EvmSnapshot(hre.ethers.provider) + + const firstNodeOperatorId = 0 + const firstNodeOperatorStartIndex = 0 + const firstNodeOperatorKeys = new signingKeys.FakeValidatorKeys(5, { kFill: 'a', sFill: 'b' }) + const firstNodeOperatorLastIndex = firstNodeOperatorKeys.count - 1 + const secondNodeOperatorId = 1 + const secondNodeOperatorStartIndex = 0 + const secondNodeOperatorKeys = new signingKeys.FakeValidatorKeys(7, { kFill: 'c', sFill: 'd' }) + const secondNodeOperatorLastIndex = secondNodeOperatorKeys.count - 1 + + before('deploy base app', async () => { + // Deploy the app's base contract. + app = await SigningKeysMock.new([nodeOpId1, nodeOpId2]) + await snapshot.make() + }) + + afterEach(async () => { + await snapshot.rollback() + }) + + describe('saveKeysSigs()', () => { + it('reverts with INVALID_KEYS_COUNT error when keys count > UINT64_MAX', async () => { + const keysCount = toBN('0x10000000000000001') + await assert.reverts( + app.saveKeysSigs(firstNodeOperatorId, firstNodeOperatorStartIndex, keysCount, '0x', '0x'), + 'INVALID_KEYS_COUNT' + ) + }) + + it('reverts with "INVALID_KEYS_COUNT" error when keys count is 0', async () => { + const keysCount = 0 + await assert.reverts( + app.saveKeysSigs(firstNodeOperatorId, firstNodeOperatorStartIndex, keysCount, '0x', '0x'), + 'INVALID_KEYS_COUNT' + ) + }) + + it('reverts with "LENGTH_MISMATCH" error when public keys batch has invalid length', async () => { + const keysCount = 2 + const [publicKeys, signatures] = firstNodeOperatorKeys.slice(0, keysCount) + await assert.reverts( + app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + keysCount, + publicKeys + 'deadbeaf', + signatures + ), + 'LENGTH_MISMATCH' + ) + }) + + it('reverts with "LENGTH_MISMATCH" error when signatures batch has invalid length', async () => { + const keysCount = 2 + const [publicKeys, signatures] = firstNodeOperatorKeys.slice(0, keysCount) + await assert.reverts( + app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + keysCount, + publicKeys, + signatures.slice(0, -2) + ), + 'LENGTH_MISMATCH' + ) + }) + + it('reverts with "LENGTH_MISMATCH" error when public keys and signatures length mismatch', async () => { + const keysCount = 2 + const [publicKeys] = firstNodeOperatorKeys.slice(0, keysCount) + const [, signatures] = firstNodeOperatorKeys.slice(0, keysCount + 1) + await assert.reverts( + app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + keysCount, + publicKeys, + signatures.slice(0, -2) + ), + 'LENGTH_MISMATCH' + ) + }) + + it('reverts with "EMPTY_KEY" error when public key is zero bytes batch (at 1st position)', async () => { + const keysCount = 1 + const [, signature] = firstNodeOperatorKeys.get(0) + await assert.reverts( + app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + keysCount, + signingKeys.EMPTY_PUBLIC_KEY, + signature + ), + 'EMPTY_KEY' + ) + }) + + it('reverts with "EMPTY_KEY" error when public key is zero bytes batch (at last position)', async () => { + const keysCount = 3 + let [publicKeys] = firstNodeOperatorKeys.slice(0, keysCount - 1) + const [, signatures] = firstNodeOperatorKeys.slice(0, keysCount) + publicKeys += signingKeys.EMPTY_PUBLIC_KEY.substring(2) + await assert.reverts( + app.saveKeysSigs(firstNodeOperatorId, firstNodeOperatorStartIndex, keysCount, publicKeys, signatures), + 'EMPTY_KEY' + ) + }) + + it('emits SigningKeyAdded with correct params for every added key', async () => { + const receipt = await app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + ...firstNodeOperatorKeys.slice() + ) + for (let i = 0; i < firstNodeOperatorKeys.count; ++i) { + assert.emits( + receipt, + 'SigningKeyAdded', + { nodeOperatorId: firstNodeOperatorId, pubkey: firstNodeOperatorKeys.get(i)[0] }, + { abi: SigningKeys._json.abi } + ) + } + }) + + it('stores keys correctly', async () => { + await app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + ...firstNodeOperatorKeys.slice() + ) + + await app.saveKeysSigs( + secondNodeOperatorId, + secondNodeOperatorStartIndex, + secondNodeOperatorKeys.count, + ...secondNodeOperatorKeys.slice() + ) + + for (let i = 0; i < firstNodeOperatorKeys.count; ++i) { + const { pubkeys, signatures } = await app.loadKeysSigs(firstNodeOperatorId, i, 1) + const [expectedPublicKey, expectedSignature] = firstNodeOperatorKeys.get(i) + assert.equal(pubkeys, expectedPublicKey) + assert.equal(signatures, expectedSignature) + } + for (let i = 0; i < secondNodeOperatorKeys.count; ++i) { + const { pubkeys, signatures } = await app.loadKeysSigs(secondNodeOperatorId, i, 1) + const [expectedPublicKey, expectedSignature] = secondNodeOperatorKeys.get(i) + assert.equal(pubkeys, expectedPublicKey) + assert.equal(signatures, expectedSignature) + } + }) + }) + + describe('removeKeysSigs()', async () => { + beforeEach(async () => { + await app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + ...firstNodeOperatorKeys.slice() + ) + await app.saveKeysSigs( + secondNodeOperatorId, + secondNodeOperatorStartIndex, + secondNodeOperatorKeys.count, + ...secondNodeOperatorKeys.slice() + ) + }) + + it('reverts with INVALID_KEYS_COUNT error when keys count is zero ', async () => { + const keysCount = 0 + await assert.reverts( + app.removeKeysSigs(firstNodeOperatorId, firstNodeOperatorStartIndex, keysCount, firstNodeOperatorLastIndex), + 'INVALID_KEYS_COUNT' + ) + }) + + it('reverts with INVALID_KEYS_COUNT error when index is greater than last keys index', async () => { + const keyIndex = firstNodeOperatorLastIndex + 1 + const keysCount = 1 + await assert.reverts( + app.removeKeysSigs(firstNodeOperatorId, keyIndex, keysCount, firstNodeOperatorLastIndex), + 'INVALID_KEYS_COUNT' + ) + }) + + it('reverts with INVALID_KEYS_COUNT error when keys count is greater than last keys index', async () => { + const keysCount = firstNodeOperatorKeys.count + 1 + await assert.reverts( + app.removeKeysSigs(firstNodeOperatorId, firstNodeOperatorStartIndex, keysCount, firstNodeOperatorLastIndex), + 'INVALID_KEYS_COUNT' + ) + }) + + it.only('emits SigningKeyAdded with correct params for every added key', async () => { + const receipt = await app.removeKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + firstNodeOperatorLastIndex + ) + + for (let i = firstNodeOperatorStartIndex; i < firstNodeOperatorKeys.count; ++i) { + assert.emits( + receipt, + 'SigningKeyRemoved', + { nodeOperatorId: firstNodeOperatorId, pubkey: firstNodeOperatorKeys.get(i)[0] }, + { abi: SigningKeys._json.abi } + ) + } + }) + + it.only('removes keys correctly (clear storage)', async () => { + await app.removeKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + firstNodeOperatorLastIndex + ) + + for (let i = firstNodeOperatorStartIndex; i < firstNodeOperatorKeys.count; ++i) { + const { pubkeys, signatures } = await app.loadKeysSigs(firstNodeOperatorId, i, 1) + assert.equal(pubkeys, signingKeys.EMPTY_PUBLIC_KEY) + assert.equal(signatures, signingKeys.EMPTY_SIGNATURE) + } + }) + + it.only('removes keys correctly (move last to deleted position)', async () => { + await app.removeKeysSigs(firstNodeOperatorId, 0, 1, firstNodeOperatorLastIndex) + const { pubkeys, signatures } = await app.loadKeysSigs(firstNodeOperatorId, 0, 1) + const [expectedPublicKey, expectedSignature] = firstNodeOperatorKeys.get(firstNodeOperatorLastIndex) + assert.equal(pubkeys, expectedPublicKey) + assert.equal(signatures, expectedSignature) + }) + }) +}) diff --git a/test/helpers/signing-keys.js b/test/helpers/signing-keys.js index ac3c45ded..dffd9a4f8 100644 --- a/test/helpers/signing-keys.js +++ b/test/helpers/signing-keys.js @@ -1,6 +1,7 @@ const PUBKEY_LENGTH = 48 const SIGNATURE_LENGTH = 96 const EMPTY_PUBLIC_KEY = '0x' + '0'.repeat(2 * PUBKEY_LENGTH) +const EMPTY_SIGNATURE = '0x' + '0'.repeat(2 * SIGNATURE_LENGTH) const { pad, hexConcat, hexSplit } = require('./utils') const { strip0x } = require('../0.6.12/helpers') @@ -39,18 +40,18 @@ class ValidatorKeys { } class FakeValidatorKeys extends ValidatorKeys { - constructor(length, seed = randomInt(10, 10 ** 9)) { + constructor(length, { seed = randomInt(10, 10 ** 9), kFill = 'f', sFill = 'e' } = {}) { super( Array(length) .fill(0) .map((_, i) => Number(seed + i).toString(16)) .map((v) => (v.length % 2 === 0 ? v : '0' + v)) // make resulting hex str length representation even(faa -> 0faa) - .map((v) => pad('0x' + v, PUBKEY_LENGTH, 'f')), + .map((v) => pad('0x' + v, PUBKEY_LENGTH, kFill)), Array(length) .fill(0) .map((_, i) => Number(seed + i).toString(16)) .map((v) => (v.length % 2 === 0 ? v : '0' + v)) // make resulting hex str length representation even(faa -> 0faa) - .map((v) => pad('0x' + v, SIGNATURE_LENGTH, 'e')) + .map((v) => pad('0x' + v, SIGNATURE_LENGTH, sFill)) ) } } @@ -71,6 +72,7 @@ module.exports = { PUBKEY_LENGTH, SIGNATURE_LENGTH, EMPTY_PUBLIC_KEY, + EMPTY_SIGNATURE, FakeValidatorKeys, splitPublicKeysBatch, splitSignaturesBatch From 4a0261c40a3e20fd8763a2950fb816221bd2c60e Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 09:29:03 +0100 Subject: [PATCH 184/199] feat: signing keys lib refactor --- contracts/0.4.24/lib/SigningKeys.sol | 175 ++++-------------- .../0.4.24/nos/NodeOperatorsRegistry.sol | 42 ++--- .../0.4.24/test_helpers/SiginigKyesMock.sol | 38 +++- test/0.4.24/node-operators-registry.test.js | 10 +- test/0.4.24/signingkey-lib.test.js | 58 +++++- 5 files changed, 141 insertions(+), 182 deletions(-) diff --git a/contracts/0.4.24/lib/SigningKeys.sol b/contracts/0.4.24/lib/SigningKeys.sol index 793f68f89..346dbcbea 100644 --- a/contracts/0.4.24/lib/SigningKeys.sol +++ b/contracts/0.4.24/lib/SigningKeys.sol @@ -6,51 +6,44 @@ pragma solidity 0.4.24; import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol"; import {SafeMath64} from "@aragon/os/contracts/lib/math/SafeMath64.sol"; -// import {MemUtils} from "../../common/lib/MemUtils.sol"; - -import "hardhat/console.sol"; +/// @title Library for manage operator keys in storage +/// @author KRogLA library SigningKeys { using SafeMath for uint256; using SafeMath64 for uint64; - using SigningKeys for bytes32; uint64 internal constant PUBKEY_LENGTH = 48; uint64 internal constant SIGNATURE_LENGTH = 96; - uint256 internal constant UINT64_MAX = uint256(~uint64(0)); + uint256 internal constant UINT64_MAX = 0xFFFFFFFFFFFFFFFF; event SigningKeyAdded(uint256 indexed nodeOperatorId, bytes pubkey); event SigningKeyRemoved(uint256 indexed nodeOperatorId, bytes pubkey); - function isKeyEmpty(bytes memory _key) internal pure returns (bool) { - assert(_key.length == PUBKEY_LENGTH); - - uint256 k1; - uint256 k2; - assembly { - k1 := mload(add(_key, 0x20)) - k2 := mload(add(_key, 0x40)) - } - - return 0 == k1 && 0 == (k2 >> ((2 * 32 - PUBKEY_LENGTH) * 8)); - } - function getKeyOffset(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal pure returns (uint256) { return uint256(keccak256(abi.encodePacked(_position, _nodeOperatorId, _keyIndex))); } + /// @dev store opeartor keys to storage + /// @param _position storage slot + /// @param _nodeOperatorId operator id + /// @param _startIndex start index + /// @param _keysCount keys count to load + /// @param _pubkeys kes buffer to read from + /// @param _signatures signatures buffer to read from + /// @return new total keys count function saveKeysSigs( bytes32 _position, uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount, - bytes _publicKeys, + bytes _pubkeys, bytes _signatures ) internal returns (uint256) { require(_keysCount > 0 && _startIndex.add(_keysCount - 1) <= UINT64_MAX, "INVALID_KEYS_COUNT"); require( - _publicKeys.length == _keysCount.mul(PUBKEY_LENGTH) && _signatures.length == _keysCount.mul(SIGNATURE_LENGTH), + _pubkeys.length == _keysCount.mul(PUBKEY_LENGTH) && _signatures.length == _keysCount.mul(SIGNATURE_LENGTH), "LENGTH_MISMATCH" ); @@ -61,20 +54,10 @@ library SigningKeys { for (uint256 i; i < _keysCount;) { curOffset = _position.getKeyOffset(_nodeOperatorId, _startIndex); assembly { - let _ofs := add(add(_publicKeys, 0x20), mul(i, 48)) //PUBKEY_LENGTH = 48 + let _ofs := add(add(_pubkeys, 0x20), mul(i, 48)) //PUBKEY_LENGTH = 48 let _part1 := mload(_ofs) // bytes 0..31 let _part2 := mload(add(_ofs, 0x10)) // bytes 16..47 isEmpty := iszero(or(_part1, _part2)) - - /// @dev custom revert error - // if iszero(or(_part1, _part2)) { - // let ptrError := mload(0x40) - // mstore(ptrError, shl(224, 0x08c379a0)) // selector of `Error(string)` - // mstore(add(ptrError, 4), 0x20) // offset of the abi.encoded `string` - // mstore(add(ptrError, 0x24), 9) // error text length - // mstore(add(ptrError, 0x44), "EMPTY_KEY") // error text 0x454d5054595f4b4559 - // revert(ptrError, 0x64) // revert data length is 4 bytes for selector and 3 slots of 0x20 bytes - // } mstore(add(tmpKey, 0x30), _part2) // store 2nd part first mstore(add(tmpKey, 0x20), _part1) // store 1st part with overwrite bytes 16-31 } @@ -94,32 +77,35 @@ library SigningKeys { } emit SigningKeyAdded(_nodeOperatorId, tmpKey); } - return _startIndex; + return _startIndex; } + /// @dev remove opeartor keys from storage + /// @param _position storage slot + /// @param _nodeOperatorId operator id + /// @param _startIndex start index + /// @param _keysCount keys count to load + /// @param _totalKeysCount current total keys count for operator + /// @return new _totalKeysCount function removeKeysSigs( bytes32 _position, uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount, uint256 _totalKeysCount - ) internal { - require(_keysCount > 0 && _startIndex.add(_keysCount) <= _totalKeysCount && _totalKeysCount <= UINT64_MAX, "INVALID_KEYS_COUNT"); + ) internal returns (uint256) { + require( + _keysCount > 0 && _startIndex.add(_keysCount) <= _totalKeysCount && _totalKeysCount <= UINT64_MAX, + "INVALID_KEYS_COUNT" + ); uint256 curOffset; uint256 lastOffset; uint256 j; bytes memory tmpKey = new bytes(48); - - console.log("_nodeOperatorId", _nodeOperatorId); - console.log("_startIndex", _startIndex); - console.log("_keysCount", _keysCount); - console.log("_totalKeysCount", _totalKeysCount); - + // removing from the last index for (uint256 i = _startIndex + _keysCount; i > _startIndex;) { curOffset = _position.getKeyOffset(_nodeOperatorId, i - 1); - console.log("curOffset", curOffset); - assembly { // read key mstore(add(tmpKey, 0x30), shr(128, sload(add(curOffset, 1)))) // bytes 16..47 @@ -127,11 +113,7 @@ library SigningKeys { } if (i < _totalKeysCount) { lastOffset = _position.getKeyOffset(_nodeOperatorId, _totalKeysCount - 1); - assembly { - // read key - mstore(add(tmpKey, 0x30), shr(128, sload(add(lastOffset, 1)))) // bytes 16..47 - mstore(add(tmpKey, 0x20), sload(lastOffset)) // bytes 0..31 - } + // move last key to deleted key index for (j = 0; j < 5;) { assembly { sstore(add(curOffset, j), sload(add(lastOffset, j))) @@ -140,76 +122,30 @@ library SigningKeys { } curOffset = lastOffset; } + // clear storage for (j = 0; j < 5;) { assembly { sstore(add(curOffset, j), 0) j := add(j, 1) } } - assembly { _totalKeysCount := sub(_totalKeysCount, 1) i := sub(i, 1) } emit SigningKeyRemoved(_nodeOperatorId, tmpKey); - console.logBytes(tmpKey); } + return _totalKeysCount; } - // function removeUnusedKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _index, uint256 _lastIndex) - // internal - // returns (uint256) - // { - // (bytes memory removedKey,) = _position.loadKeySig(_nodeOperatorId, _index); - - // if (_index < _lastIndex) { - // (bytes memory key, bytes memory signature) = _position.loadKeySig(_nodeOperatorId, _lastIndex); - // _position.storeKeySig(_nodeOperatorId, _index, key, signature); - // } - - // _position.deleteKeySig(_nodeOperatorId, _lastIndex); - // emit SigningKeyRemoved(_nodeOperatorId, removedKey); - - // return _lastIndex; - // } - - // function storeKeySig( - // bytes32 _position, - // uint256 _nodeOperatorId, - // uint256 _keyIndex, - // bytes memory _pubkey, - // bytes memory _signature - // ) internal { - // // assert(_pubkey.length == PUBKEY_LENGTH); - // // assert(_signature.length == SIGNATURE_LENGTH); - - // // key - // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - // uint256 keyExcessBits = (2 * 32 - PUBKEY_LENGTH) * 8; - // assembly { - // sstore(offset, mload(add(_pubkey, 0x20))) - // sstore(add(offset, 1), shl(keyExcessBits, shr(keyExcessBits, mload(add(_pubkey, 0x40))))) - // } - // offset += 2; - - // // signature - // for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { - // assembly { - // sstore(offset, mload(add(_signature, add(0x20, i)))) - // } - // offset++; - // } - // } - - // function deleteKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal { - // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - // for (uint256 i = 0; i < (PUBKEY_LENGTH + SIGNATURE_LENGTH) / 32 + 1; ++i) { - // assembly { - // sstore(add(offset, i), 0) - // } - // } - // } - + /// @dev laod opeartor keys from storage + /// @param _position storage slot + /// @param _nodeOperatorId operator id + /// @param _startIndex start index + /// @param _keysCount keys count to load + /// @param _pubkeys preallocated kes buffer to read in + /// @param _signatures preallocated signatures buffer to read in + /// @param _bufOffset start offset in `_pubkeys`/`_signatures` buffer to place values (in number of keys) function loadKeysSigs( bytes32 _position, uint256 _nodeOperatorId, @@ -217,7 +153,7 @@ library SigningKeys { uint256 _keysCount, bytes memory _pubkeys, bytes memory _signatures, - uint256 _bufOffset // key offset inside _pubkeys/_signatures buffers + uint256 _bufOffset ) internal view { uint256 curOffset; for (uint256 i; i < _keysCount;) { @@ -237,36 +173,7 @@ library SigningKeys { } } - // function loadKeySig(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) - // internal - // view - // returns (bytes memory pubkey, bytes memory signature) - // { - // uint256 offset = _position.getKeyOffset(_nodeOperatorId, _keyIndex); - - // // key - // bytes memory tmpKey = MemUtils.unsafeAllocateBytes(64); - // assembly { - // mstore(add(tmpKey, 0x20), sload(offset)) - // mstore(add(tmpKey, 0x40), sload(add(offset, 1))) - // } - // offset += 2; - // pubkey = MemUtils.unsafeAllocateBytes(PUBKEY_LENGTH); - // MemUtils.copyBytes(tmpKey, pubkey, 0, 0, PUBKEY_LENGTH); - // // signature - // signature = MemUtils.unsafeAllocateBytes(SIGNATURE_LENGTH); - // for (uint256 i = 0; i < SIGNATURE_LENGTH; i += 32) { - // assembly { - // mstore(add(signature, add(0x20, i)), sload(offset)) - // } - // offset++; - // } - // } - function initKeysSigsBuf(uint256 _count) internal pure returns (bytes memory, bytes memory) { - return ( - new bytes(_count.mul(PUBKEY_LENGTH)), new bytes(_count.mul(SIGNATURE_LENGTH)) - // MemUtils.unsafeAllocateBytes(_count.mul(PUBKEY_LENGTH)), MemUtils.unsafeAllocateBytes(_count.mul(SIGNATURE_LENGTH)) - ); + return (new bytes(_count.mul(PUBKEY_LENGTH)), new bytes(_count.mul(SIGNATURE_LENGTH))); } } diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 9db936c1d..63282fc17 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -54,7 +54,12 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { event NonceChanged(uint256 nonce); event StuckPenaltyDelayChanged(uint256 stuckPenaltyDelay); - event StuckPenaltyStateChanged(uint256 indexed nodeOperatorId, uint256 stuckValidatorsCount, uint256 refundedValidatorsCount, uint256 stuckPenaltyEndTimestamp); + event StuckPenaltyStateChanged( + uint256 indexed nodeOperatorId, + uint256 stuckValidatorsCount, + uint256 refundedValidatorsCount, + uint256 stuckPenaltyEndTimestamp + ); event TargetValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 targetValidatorsCount); event NodeOperatorPenalized(address indexed recipientAddress, uint256 sharesPenalizedAmount); @@ -432,7 +437,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // see `onAllValidatorCountersUpdated()` } - function _checkReportPayload(uint256 idsLength, uint256 countsLength) internal pure returns (uint256 count) { count = idsLength / 8; require(countsLength / 16 == count && idsLength % 8 == 0 && countsLength % 16 == 0, "INVALID_REPORT_DATA"); @@ -523,8 +527,7 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { } /// @notice Called by StakingRouter after oracle finishes updating validators counters for all node operators - function onAllValidatorCountersUpdated() external - { + function onAllValidatorCountersUpdated() external { _auth(STAKING_ROUTER_ROLE); // for the permissioned module, we're distributing rewards within oracle operation // since the number of node ops won't be high and thus gas costs are limited @@ -603,7 +606,10 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { if (_stuckValidatorsCount == stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET)) return; Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); - _requireValidRange(_stuckValidatorsCount <= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) - signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET)); + _requireValidRange( + _stuckValidatorsCount + <= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) - signingKeysStats.get(EXITED_KEYS_COUNT_OFFSET) + ); stuckPenaltyStats.set(STUCK_VALIDATORS_COUNT_OFFSET, _stuckValidatorsCount); if (_stuckValidatorsCount <= stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET)) { @@ -824,7 +830,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { uint256 loadedKeysCount = 0; uint64 depositedSigningKeysCountBefore; uint64 depositedSigningKeysCountAfter; - // uint256 keyIndex; uint256 keysCount; Packed64x4.Packed memory signingKeysStats; for (uint256 i; i < _nodeOperatorIds.length; ++i) { @@ -841,12 +846,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { ); loadedKeysCount += keysCount; - // for (keyIndex = depositedSigningKeysCountBefore; keyIndex < depositedSigningKeysCountAfter; ++keyIndex) { - // SIGNING_KEYS_MAPPING_NAME.loadKeysSigs( - // _nodeOperatorIds[i], keyIndex, loadedKeysCount, pubkeys, signatures - // ); - // ++loadedKeysCount; - // } emit DepositedSigningKeysCountChanged(_nodeOperatorIds[i], depositedSigningKeysCountAfter); signingKeysStats.set(DEPOSITED_KEYS_COUNT_OFFSET, depositedSigningKeysCountAfter); _saveOperatorSigningKeysStats(_nodeOperatorIds[i], signingKeysStats); @@ -978,9 +977,9 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _requireValidRange(totalSigningKeysCount.add(_keysCount) <= UINT64_MAX); - SIGNING_KEYS_MAPPING_NAME.saveKeysSigs(_nodeOperatorId, totalSigningKeysCount, _keysCount, _publicKeys, _signatures); + totalSigningKeysCount = + SIGNING_KEYS_MAPPING_NAME.saveKeysSigs(_nodeOperatorId, totalSigningKeysCount, _keysCount, _publicKeys, _signatures); - totalSigningKeysCount += _keysCount; emit TotalSigningKeysCountChanged(_nodeOperatorId, totalSigningKeysCount); signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, uint64(totalSigningKeysCount)); @@ -1041,15 +1040,8 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { // comapring _fromIndex.add(_keysCount) <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than MAX_UINT64 _requireValidRange(_fromIndex >= signingKeysStats.get(DEPOSITED_KEYS_COUNT_OFFSET) && _fromIndex.add(_keysCount) <= totalSigningKeysCount); - // removing from the last index to the highest one, so we won't get outside the array - - SIGNING_KEYS_MAPPING_NAME.removeKeysSigs(_nodeOperatorId, _fromIndex, _keysCount, totalSigningKeysCount); - - // for (uint256 i = _toIndex; i > _fromIndex; --i) { - // totalSigningKeysCount = - // SIGNING_KEYS_MAPPING_NAME.removeUnusedKeySig(_nodeOperatorId, i - 1, totalSigningKeysCount.sub(1)); - // } - totalSigningKeysCount -= _keysCount; + totalSigningKeysCount = + SIGNING_KEYS_MAPPING_NAME.removeKeysSigs(_nodeOperatorId, _fromIndex, _keysCount, totalSigningKeysCount); signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, uint64(totalSigningKeysCount)); emit TotalSigningKeysCountChanged(_nodeOperatorId, totalSigningKeysCount); @@ -1129,10 +1121,6 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { for (uint256 i; i < _limit; ++i) { used[i] = (_offset + i) < depositedSigningKeysCount; } - // for (uint256 i; i < _limit; ++i) { - // SIGNING_KEYS_MAPPING_NAME.loadKeySigAndAppend(_nodeOperatorId, _offset + i, i, pubkeys, signatures); - // used[i] = (_offset + i) < depositedSigningKeysCount; - // } } /// @notice Returns the type of the staking module diff --git a/contracts/0.4.24/test_helpers/SiginigKyesMock.sol b/contracts/0.4.24/test_helpers/SiginigKyesMock.sol index 0b379e137..4b2da4ab8 100644 --- a/contracts/0.4.24/test_helpers/SiginigKyesMock.sol +++ b/contracts/0.4.24/test_helpers/SiginigKyesMock.sol @@ -33,13 +33,11 @@ contract SigningKeysMock { return KEYSSIGS_POSITION.saveKeysSigs(_nodeOperatorId, _startIndex, _keysCount, _publicKeys, _signatures); } - function removeKeysSigs( - uint256 _nodeOperatorId, - uint256 _startIndex, - uint256 _keysCount, - uint256 _lastIndex - ) external { - KEYSSIGS_POSITION.removeKeysSigs(_nodeOperatorId, _startIndex, _keysCount, _lastIndex); + function removeKeysSigs(uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount, uint256 _lastIndex) + external + returns (uint256) + { + return KEYSSIGS_POSITION.removeKeysSigs(_nodeOperatorId, _startIndex, _keysCount, _lastIndex); } function loadKeysSigs(uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount) @@ -57,4 +55,30 @@ contract SigningKeysMock { 0 // key offset inside _pubkeys/_signatures buffers ); } + + function loadKeysSigsBatch(uint256[] _nodeOpIds, uint256[] _startIndexes, uint256[] _keysCounts) + external + view + returns (bytes memory pubkeys, bytes memory signatures) + { + require(_nodeOpIds.length == _startIndexes.length && _startIndexes.length == _keysCounts.length, "LENGTH_MISMATCH"); + uint256 totalKeysCount; + uint256 i; + for (i = 0; i < _nodeOpIds.length; ++i) { + totalKeysCount += _keysCounts[i]; + } + (pubkeys, signatures) = SigningKeys.initKeysSigsBuf(totalKeysCount); + uint256 loadedKeysCount; + for (i = 0; i < _nodeOpIds.length; ++i) { + KEYSSIGS_POSITION.loadKeysSigs( + _nodeOpIds[i], + _startIndexes[i], + _keysCounts[i], + pubkeys, + signatures, + loadedKeysCount // key offset inside _pubkeys/_signatures buffers + ); + loadedKeysCount += _keysCounts[i]; + } + } } diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index e02a48da1..b1d4c1426 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -2467,7 +2467,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) }) - describe.only('removeSigningKey()', async () => { + describe('removeSigningKey()', async () => { const firstNodeOperatorId = 0 const secondNodeOperatorId = 1 const nonExistentNodeOperatorId = 3 @@ -2771,14 +2771,10 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob ) }) - it.only('emits SigningKeyRemoved event with correct params', async () => { + it('emits SigningKeyRemoved event with correct params', async () => { const keyIndex = NODE_OPERATORS[firstNodeOperatorId].depositedSigningKeysCount - assert.isTrue(keyIndex <= NODE_OPERATORS[firstNodeOperatorId].totalSigningKeysCount) + assert.isTrue(keyIndex < NODE_OPERATORS[firstNodeOperatorId].totalSigningKeysCount) const receipt = await app.removeSigningKey(firstNodeOperatorId, keyIndex, { from: voting }) - console.log('AAAA', { - keyIndex, - kkk: firstNodeOperatorKeys.slice() - }); assert.emits( receipt, 'SigningKeyRemoved', diff --git a/test/0.4.24/signingkey-lib.test.js b/test/0.4.24/signingkey-lib.test.js index 4d8adcc73..8f2e42990 100644 --- a/test/0.4.24/signingkey-lib.test.js +++ b/test/0.4.24/signingkey-lib.test.js @@ -168,6 +168,49 @@ contract('SigningKeys', ([appManager, voting, user1, user2, user3, nobody]) => { assert.equal(signatures, expectedSignature) } }) + + it('read keys batch correctly', async () => { + await app.saveKeysSigs( + firstNodeOperatorId, + firstNodeOperatorStartIndex, + firstNodeOperatorKeys.count, + ...firstNodeOperatorKeys.slice() + ) + + await app.saveKeysSigs( + secondNodeOperatorId, + secondNodeOperatorStartIndex, + secondNodeOperatorKeys.count, + ...secondNodeOperatorKeys.slice() + ) + + const { pubkeys, signatures } = await app.loadKeysSigsBatch( + [secondNodeOperatorId, firstNodeOperatorId], + [secondNodeOperatorStartIndex + 2, firstNodeOperatorStartIndex + 1], + [secondNodeOperatorKeys.count - 4, firstNodeOperatorKeys.count - 2] + ) + + let expectedPublicKeys = '' + let expectedSignatures = '' + let startIndex = secondNodeOperatorStartIndex + 2 + let endIndex = startIndex + secondNodeOperatorKeys.count - 4 + for (let i = startIndex; i < endIndex; ++i) { + const [key, sig] = secondNodeOperatorKeys.get(i) + expectedPublicKeys += key.substring(2) + expectedSignatures += sig.substring(2) + } + + startIndex = firstNodeOperatorStartIndex + 1 + endIndex = startIndex + firstNodeOperatorKeys.count - 2 + for (let i = startIndex; i < endIndex; ++i) { + const [key, sig] = firstNodeOperatorKeys.get(i) + expectedPublicKeys += key.substring(2) + expectedSignatures += sig.substring(2) + } + + assert.equal(pubkeys, '0x' + expectedPublicKeys) + assert.equal(signatures, '0x' + expectedSignatures) + }) }) describe('removeKeysSigs()', async () => { @@ -211,12 +254,12 @@ contract('SigningKeys', ([appManager, voting, user1, user2, user3, nobody]) => { ) }) - it.only('emits SigningKeyAdded with correct params for every added key', async () => { + it('emits SigningKeyAdded with correct params for every added key', async () => { const receipt = await app.removeKeysSigs( firstNodeOperatorId, firstNodeOperatorStartIndex, firstNodeOperatorKeys.count, - firstNodeOperatorLastIndex + firstNodeOperatorKeys.count ) for (let i = firstNodeOperatorStartIndex; i < firstNodeOperatorKeys.count; ++i) { @@ -229,12 +272,12 @@ contract('SigningKeys', ([appManager, voting, user1, user2, user3, nobody]) => { } }) - it.only('removes keys correctly (clear storage)', async () => { + it('removes keys correctly (clear storage)', async () => { await app.removeKeysSigs( firstNodeOperatorId, firstNodeOperatorStartIndex, firstNodeOperatorKeys.count, - firstNodeOperatorLastIndex + firstNodeOperatorKeys.count ) for (let i = firstNodeOperatorStartIndex; i < firstNodeOperatorKeys.count; ++i) { @@ -244,9 +287,10 @@ contract('SigningKeys', ([appManager, voting, user1, user2, user3, nobody]) => { } }) - it.only('removes keys correctly (move last to deleted position)', async () => { - await app.removeKeysSigs(firstNodeOperatorId, 0, 1, firstNodeOperatorLastIndex) - const { pubkeys, signatures } = await app.loadKeysSigs(firstNodeOperatorId, 0, 1) + it('removes keys correctly (move last to deleted position)', async () => { + const keyIndex = 0 + await app.removeKeysSigs(firstNodeOperatorId, keyIndex, 1, firstNodeOperatorKeys.count) + const { pubkeys, signatures } = await app.loadKeysSigs(firstNodeOperatorId, keyIndex, 1) const [expectedPublicKey, expectedSignature] = firstNodeOperatorKeys.get(firstNodeOperatorLastIndex) assert.equal(pubkeys, expectedPublicKey) assert.equal(signatures, expectedSignature) From 87ada8e5b2b2b485577feebb280ca1b7d1818780 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 09:35:52 +0100 Subject: [PATCH 185/199] test: fix --- test/0.4.24/node-operators-registry-penalty.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/0.4.24/node-operators-registry-penalty.test.js b/test/0.4.24/node-operators-registry-penalty.test.js index d5e272430..c21fe47af 100644 --- a/test/0.4.24/node-operators-registry-penalty.test.js +++ b/test/0.4.24/node-operators-registry-penalty.test.js @@ -309,7 +309,6 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, use // calls distributeRewards() inside receipt = await app.testing__distributeRewards({ from: voting }) - assert.emits(receipt, 'RewardsDistributed', { rewardAddress: user1, sharesAmount: ETH(1) }) assert.emits(receipt, 'RewardsDistributed', { rewardAddress: user2, sharesAmount: ETH(4*2) }) assert.notEmits(receipt, 'RewardsDistributed', { rewardAddress: user3, sharesAmount: 0 }) From 05899df6025a720ba8bd7e06becab22ee5ede467 Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 12:42:26 +0100 Subject: [PATCH 186/199] test: fixes --- .../test_helpers/NodeOperatorsRegistryMock.sol | 4 ++-- lib/abi/NodeOperatorsRegistry.json | 2 +- test/scenario/lido_penalties_slashing.js | 12 +++++------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol index fd0f16126..8f0912221 100644 --- a/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol +++ b/contracts/0.4.24/test_helpers/NodeOperatorsRegistryMock.sol @@ -153,8 +153,8 @@ contract NodeOperatorsRegistryMock is NodeOperatorsRegistry { ACTIVE_OPERATORS_COUNT_POSITION.setStorageUint256(0); KEYS_OP_INDEX_POSITION.setStorageUint256(0); - _nodeOperatorTotals = NodeOperatorTotals({ - signingKeysStats: Packed64x4.Packed(0) + _nodeOperatorSummary = NodeOperatorSummary({ + summarySigningKeysStats: Packed64x4.Packed(0) }); Packed64x4.Packed memory tmp; diff --git a/lib/abi/NodeOperatorsRegistry.json b/lib/abi/NodeOperatorsRegistry.json index 0c5d9263d..cdcfc9ae4 100644 --- a/lib/abi/NodeOperatorsRegistry.json +++ b/lib/abi/NodeOperatorsRegistry.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"depositsCount","type":"uint256"},{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"},{"indexed":false,"name":"refundedValidatorsCount","type":"uint256"},{"indexed":false,"name":"stuckPenaltyEndTimestamp","type":"uint256"}],"name":"StuckPenaltyStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"},{"indexed":false,"name":"refundedValidatorsCount","type":"uint256"},{"indexed":false,"name":"stuckPenaltyEndTimestamp","type":"uint256"}],"name":"StuckPenaltyStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file diff --git a/test/scenario/lido_penalties_slashing.js b/test/scenario/lido_penalties_slashing.js index daf3176de..67772eafa 100644 --- a/test/scenario/lido_penalties_slashing.js +++ b/test/scenario/lido_penalties_slashing.js @@ -588,13 +588,11 @@ contract('Lido: penalties, slashing, operator stops', (addresses) => { const nodeOperator1TokenSharesAfter = await token.sharesOf(nodeOperator1.address) const nodeOperator2TokenSharesAfter = await token.sharesOf(nodeOperator2.address) - console.log({ - nodeOperator1TokenSharesBefore: nodeOperator1TokenSharesBefore.toString(), - nodeOperator1TokenSharesAfter: nodeOperator1TokenSharesAfter.toString(), - nodeOperator2TokenSharesBefore: nodeOperator2TokenSharesBefore.toString(), - nodeOperator2TokenSharesAfter: nodeOperator2TokenSharesAfter.toString(), - }) - assertBn(nodeOperator1TokenSharesAfter, nodeOperator1TokenSharesBefore, `first node operator balance hasn't changed`) + assertBn( + nodeOperator1TokenSharesAfter, + nodeOperator1TokenSharesBefore, + `first node operator balance hasn't changed` + ) assert( !nodeOperator2TokenSharesBefore.sub(nodeOperator2TokenSharesAfter).positive, `second node operator gained shares under fee distribution` From 4c776cc62b7582dddde77367fcf76d4a9647a45a Mon Sep 17 00:00:00 2001 From: KRogLA Date: Tue, 21 Feb 2023 12:46:02 +0100 Subject: [PATCH 187/199] chore: abi upd --- lib/abi/NodeOperatorsRegistry.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/abi/NodeOperatorsRegistry.json b/lib/abi/NodeOperatorsRegistry.json index d20c281bf..cdcfc9ae4 100644 --- a/lib/abi/NodeOperatorsRegistry.json +++ b/lib/abi/NodeOperatorsRegistry.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"},{"indexed":false,"name":"refundedValidatorsCount","type":"uint256"},{"indexed":false,"name":"stuckPenaltyEndTimestamp","type":"uint256"}],"name":"StuckPenaltyStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"},{"indexed":false,"name":"refundedValidatorsCount","type":"uint256"},{"indexed":false,"name":"stuckPenaltyEndTimestamp","type":"uint256"}],"name":"StuckPenaltyStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file From 17d35267922b039e2d6667a250a179ad4d73123d Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Mon, 20 Feb 2023 21:04:42 +0200 Subject: [PATCH 188/199] staking router: fix struct name and docs layout --- contracts/0.8.9/StakingRouter.sol | 39 ++++++++++++++----------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/contracts/0.8.9/StakingRouter.sol b/contracts/0.8.9/StakingRouter.sol index bb8f1d889..8ead5a7ce 100644 --- a/contracts/0.8.9/StakingRouter.sol +++ b/contracts/0.8.9/StakingRouter.sol @@ -332,18 +332,28 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version } } - struct ValidatorsCountCorrection { + struct ValidatorsCountsCorrection { + /// @notice The expected current number of exited validators of the module that is + /// being corrected. uint256 currentModuleExitedValidatorsCount; + /// @notice The expected current number of exited validators of the node operator + /// that is being corrected. uint256 currentNodeOperatorExitedValidatorsCount; + /// @notice The expected current number of stuck validators of the node operator + /// that is being corrected. uint256 currentNodeOperatorStuckValidatorsCount; + /// @notice The corrected number of exited validators of the module. uint256 newModuleExitedValidatorsCount; + /// @notice The corrected number of exited validators of the node operator. uint256 newNodeOperatorExitedValidatorsCount; + /// @notice The corrected number of stuck validators of the node operator. uint256 newNodeOperatorStuckValidatorsCount; } /** - * @notice Sets exited validators count for the given module and given node operator in that module - * without performing critical safety checks, e.g. that exited validators count cannot decrease. + * @notice Sets exited validators count for the given module and given node operator in that + * module without performing critical safety checks, e.g. that exited validators count cannot + * decrease. * * Should only be used by the DAO in extreme cases and with sufficient precautions to correct * invalid data reported by the oracle committee due to a bug in the oracle daemon. @@ -355,31 +365,16 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version * @param _triggerUpdateFinish Whether to call `onAllValidatorCountersUpdated` on * the module after applying the corrections. * - * @param _correction.currentModuleExitedValidatorsCount The expected current number of exited - * validators of the module that is being corrected. + * @param _correction See the docs for the `ValidatorsCountsCorrection` struct. * - * @param _correction.currentNodeOperatorExitedValidatorsCount The expected current number of exited - * validators of the node operator that is being corrected. - * - * @param _correction.currentNodeOperatorStuckValidatorsCount The expected current number of stuck - * validators of the node operator that is being corrected. - * - * @param _correction.newModuleExitedValidatorsCount The corrected number of exited validators of the module. - * - * @param _correction.newNodeOperatorExitedValidatorsCount The corrected number of exited validators of the - * node operator. - * - * @param _correction.newNodeOperatorStuckValidatorsCount The corrected number of stuck validators of the - * node operator. - * - * Reverts if the current numbers of exited and stuck validators of the module and node operator don't - * match the supplied expected current values. + * Reverts if the current numbers of exited and stuck validators of the module and node operator + * don't match the supplied expected current values. */ function unsafeSetExitedValidatorsCount( uint256 _stakingModuleId, uint256 _nodeOperatorId, bool _triggerUpdateFinish, - ValidatorsCountCorrection memory _correction + ValidatorsCountsCorrection memory _correction ) external onlyRole(UNSAFE_SET_EXITED_VALIDATORS_ROLE) From 579596094e631e7c301167087b1e5500f8a36323 Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Mon, 20 Feb 2023 21:13:58 +0200 Subject: [PATCH 189/199] staking module interface: improve fn naming consistency --- contracts/0.4.24/nos/NodeOperatorsRegistry.sol | 9 +++++---- contracts/0.8.9/StakingRouter.sol | 8 ++++---- contracts/0.8.9/interfaces/IStakingModule.sol | 7 ++++--- contracts/0.8.9/test_helpers/ModuleSolo.sol | 4 ++-- contracts/0.8.9/test_helpers/StakingModuleMock.sol | 4 ++-- test/0.4.24/node-operators-registry.test.js | 14 +++++++------- 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 63282fc17..2c3716fda 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -430,11 +430,11 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { } /// @notice Called by StakingRouter to signal that stETH rewards were minted for this module. - function handleRewardsMinted(uint256) external view { + function onRewardsMinted(uint256 /* _totalShares */) external view { _auth(STAKING_ROUTER_ROLE); // since we're pushing rewards to operators after exited validators counts are // updated (as opposed to pulling by node ops), we don't need any handling here - // see `onAllValidatorCountersUpdated()` + // see `onExitedAndStuckValidatorsCountsUpdated()` } function _checkReportPayload(uint256 idsLength, uint256 countsLength) internal pure returns (uint256 count) { @@ -526,8 +526,9 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { _updateRefundValidatorsKeysCount(_nodeOperatorId, uint64(_refundedValidatorsCount)); } - /// @notice Called by StakingRouter after oracle finishes updating validators counters for all node operators - function onAllValidatorCountersUpdated() external { + /// @notice Called by StakingRouter after it finishes updating exited and stuck validators + /// counts for this module's node operators. + function onExitedAndStuckValidatorsCountsUpdated() external { _auth(STAKING_ROUTER_ROLE); // for the permissioned module, we're distributing rewards within oracle operation // since the number of node ops won't be high and thus gas costs are limited diff --git a/contracts/0.8.9/StakingRouter.sol b/contracts/0.8.9/StakingRouter.sol index 8ead5a7ce..23fbb8d73 100644 --- a/contracts/0.8.9/StakingRouter.sol +++ b/contracts/0.8.9/StakingRouter.sol @@ -263,7 +263,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version { for (uint256 i = 0; i < _stakingModuleIds.length; ) { address moduleAddr = _getStakingModuleById(_stakingModuleIds[i]).stakingModuleAddress; - IStakingModule(moduleAddr).handleRewardsMinted(_totalShares[i]); + IStakingModule(moduleAddr).onRewardsMinted(_totalShares[i]); unchecked { ++i; } } } @@ -328,7 +328,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version newExitedValidatorsCount >= prevReportedExitedValidatorsCount ) { // oracle finished updating exited validators for all node ops - moduleContract.onAllValidatorCountersUpdated(); + moduleContract.onExitedAndStuckValidatorsCountsUpdated(); } } @@ -362,7 +362,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version * * @param _nodeOperatorId ID of the node operator. * - * @param _triggerUpdateFinish Whether to call `onAllValidatorCountersUpdated` on + * @param _triggerUpdateFinish Whether to call `onExitedAndStuckValidatorsCountsUpdated` on * the module after applying the corrections. * * @param _correction See the docs for the `ValidatorsCountsCorrection` struct. @@ -413,7 +413,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version ); if (_triggerUpdateFinish) { - IStakingModule(moduleAddr).onAllValidatorCountersUpdated(); + IStakingModule(moduleAddr).onExitedAndStuckValidatorsCountsUpdated(); } } diff --git a/contracts/0.8.9/interfaces/IStakingModule.sol b/contracts/0.8.9/interfaces/IStakingModule.sol index cb3fbd5c8..4184d042c 100644 --- a/contracts/0.8.9/interfaces/IStakingModule.sol +++ b/contracts/0.8.9/interfaces/IStakingModule.sol @@ -79,7 +79,7 @@ interface IStakingModule { /// @notice Called by StakingRouter to signal that stETH rewards were minted for this module. /// @param _totalShares Amount of stETH shares that were minted to reward all node operators. - function handleRewardsMinted(uint256 _totalShares) external; + function onRewardsMinted(uint256 _totalShares) external; /// @notice Updates the number of the validators of the given node operator that were requested /// to exit but failed to do so in the max allowed time @@ -125,8 +125,9 @@ interface IStakingModule { external returns (bytes memory publicKeys, bytes memory signatures); - /// @notice Called by StakingRouter after oracle finishes updating validators counters for all node operators - function onAllValidatorCountersUpdated() external; + /// @notice Called by StakingRouter after it finishes updating exited and stuck validators + /// counts for this module's node operators. + function onExitedAndStuckValidatorsCountsUpdated() external; /// @notice Called by StakingRouter when withdrawal credentials are changed. /// @dev This method MUST discard all StakingModule's unused deposit data cause they become diff --git a/contracts/0.8.9/test_helpers/ModuleSolo.sol b/contracts/0.8.9/test_helpers/ModuleSolo.sol index 9c28a2746..3ccdc1b33 100644 --- a/contracts/0.8.9/test_helpers/ModuleSolo.sol +++ b/contracts/0.8.9/test_helpers/ModuleSolo.sol @@ -76,7 +76,7 @@ contract ModuleSolo is IStakingModule { function setNodeOperatorStakingLimit(uint256 _id, uint256 _stakingLimit) external {} - function handleRewardsMinted(uint256 _totalShares) external {} + function onRewardsMinted(uint256 _totalShares) external {} function updateStuckValidatorsCount( bytes calldata _nodeOperatorIds, @@ -90,7 +90,7 @@ contract ModuleSolo is IStakingModule { function updateRefundedValidatorsCount(uint256 _nodeOperatorId, uint256 _refundedValidatorsCount) external {} - function onAllValidatorCountersUpdated() external {} + function onExitedAndStuckValidatorsCountsUpdated() external {} function unsafeUpdateValidatorsCount( uint256 /* _nodeOperatorId */, diff --git a/contracts/0.8.9/test_helpers/StakingModuleMock.sol b/contracts/0.8.9/test_helpers/StakingModuleMock.sol index ca7bb61e1..f26bbbc4f 100644 --- a/contracts/0.8.9/test_helpers/StakingModuleMock.sol +++ b/contracts/0.8.9/test_helpers/StakingModuleMock.sol @@ -61,7 +61,7 @@ contract StakingModuleMock is IStakingModule { view returns (uint256[] memory nodeOperatorIds) {} - function handleRewardsMinted(uint256 _totalShares) external {} + function onRewardsMinted(uint256 _totalShares) external {} function updateStuckValidatorsCount( bytes calldata _nodeOperatorIds, @@ -75,7 +75,7 @@ contract StakingModuleMock is IStakingModule { function updateRefundedValidatorsCount(uint256 _nodeOperatorId, uint256 _refundedValidatorsCount) external {} - function onAllValidatorCountersUpdated() external {} + function onExitedAndStuckValidatorsCountsUpdated() external {} function unsafeUpdateValidatorsCount( uint256 /* _nodeOperatorId */, diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index b1d4c1426..a00d32d7b 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -3260,7 +3260,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) it('reverts if no STAKING_ROUTER_ROLE', async () => { - await assert.reverts(app.onAllValidatorCountersUpdated({ from: user3 }), 'APP_AUTH_FAILED') + await assert.reverts(app.onExitedAndStuckValidatorsCountsUpdated({ from: user3 }), 'APP_AUTH_FAILED') }) it("doesn't distribute rewards if no shares to distribute", async () => { @@ -3272,7 +3272,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob steth.sharesOf(user3) ]) // calls distributeRewards() inside - await app.onAllValidatorCountersUpdated({ from: voting }) + await app.onExitedAndStuckValidatorsCountsUpdated({ from: voting }) const recipientsSharesAfter = await Promise.all([ steth.sharesOf(user1), steth.sharesOf(user2), @@ -3289,7 +3289,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await steth.mintShares(app.address, ETH(10)) // calls distributeRewards() inside - await app.onAllValidatorCountersUpdated({ from: voting }) + await app.onExitedAndStuckValidatorsCountsUpdated({ from: voting }) assert.equals(await steth.sharesOf(user1), ETH(3)) assert.equals(await steth.sharesOf(user2), ETH(7)) @@ -3301,7 +3301,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await steth.mintShares(app.address, ETH(10)) // calls distributeRewards() inside - receipt = await app.onAllValidatorCountersUpdated({ from: voting }) + receipt = await app.onExitedAndStuckValidatorsCountsUpdated({ from: voting }) assert.emits(receipt, 'RewardsDistributed', { rewardAddress: user1, sharesAmount: ETH(3) }) assert.emits(receipt, 'RewardsDistributed', { rewardAddress: user2, sharesAmount: ETH(7) }) @@ -3485,16 +3485,16 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob }) }) - describe('handleRewardsMinted()', () => { + describe('onRewardsMinted()', () => { it('reverts with no STAKING_ROUTER_ROLE', async () => { const hasPermission = await dao.hasPermission(user1, app, 'STAKING_ROUTER_ROLE') assert.isFalse(hasPermission) - await assert.reverts(app.handleRewardsMinted(123, { from: user1 })) + await assert.reverts(app.onRewardsMinted(123, { from: user1 })) }) it('no reverts with STAKING_ROUTER_ROLE', async () => { const hasPermission = await dao.hasPermission(voting, app, 'STAKING_ROUTER_ROLE') assert.isTrue(hasPermission) - await app.handleRewardsMinted(123, { from: voting }) + await app.onRewardsMinted(123, { from: voting }) }) }) }) From a82916e4db7bccec1bdc23a8fd3d485c7c10bf2e Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Tue, 21 Feb 2023 00:45:14 +0200 Subject: [PATCH 190/199] staking router, acct oracle: fix rewards distribution for modules without updates --- .../0.4.24/nos/NodeOperatorsRegistry.sol | 5 + contracts/0.8.9/StakingRouter.sol | 49 ++--- contracts/0.8.9/interfaces/IStakingModule.sol | 5 + contracts/0.8.9/oracle/AccountingOracle.sol | 91 +++++++--- .../MockStakingRouterForAccountingOracle.sol | 6 + test/0.4.24/node-operators-registry.test.js | 2 +- .../accounting-oracle-access-control.test.js | 43 ++++- .../oracle/accounting-oracle-deploy.test.js | 3 +- .../accounting-oracle-happy-path.test.js | 171 +++++++++++++++--- ...ng-oracle-submit-report-extra-data.test.js | 13 +- test/helpers/factories.js | 6 +- test/helpers/oracle.js | 5 +- test/helpers/protocol.js | 14 +- .../lido_rewards_distribution_math.js | 4 +- 14 files changed, 322 insertions(+), 95 deletions(-) diff --git a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol index 2c3716fda..b1c8b4eaf 100644 --- a/contracts/0.4.24/nos/NodeOperatorsRegistry.sol +++ b/contracts/0.4.24/nos/NodeOperatorsRegistry.sol @@ -528,6 +528,11 @@ contract NodeOperatorsRegistry is AragonApp, Versioned { /// @notice Called by StakingRouter after it finishes updating exited and stuck validators /// counts for this module's node operators. + /// + /// Guaranteed to be called after an oracle report is applied, regardless of whether any node + /// operator in this module has actually received any updated counts as a result of the report + /// but given that the total number of exited validators returned from getStakingModuleSummary + /// is the same as StakingRouter expects based on the total count received from the oracle. function onExitedAndStuckValidatorsCountsUpdated() external { _auth(STAKING_ROUTER_ROLE); // for the permissioned module, we're distributing rewards within oracle operation diff --git a/contracts/0.8.9/StakingRouter.sol b/contracts/0.8.9/StakingRouter.sol index 23fbb8d73..038d33429 100644 --- a/contracts/0.8.9/StakingRouter.sol +++ b/contracts/0.8.9/StakingRouter.sol @@ -277,6 +277,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version { for (uint256 i = 0; i < _stakingModuleIds.length; ) { StakingModule storage stakingModule = _getStakingModuleById(_stakingModuleIds[i]); + uint256 prevReportedExitedValidatorsCount = stakingModule.exitedValidatorsCount; if (_exitedValidatorsCounts[i] < prevReportedExitedValidatorsCount) { revert ExitedValidatorsCountCannotDecrease(); @@ -295,6 +296,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version prevReportedExitedValidatorsCount - totalExitedValidatorsCount ); } + stakingModule.exitedValidatorsCount = _exitedValidatorsCounts[i]; unchecked { ++i; } } @@ -308,28 +310,11 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version external onlyRole(REPORT_EXITED_VALIDATORS_ROLE) { - StakingModule storage stakingModule = _getStakingModuleById(_stakingModuleId); - IStakingModule moduleContract = IStakingModule(stakingModule.stakingModuleAddress); - ( - uint256 prevExitedValidatorsCount, - /* uint256 totalDepositedValidators */, - /* uint256 depositableValidatorsCount */ - ) = moduleContract.getStakingModuleSummary(); - - moduleContract.updateExitedValidatorsCount(_nodeOperatorIds, _exitedValidatorsCounts); - - uint256 prevReportedExitedValidatorsCount = stakingModule.exitedValidatorsCount; - ( - uint256 newExitedValidatorsCount, - /* uint256 totalDepositedValidators */, - /* uint256 depositableValidatorsCount */ - ) = moduleContract.getStakingModuleSummary(); - if (prevExitedValidatorsCount < prevReportedExitedValidatorsCount && - newExitedValidatorsCount >= prevReportedExitedValidatorsCount - ) { - // oracle finished updating exited validators for all node ops - moduleContract.onExitedAndStuckValidatorsCountsUpdated(); - } + address moduleAddr = _getStakingModuleById(_stakingModuleId).stakingModuleAddress; + IStakingModule(moduleAddr).updateExitedValidatorsCount( + _nodeOperatorIds, + _exitedValidatorsCounts + ); } struct ValidatorsCountsCorrection { @@ -429,6 +414,26 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version IStakingModule(moduleAddr).updateStuckValidatorsCount(_nodeOperatorIds, _stuckValidatorsCounts); } + function onValidatorsCountsByNodeOperatorReportingFinished() + external + onlyRole(REPORT_EXITED_VALIDATORS_ROLE) + { + uint256 stakingModulesCount = getStakingModulesCount(); + + for (uint256 i; i < stakingModulesCount; ) { + StakingModule storage stakingModule = _getStakingModuleByIndex(i); + IStakingModule moduleContract = IStakingModule(stakingModule.stakingModuleAddress); + + (uint256 exitedValidatorsCount, , ) = moduleContract.getStakingModuleSummary(); + if (exitedValidatorsCount == stakingModule.exitedValidatorsCount) { + // oracle finished updating exited validators for all node ops + moduleContract.onExitedAndStuckValidatorsCountsUpdated(); + } + + unchecked { ++i; } + } + } + function getExitedValidatorsCountAcrossAllModules() external view returns (uint256) { uint256 stakingModulesCount = getStakingModulesCount(); uint256 exitedValidatorsCount = 0; diff --git a/contracts/0.8.9/interfaces/IStakingModule.sol b/contracts/0.8.9/interfaces/IStakingModule.sol index 4184d042c..dee857212 100644 --- a/contracts/0.8.9/interfaces/IStakingModule.sol +++ b/contracts/0.8.9/interfaces/IStakingModule.sol @@ -127,6 +127,11 @@ interface IStakingModule { /// @notice Called by StakingRouter after it finishes updating exited and stuck validators /// counts for this module's node operators. + /// + /// Guaranteed to be called after an oracle report is applied, regardless of whether any node + /// operator in this module has actually received any updated counts as a result of the report + /// but given that the total number of exited validators returned from getStakingModuleSummary + /// is the same as StakingRouter expects based on the total count received from the oracle. function onExitedAndStuckValidatorsCountsUpdated() external; /// @notice Called by StakingRouter when withdrawal credentials are changed. diff --git a/contracts/0.8.9/oracle/AccountingOracle.sol b/contracts/0.8.9/oracle/AccountingOracle.sol index 8043dc59c..f6ef31d40 100644 --- a/contracts/0.8.9/oracle/AccountingOracle.sol +++ b/contracts/0.8.9/oracle/AccountingOracle.sol @@ -74,6 +74,8 @@ interface IStakingRouter { bytes calldata nodeOperatorIds, bytes calldata stuckValidatorsCounts ) external; + + function onValidatorsCountsByNodeOperatorReportingFinished() external; } @@ -118,6 +120,7 @@ contract AccountingOracle is BaseOracle { struct ExtraDataProcessingState { uint64 refSlot; uint16 dataFormat; + bool submitted; uint64 itemsCount; uint64 itemsProcessed; uint256 lastSortingKey; @@ -139,7 +142,13 @@ contract AccountingOracle is BaseOracle { /// Initialization & admin functions /// - constructor(address lidoLocator, address lido, address legacyOracle, uint256 secondsPerSlot, uint256 genesisTime) + constructor( + address lidoLocator, + address lido, + address legacyOracle, + uint256 secondsPerSlot, + uint256 genesisTime + ) BaseOracle(secondsPerSlot, genesisTime) { if (lidoLocator == address(0)) revert LidoLocatorCannotBeZero(); @@ -376,6 +385,13 @@ contract AccountingOracle is BaseOracle { _handleConsensusReportData(data, prevRefSlot); } + /// @notice Triggers the processing required when no extra data is present in the report, + /// i.e. when extra data format equals EXTRA_DATA_FORMAT_EMPTY. + /// + function submitReportExtraDataEmpty() external { + _submitReportExtraDataEmpty(); + } + /// @notice Submits report extra data in the EXTRA_DATA_FORMAT_LIST format for processing. /// /// @param items The extra data items list. See docs for the `EXTRA_DATA_FORMAT_LIST` @@ -393,17 +409,19 @@ contract AccountingOracle is BaseOracle { /// @notice Hash of the main report data. Zero bytes if consensus on the hash hasn't been /// reached yet for the current reporting frame. bytes32 mainDataHash; - /// @notice Whether main report data for the for the current reporting frame has been - /// already submitted. + /// @notice Whether the main report data for the current reporting frame has already been + /// submitted. bool mainDataSubmitted; - /// @notice Hash of the extra report data. Zero bytes if consensus on the main data hash - /// hasn't been reached yet, or if the main report data hasn't been submitted yet, for the - /// current reporting frame. Also zero bytes if the current reporting frame's data doesn't - /// contain any extra data. + /// @notice Hash of the extra report data. Should be ignored unless `mainDataSubmitted` + /// is true. bytes32 extraDataHash; - /// @notice Format of the extra report data for the current reporting frame. + /// @notice Format of the extra report data for the current reporting frame. Should be + /// ignored unless `mainDataSubmitted` is true. uint256 extraDataFormat; + /// @notice Whether any extra report data for the current reporting frame has been submitted. + bool extraDataSubmitted; /// @notice Total number of extra report data items for the current reporting frame. + /// Should be ignored unless `mainDataSubmitted` is true. uint256 extraDataItemsCount; /// @notice How many extra report data items are already submitted for the current /// reporting frame. @@ -431,12 +449,9 @@ contract AccountingOracle is BaseOracle { } ExtraDataProcessingState memory extraState = _storageExtraDataProcessingState().value; - if (extraState.dataHash == bytes32(0) || extraState.refSlot != processingRefSlot) { - return result; - } - result.extraDataHash = extraState.dataHash; result.extraDataFormat = extraState.dataFormat; + result.extraDataSubmitted = extraState.submitted; result.extraDataItemsCount = extraState.itemsCount; result.extraDataItemsSubmitted = extraState.itemsProcessed; } @@ -462,7 +477,8 @@ contract AccountingOracle is BaseOracle { /// /// 0. last reference slot of legacy oracle /// 1. last legacy oracle's consensus report arrives - /// 2. new oracle is deployed and enabled, legacy oracle is disabled and upgraded to compatibility code + /// 2. new oracle is deployed and enabled, legacy oracle is disabled and upgraded to + /// the compatibility implementation /// 3. first reference slot of the new oracle /// 4. first new oracle's consensus report arrives /// @@ -523,7 +539,9 @@ contract AccountingOracle is BaseOracle { uint256 prevProcessingRefSlot ) internal override { ExtraDataProcessingState memory state = _storageExtraDataProcessingState().value; - if (state.refSlot == prevProcessingRefSlot && state.itemsProcessed < state.itemsCount) { + if (state.refSlot == prevProcessingRefSlot && ( + !state.submitted || state.itemsProcessed < state.itemsCount + )) { emit WarnExtraDataIncompleteProcessing( prevProcessingRefSlot, state.itemsProcessed, @@ -599,6 +617,7 @@ contract AccountingOracle is BaseOracle { _storageExtraDataProcessingState().value = ExtraDataProcessingState({ refSlot: data.refSlot.toUint64(), dataFormat: data.extraDataFormat.toUint16(), + submitted: false, dataHash: data.extraDataHash, itemsCount: data.extraDataItemsCount.toUint16(), itemsProcessed: 0, @@ -655,6 +674,30 @@ contract AccountingOracle is BaseOracle { ); } + function _submitReportExtraDataEmpty() internal { + ExtraDataProcessingState memory procState = _storageExtraDataProcessingState().value; + _checkCanSubmitExtraData(procState, EXTRA_DATA_FORMAT_EMPTY); + if (procState.submitted) revert ExtraDataAlreadyProcessed(); + IStakingRouter(LOCATOR.stakingRouter()).onValidatorsCountsByNodeOperatorReportingFinished(); + _storageExtraDataProcessingState().value.submitted = true; + emit ExtraDataSubmitted(procState.refSlot, 0, 0); + } + + function _checkCanSubmitExtraData(ExtraDataProcessingState memory procState, uint256 format) + internal + { + _checkMsgSenderIsAllowedToSubmitData(); + _checkProcessingDeadline(); + + if (procState.refSlot != LAST_PROCESSING_REF_SLOT_POSITION.getStorageUint256()) { + revert CannotSubmitExtraDataBeforeMainData(); + } + + if (procState.dataFormat != format) { + revert UnexpectedExtraDataFormat(procState.dataFormat, format); + } + } + struct ExtraDataIterState { // volatile uint256 index; @@ -666,18 +709,8 @@ contract AccountingOracle is BaseOracle { } function _submitReportExtraDataList(bytes calldata items) internal { - _checkMsgSenderIsAllowedToSubmitData(); - _checkProcessingDeadline(); - ExtraDataProcessingState memory procState = _storageExtraDataProcessingState().value; - - if (procState.refSlot != LAST_PROCESSING_REF_SLOT_POSITION.getStorageUint256()) { - revert CannotSubmitExtraDataBeforeMainData(); - } - - if (procState.dataFormat != EXTRA_DATA_FORMAT_LIST) { - revert UnexpectedExtraDataFormat(procState.dataFormat, EXTRA_DATA_FORMAT_LIST); - } + _checkCanSubmitExtraData(procState, EXTRA_DATA_FORMAT_LIST); if (procState.itemsProcessed == procState.itemsCount) { revert ExtraDataAlreadyProcessed(); @@ -707,10 +740,12 @@ contract AccountingOracle is BaseOracle { revert UnexpectedExtraDataItemsCount(procState.itemsCount, itemsProcessed); } - ExtraDataProcessingState storage _procState = _storageExtraDataProcessingState().value; - _procState.itemsProcessed = uint64(itemsProcessed); - _procState.lastSortingKey = iter.lastSortingKey; + procState.submitted = true; + procState.itemsProcessed = uint64(itemsProcessed); + procState.lastSortingKey = iter.lastSortingKey; + _storageExtraDataProcessingState().value = procState; + IStakingRouter(iter.stakingRouter).onValidatorsCountsByNodeOperatorReportingFinished(); emit ExtraDataSubmitted(procState.refSlot, itemsProcessed, itemsProcessed); } diff --git a/contracts/0.8.9/test_helpers/oracle/MockStakingRouterForAccountingOracle.sol b/contracts/0.8.9/test_helpers/oracle/MockStakingRouterForAccountingOracle.sol index 06e4bb0a2..0efb0d2f4 100644 --- a/contracts/0.8.9/test_helpers/oracle/MockStakingRouterForAccountingOracle.sol +++ b/contracts/0.8.9/test_helpers/oracle/MockStakingRouterForAccountingOracle.sol @@ -25,6 +25,8 @@ contract MockStakingRouterForAccountingOracle is IStakingRouter { ReportKeysByNodeOperatorCallData[] public calls_reportExitedKeysByNodeOperator; ReportKeysByNodeOperatorCallData[] public calls_reportStuckKeysByNodeOperator; + uint256 public totalCalls_onValidatorsCountsByNodeOperatorReportingFinished; + function setExitedKeysCountAcrossAllModules(uint256 count) external { _exitedKeysCountAcrossAllModules = count; @@ -80,4 +82,8 @@ contract MockStakingRouterForAccountingOracle is IStakingRouter { stakingModuleId, nodeOperatorIds, stuckKeysCounts )); } + + function onValidatorsCountsByNodeOperatorReportingFinished() external { + ++totalCalls_onValidatorsCountsByNodeOperatorReportingFinished; + } } diff --git a/test/0.4.24/node-operators-registry.test.js b/test/0.4.24/node-operators-registry.test.js index a00d32d7b..57db0b3a5 100644 --- a/test/0.4.24/node-operators-registry.test.js +++ b/test/0.4.24/node-operators-registry.test.js @@ -3325,7 +3325,7 @@ contract('NodeOperatorsRegistry', ([appManager, voting, user1, user2, user3, nob await steth.mintShares(app.address, ETH(10)) // calls distributeRewards() inside - const tx = await app.onAllValidatorCountersUpdated({ from: voting }) + const tx = await app.onExitedAndStuckValidatorsCountsUpdated({ from: voting }) // just show the used gas console.log(`gas used to distribute rewards for ${maxNodeOperatorsCount} NOs:`, +tx.receipt.gasUsed) diff --git a/test/0.8.9/oracle/accounting-oracle-access-control.test.js b/test/0.8.9/oracle/accounting-oracle-access-control.test.js index 15afa1359..adb8f9ae5 100644 --- a/test/0.8.9/oracle/accounting-oracle-access-control.test.js +++ b/test/0.8.9/oracle/accounting-oracle-access-control.test.js @@ -9,7 +9,9 @@ const { packExtraDataList, calcExtraDataListHash, calcReportDataHash, - EXTRA_DATA_FORMAT_LIST + EXTRA_DATA_FORMAT_EMPTY, + EXTRA_DATA_FORMAT_LIST, + ZERO_HASH } = require('./accounting-oracle-deploy.test') contract('AccountingOracle', ([admin, account1, account2, member1, member2, stranger]) => { @@ -22,7 +24,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra const submitDataRoleKeccak156 = web3.utils.keccak256('SUBMIT_DATA_ROLE') - const deploy = async (options = undefined) => { + const deploy = async ({emptyExtraData = false} = {}) => { const deployed = await deployAndConfigureAccountingOracle(admin) const { refSlot } = await deployed.consensus.getCurrentFrame() @@ -41,6 +43,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra const extraDataItems = encodeExtraDataItems(extraData) extraDataList = packExtraDataList(extraDataItems) const extraDataHash = calcExtraDataListHash(extraDataList) + reportFields = { consensusVersion: CONSENSUS_VERSION, refSlot: +refSlot, @@ -53,9 +56,9 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra lastWithdrawalRequestIdToFinalize: 1, finalizationShareRate: e27(1), isBunkerMode: true, - extraDataFormat: EXTRA_DATA_FORMAT_LIST, - extraDataHash: extraDataHash, - extraDataItemsCount: extraDataItems.length + extraDataFormat: emptyExtraData ? EXTRA_DATA_FORMAT_EMPTY : EXTRA_DATA_FORMAT_LIST, + extraDataHash: emptyExtraData ? ZERO_HASH : extraDataHash, + extraDataItemsCount: emptyExtraData ? 0 : extraDataItems.length } reportItems = getReportDataItems(reportFields) const reportHash = calcReportDataHash(reportItems) @@ -136,5 +139,35 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) }) }) + + context('submitReportExtraDataEmpty', () => { + beforeEach(() => deploy({emptyExtraData: true})) + + it('should revert from not consensus member without SUBMIT_DATA_ROLE role ', async () => { + await assert.reverts(oracle.submitReportExtraDataEmpty({ from: account1 }), 'SenderNotAllowed()') + }) + + it('should allow calling from a possessor of SUBMIT_DATA_ROLE role', async () => { + await oracle.grantRole(submitDataRoleKeccak156, account2) + const deadline = (await oracle.getConsensusReport()).processingDeadlineTime + await consensus.setTime(deadline) + + await oracle.submitReportData(reportItems, CONSENSUS_VERSION, { from: account2 }) + const tx = await oracle.submitReportExtraDataEmpty({ from: account2 }) + + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) + }) + + it('should allow calling from a member', async () => { + await consensus.addMember(member2, 2) + const deadline = (await oracle.getConsensusReport()).processingDeadlineTime + await consensus.setTime(deadline) + + await oracle.submitReportData(reportItems, CONSENSUS_VERSION, { from: member2 }) + const tx = await oracle.submitReportExtraDataEmpty({ from: member2 }) + + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot }) + }) + }) }) }) diff --git a/test/0.8.9/oracle/accounting-oracle-deploy.test.js b/test/0.8.9/oracle/accounting-oracle-deploy.test.js index ece7864b8..6bd5abb21 100644 --- a/test/0.8.9/oracle/accounting-oracle-deploy.test.js +++ b/test/0.8.9/oracle/accounting-oracle-deploy.test.js @@ -43,9 +43,9 @@ const V1_ORACLE_LAST_REPORT_SLOT = V1_ORACLE_LAST_COMPLETED_EPOCH * SLOTS_PER_EP const EXTRA_DATA_FORMAT_EMPTY = 0 const EXTRA_DATA_FORMAT_LIST = 1 - const EXTRA_DATA_TYPE_STUCK_VALIDATORS = 1 const EXTRA_DATA_TYPE_EXITED_VALIDATORS = 2 + function getReportDataItems(r) { return [ r.consensusVersion, @@ -269,6 +269,7 @@ async function deployAndConfigureAccountingOracle(admin) { const initTx = await initAccountingOracle({ admin, ...deployed }) return { ...deployed, initTx } } + contract('AccountingOracle', ([admin, member1]) => { let consensus let oracle diff --git a/test/0.8.9/oracle/accounting-oracle-happy-path.test.js b/test/0.8.9/oracle/accounting-oracle-happy-path.test.js index 18bdc4939..d76ed1733 100644 --- a/test/0.8.9/oracle/accounting-oracle-happy-path.test.js +++ b/test/0.8.9/oracle/accounting-oracle-happy-path.test.js @@ -1,20 +1,26 @@ -const { BN } = require('bn.js') const { assert } = require('../../helpers/assert') -const { assertBn, assertEvent, assertAmountOfEvents } = require('@aragon/contract-helpers-test/src/asserts') -const { assertRevert } = require('../../helpers/assertThrow') -const { e9, e18, e27, hex, printEvents } = require('../../helpers/utils') -const { ZERO_ADDRESS, bn } = require('@aragon/contract-helpers-test') +const { assertBn } = require('@aragon/contract-helpers-test/src/asserts') +const { e9, e18, e27, hex } = require('../../helpers/utils') const { - SLOTS_PER_EPOCH, SECONDS_PER_SLOT, GENESIS_TIME, SECONDS_PER_EPOCH, - EPOCHS_PER_FRAME, SLOTS_PER_FRAME, SECONDS_PER_FRAME, - computeSlotAt, computeEpochAt, computeEpochFirstSlotAt, - computeEpochFirstSlot, computeTimestampAtSlot, computeTimestampAtEpoch, - ZERO_HASH, CONSENSUS_VERSION, + SECONDS_PER_SLOT, + GENESIS_TIME, + SECONDS_PER_EPOCH, + SLOTS_PER_FRAME, + SECONDS_PER_FRAME, + computeTimestampAtSlot, + ZERO_HASH, + CONSENSUS_VERSION, V1_ORACLE_LAST_REPORT_SLOT, - EXTRA_DATA_FORMAT_LIST, EXTRA_DATA_TYPE_STUCK_VALIDATORS, EXTRA_DATA_TYPE_EXITED_VALIDATORS, - deployAndConfigureAccountingOracle, getReportDataItems, calcReportDataHash, encodeExtraDataItems, - packExtraDataList, calcExtraDataListHash} = require('./accounting-oracle-deploy.test') + EXTRA_DATA_FORMAT_EMPTY, + EXTRA_DATA_FORMAT_LIST, + deployAndConfigureAccountingOracle, + getReportDataItems, + calcReportDataHash, + encodeExtraDataItems, + packExtraDataList, + calcExtraDataListHash +} = require('./accounting-oracle-deploy.test') contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { @@ -77,6 +83,7 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { assert.isFalse(procState.mainDataSubmitted) assert.equal(procState.extraDataHash, ZERO_HASH) assert.equal(+procState.extraDataFormat, 0) + assert.isFalse(procState.extraDataSubmitted) assert.equal(+procState.extraDataItemsCount, 0) assert.equal(+procState.extraDataItemsSubmitted, 0) }) @@ -152,6 +159,7 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { assert.isFalse(procState.mainDataSubmitted) assert.equal(procState.extraDataHash, ZERO_HASH) assert.equal(+procState.extraDataFormat, 0) + assert.isFalse(procState.extraDataSubmitted) assert.equal(+procState.extraDataItemsCount, 0) assert.equal(+procState.extraDataItemsSubmitted, 0) }) @@ -161,14 +169,14 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { }) it('non-member cannot submit the data', async () => { - await assertRevert( + await assert.reverts( oracle.submitReportData(reportItems, oracleVersion, {from: stranger}), 'SenderNotAllowed()' ) }) it('the data cannot be submitted passing a different contract version', async () => { - await assertRevert( + await assert.reverts( oracle.submitReportData(reportItems, oracleVersion - 1, {from: member1}), `UnexpectedContractVersion(${oracleVersion}, ${oracleVersion - 1})` ) @@ -178,7 +186,7 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { const invalidReport = { ...reportFields, numValidators: reportFields.numValidators + 1 } const invalidReportItems = getReportDataItems(invalidReport) const invalidReportHash = calcReportDataHash(invalidReportItems) - await assertRevert( + await assert.reverts( oracle.submitReportData(invalidReportItems, oracleVersion, {from: member1}), `UnexpectedDataHash("${reportHash}", "${invalidReportHash}")` ) @@ -189,7 +197,7 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { it(`a committee member submits the rebase data`, async () => { prevProcessingRefSlot = +await oracle.getLastProcessingRefSlot() const tx = await oracle.submitReportData(reportItems, oracleVersion, {from: member1}) - assertEvent(tx, 'ProcessingStarted', {expectedArgs: {refSlot: reportFields.refSlot}}) + assert.emits(tx, 'ProcessingStarted', {refSlot: reportFields.refSlot}) assert.isTrue((await oracle.getConsensusReport()).processingStarted) assert.isAbove(+await oracle.getLastProcessingRefSlot(), prevProcessingRefSlot) }) @@ -207,6 +215,7 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { assert.isTrue(procState.mainDataSubmitted) assert.equal(procState.extraDataHash, reportFields.extraDataHash) assert.equal(+procState.extraDataFormat, reportFields.extraDataFormat) + assert.isFalse(procState.extraDataSubmitted) assert.equal(+procState.extraDataItemsCount, reportFields.extraDataItemsCount) assert.equal(+procState.extraDataItemsSubmitted, 0) }) @@ -224,7 +233,6 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { assertBn(lastOracleReportCall.elRewardsVaultBalance, reportFields.elRewardsVaultBalance) assertBn(lastOracleReportCall.lastWithdrawalRequestIdToFinalize, reportFields.lastWithdrawalRequestIdToFinalize) assertBn(lastOracleReportCall.finalizationShareRate, reportFields.finalizationShareRate) - // assert.equal(lastOracleReportCall.isBunkerMode, reportFields.isBunkerMode) }) it(`withdrawal queue got bunker mode report`, async () => { @@ -271,7 +279,7 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { }) it('a non-member cannot submit extra data', async () => { - await assertRevert( + await assert.reverts( oracle.submitReportExtraDataList(extraDataList, {from: stranger}), 'SenderNotAllowed()' ) @@ -287,20 +295,27 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { const invalidExtraDataItems = encodeExtraDataItems(invalidExtraData) const invalidExtraDataList = packExtraDataList(invalidExtraDataItems) const invalidExtraDataHash = calcExtraDataListHash(invalidExtraDataList) - await assertRevert( + await assert.reverts( oracle.submitReportExtraDataList(invalidExtraDataList, {from: member2}), `UnexpectedExtraDataHash("${extraDataHash}", "${invalidExtraDataHash}")` ) }) + it(`an empty extra data cannot be submitted`, async () => { + await assert.reverts( + oracle.submitReportExtraDataEmpty({from: member2}), + `UnexpectedExtraDataFormat(${EXTRA_DATA_FORMAT_LIST}, ${EXTRA_DATA_FORMAT_EMPTY})` + ) + }) + it('a committee member submits extra data', async () => { const tx = await oracle.submitReportExtraDataList(extraDataList, {from: member2}) - assertEvent(tx, 'ExtraDataSubmitted', {expectedArgs: { + assert.emits(tx, 'ExtraDataSubmitted', { refSlot: reportFields.refSlot, itemsProcessed: extraDataItems.length, itemsCount: extraDataItems.length, - }}) + }) const frame = await consensus.getCurrentFrame() const procState = await oracle.getProcessingState() @@ -314,6 +329,7 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { assert.isTrue(procState.mainDataSubmitted) assert.equal(procState.extraDataHash, reportFields.extraDataHash) assert.equal(+procState.extraDataFormat, reportFields.extraDataFormat) + assert.isTrue(procState.extraDataSubmitted) assert.equal(+procState.extraDataItemsCount, reportFields.extraDataItemsCount) assert.equal(+procState.extraDataItemsSubmitted, extraDataItems.length) }) @@ -353,11 +369,122 @@ contract('AccountingOracle', ([admin, member1, member2, member3, stranger]) => { assert.equal(call3.keysCounts, '0x' + [3].map(i => hex(i, 16)).join('')) }) + it('Staking router was told that stuck and exited keys updating is finished', async () => { + const totalFinishedCalls = +await mockStakingRouter.totalCalls_onValidatorsCountsByNodeOperatorReportingFinished() + assert.equal(totalFinishedCalls, 1) + }) + it(`extra data for the same reference slot cannot be re-submitted`, async () => { await assert.reverts( oracle.submitReportExtraDataList(extraDataList, {from: member1}), 'ExtraDataAlreadyProcessed()' ) }) + + it('some time passes, a new reporting frame starts', async () => { + await consensus.advanceTimeToNextFrameStart() + + const frame = await consensus.getCurrentFrame() + const procState = await oracle.getProcessingState() + + assert.equal(+procState.currentFrameRefSlot, +frame.refSlot) + assert.equal(+procState.processingDeadlineTime, 0) + assert.equal(procState.mainDataHash, ZERO_HASH) + assert.isFalse(procState.mainDataSubmitted) + assert.equal(procState.extraDataHash, ZERO_HASH) + assert.equal(+procState.extraDataFormat, 0) + assert.isFalse(procState.extraDataSubmitted) + assert.equal(+procState.extraDataItemsCount, 0) + assert.equal(+procState.extraDataItemsSubmitted, 0) + }) + + it('new data report with empty extra data is agreed upon and submitted', async () => { + const {refSlot} = await consensus.getCurrentFrame() + + reportFields = { + ...reportFields, + refSlot: +refSlot, + extraDataFormat: EXTRA_DATA_FORMAT_EMPTY, + extraDataHash: ZERO_HASH, + extraDataItemsCount: 0, + } + reportItems = getReportDataItems(reportFields) + reportHash = calcReportDataHash(reportItems) + + await triggerConsensusOnHash(reportHash) + + const tx = await oracle.submitReportData(reportItems, oracleVersion, {from: member2}) + assert.emits(tx, 'ProcessingStarted', {refSlot: reportFields.refSlot}) + }) + + it(`Lido got the oracle report`, async () => { + const lastOracleReportCall = await mockLido.getLastCall_handleOracleReport() + assert.equal(lastOracleReportCall.callCount, 2) + }) + + it(`withdrawal queue got bunker mode report`, async () => { + const updateBunkerModeLastCall = await mockWithdrawalQueue.lastCall__updateBunkerMode() + assert.equal(+updateBunkerModeLastCall.callCount, 2) + }) + + it(`Staking router got the exited keys report`, async () => { + const lastExitedKeysByModuleCall = await mockStakingRouter.lastCall_updateExitedKeysByModule() + assert.equal(lastExitedKeysByModuleCall.callCount, 2) + }) + + it(`a non-empty extra data cannot be submitted`, async () => { + await assert.reverts( + oracle.submitReportExtraDataList(extraDataList, {from: member2}), + `UnexpectedExtraDataFormat(${EXTRA_DATA_FORMAT_EMPTY}, ${EXTRA_DATA_FORMAT_LIST})` + ) + }) + + it('a committee member submits empty extra data', async () => { + const tx = await oracle.submitReportExtraDataEmpty({from: member3}) + + assert.emits(tx, 'ExtraDataSubmitted', { + refSlot: reportFields.refSlot, + itemsProcessed: 0, + itemsCount: 0, + }) + + const frame = await consensus.getCurrentFrame() + const procState = await oracle.getProcessingState() + + assert.equal(+procState.currentFrameRefSlot, +frame.refSlot) + assert.equal( + +procState.processingDeadlineTime, + computeTimestampAtSlot(+frame.reportProcessingDeadlineSlot) + ) + assert.equal(procState.mainDataHash, reportHash) + assert.isTrue(procState.mainDataSubmitted) + assert.equal(procState.extraDataHash, ZERO_HASH) + assert.equal(+procState.extraDataFormat, EXTRA_DATA_FORMAT_EMPTY) + assert.isTrue(procState.extraDataSubmitted) + assert.equal(+procState.extraDataItemsCount, 0) + assert.equal(+procState.extraDataItemsSubmitted, 0) + }) + + it(`Staking router didn't get the exited keys by node op report`, async () => { + const totalReportCalls = +await mockStakingRouter.totalCalls_reportExitedKeysByNodeOperator() + assert.equal(totalReportCalls, 2) + }) + + it(`Staking router didn't get the stuck keys by node op report`, async () => { + const totalReportCalls = +await mockStakingRouter.totalCalls_reportStuckKeysByNodeOperator() + assert.equal(totalReportCalls, 3) + }) + + it('Staking router was told that stuck and exited keys updating is finished', async () => { + const totalFinishedCalls = +await mockStakingRouter.totalCalls_onValidatorsCountsByNodeOperatorReportingFinished() + assert.equal(totalFinishedCalls, 2) + }) + + it(`extra data for the same reference slot cannot be re-submitted`, async () => { + await assert.reverts( + oracle.submitReportExtraDataEmpty({from: member1}), + 'ExtraDataAlreadyProcessed()' + ) + }) }) }) diff --git a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js index 91b209c16..f1f9a3c71 100644 --- a/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js +++ b/test/0.8.9/oracle/accounting-oracle-submit-report-extra-data.test.js @@ -548,7 +548,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra }) context('delivers the data to staking router', () => { - it('calling reportStakingModuleStuckValidatorsCountByNodeOperator on StakingRouter', async () => { + it('calls reportStakingModuleStuckValidatorsCountByNodeOperator on StakingRouter', async () => { const { extraData, extraDataList } = await prepareNextReportInNextFrame() await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) @@ -564,7 +564,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra } }) - it('calling reportStakingModuleExitedValidatorsCountByNodeOperator on StakingRouter', async () => { + it('calls reportStakingModuleExitedValidatorsCountByNodeOperator on StakingRouter', async () => { const { extraData, extraDataList } = await prepareNextReportInNextFrame() await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) @@ -579,6 +579,13 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra assert.equals(call.keysCounts, '0x' + item.keysCounts.map((count) => hex(count, 16)).join('')) } }) + + it('calls onValidatorsCountsByNodeOperatorReportingFinished on StakingRouter', async () => { + const { extraData, extraDataList } = await prepareNextReportInNextFrame() + await oracle.submitReportExtraDataList(extraDataList, { from: member1 }) + const callsCount = await stakingRouter.totalCalls_onValidatorsCountsByNodeOperatorReportingFinished() + assert.equals(callsCount, 1) + }) }) it('reverts if extraData has already been already processed', async () => { @@ -611,6 +618,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra assert.equals(+stateBefore.refSlot, reportFields.refSlot) assert.equals(+stateBefore.dataFormat, EXTRA_DATA_FORMAT_LIST) + assert.isFalse(stateBefore.submitted) assert.equals(+stateBefore.itemsCount, extraDataItems.length) assert.equals(+stateBefore.itemsProcessed, 0) assert.equals(+stateBefore.lastSortingKey, '0') @@ -622,6 +630,7 @@ contract('AccountingOracle', ([admin, account1, account2, member1, member2, stra assert.equals(+stateAfter.refSlot, reportFields.refSlot) assert.equals(+stateAfter.dataFormat, EXTRA_DATA_FORMAT_LIST) + assert.isTrue(stateAfter.submitted) assert.equals(+stateAfter.itemsCount, extraDataItems.length) assert.equals(stateAfter.itemsProcessed, extraDataItems.length) // TODO: figure out how to build this value and test it properly diff --git a/test/helpers/factories.js b/test/helpers/factories.js index 8dad00bf4..896c97b18 100644 --- a/test/helpers/factories.js +++ b/test/helpers/factories.js @@ -196,7 +196,7 @@ async function withdrawalCredentialsFactory() { return '0x'.padEnd(66, '1234') } -async function stakingRouterFactory({ depositContract, dao, appManager, voting, pool, withdrawalCredentials }) { +async function stakingRouterFactory({ depositContract, dao, appManager, voting, pool, oracle, withdrawalCredentials }) { const base = await StakingRouter.new(depositContract.address) const proxyAddress = await newApp(dao, 'lido-oracle', base.address, appManager.address) @@ -218,10 +218,10 @@ async function stakingRouterFactory({ depositContract, dao, appManager, voting, await stakingRouter.grantRole(await stakingRouter.STAKING_MODULE_MANAGE_ROLE(), voting.address, { from: appManager.address }) - await stakingRouter.grantRole(await stakingRouter.REPORT_EXITED_VALIDATORS_ROLE(), pool.address, { + await stakingRouter.grantRole(await stakingRouter.REPORT_EXITED_VALIDATORS_ROLE(), voting.address, { from: appManager.address }) - await stakingRouter.grantRole(await stakingRouter.REPORT_EXITED_VALIDATORS_ROLE(), voting.address, { + await stakingRouter.grantRole(await stakingRouter.REPORT_EXITED_VALIDATORS_ROLE(), oracle.address, { from: appManager.address }) await stakingRouter.grantRole(await stakingRouter.UNSAFE_SET_EXITED_VALIDATORS_ROLE(), voting.address, { diff --git a/test/helpers/oracle.js b/test/helpers/oracle.js index d1cd8d65b..704abed4a 100644 --- a/test/helpers/oracle.js +++ b/test/helpers/oracle.js @@ -66,7 +66,10 @@ async function pushOracleReport(consensus, oracle, numValidators, clBalance, elR const oracleVersion = await oracle.getContractVersion() - return await oracle.submitReportData(reportItems, oracleVersion, { from: members.addresses[0] }) + const submitDataTx = await oracle.submitReportData(reportItems, oracleVersion, { from: members.addresses[0] }) + const submitExtraDataTx = await oracle.submitReportExtraDataEmpty({ from: members.addresses[0] }) + + return { submitDataTx, submitExtraDataTx } } module.exports = { getReportDataItems, calcReportDataHash, pushOracleReport } diff --git a/test/helpers/protocol.js b/test/helpers/protocol.js index 68e1c2879..2649da274 100644 --- a/test/helpers/protocol.js +++ b/test/helpers/protocol.js @@ -30,11 +30,16 @@ async function deployProtocol(factories = {}, deployParams = {}) { protocol.burner = await protocol.factories.burnerFactory(protocol) protocol.lidoLocator = await protocol.factories.lidoLocatorFactory(protocol) + await updateLocatorImplementation(protocol.lidoLocator.address, protocol.appManager.address, { lido: protocol.pool.address, burner: protocol.burner.address }) + protocol.validatorExitBus = await protocol.factories.validatorExitBusFactory(protocol) + protocol.oracleReportSanityChecker = await protocol.factories.oracleReportSanityCheckerFactory(protocol) + protocol.oracle = await protocol.factories.accountingOracleFactory(protocol) + protocol.withdrawalCredentials = await protocol.factories.withdrawalCredentialsFactory(protocol) protocol.stakingRouter = await protocol.factories.stakingRouterFactory(protocol) protocol.stakingModules = await addStakingModules(protocol.factories.stakingModulesFactory, protocol) @@ -51,14 +56,7 @@ async function deployProtocol(factories = {}, deployParams = {}) { stakingRouter: protocol.stakingRouter.address, treasury: protocol.treasury.address, withdrawalVault: protocol.withdrawalVault.address, - postTokenRebaseReceiver: protocol.legacyOracle.address - }) - - protocol.validatorExitBus = await protocol.factories.validatorExitBusFactory(protocol) - protocol.oracleReportSanityChecker = await protocol.factories.oracleReportSanityCheckerFactory(protocol) - protocol.oracle = await protocol.factories.accountingOracleFactory(protocol) - - await updateLocatorImplementation(protocol.lidoLocator.address, protocol.appManager.address, { + postTokenRebaseReceiver: protocol.legacyOracle.address, accountingOracle: protocol.oracle.address, oracleReportSanityChecker: protocol.oracleReportSanityChecker.address, validatorsExitBusOracle: protocol.validatorExitBus.address diff --git a/test/scenario/lido_rewards_distribution_math.js b/test/scenario/lido_rewards_distribution_math.js index 6ba20bcc5..c55dcd4f9 100644 --- a/test/scenario/lido_rewards_distribution_math.js +++ b/test/scenario/lido_rewards_distribution_math.js @@ -70,11 +70,11 @@ contract('Lido: rewards distribution math', (addresses) => { } async function reportBeacon(validatorsCount, balance) { - const tx = await pushOracleReport(consensus, oracle, validatorsCount, balance) + const { submitDataTx } = await pushOracleReport(consensus, oracle, validatorsCount, balance) await ethers.provider.send('evm_increaseTime', [SECONDS_PER_FRAME + 1000]) await ethers.provider.send('evm_mine') - return tx + return submitDataTx } before(async () => { From f979709ff50a26508ddc0764960dafbdb1e890d8 Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Tue, 21 Feb 2023 01:41:15 +0200 Subject: [PATCH 191/199] tests: fix an assertion message --- test/helpers/assert.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/helpers/assert.js b/test/helpers/assert.js index 94c8bde35..b48d07fad 100644 --- a/test/helpers/assert.js +++ b/test/helpers/assert.js @@ -53,7 +53,12 @@ chai.util.addMethod(chai.assert, 'equals', function (actual, expected, errorMsg) }) chai.util.addMethod(chai.assert, 'equalsDelta', function (actual, expected, delta, errorMsg) { - this.isAtMost(+toBN(actual.toString()).sub(toBN(expected.toString())).abs().toString(), delta, errorMsg) + const diff = toBN(actual).sub(toBN(expected)).abs() + chai.assert( + diff.lte(toBN(delta)), + () => `${errorMsg ? `${errorMsg}: ` : ''}Expected ${actual} to be close to ${expected} with max diff ${delta}, actual diff ${diff}`, + () => `${errorMsg ? `${errorMsg}: ` : ''}Expected ${actual} not to be close to ${expected} with min diff ${delta}, actual diff ${diff}`, + ) }) chai.util.addMethod(chai.assert, 'notEquals', function (actual, expected, errorMsg) { From 85c6a6bda0b018f29f3bf721abf82e7ea10d8ffb Mon Sep 17 00:00:00 2001 From: Alexandr Tarelkin Date: Tue, 21 Feb 2023 03:59:23 +0300 Subject: [PATCH 192/199] test: update rewards related scenario tests --- test/scenario/lido_happy_path.js | 19 +- .../lido_rewards_distribution_math.js | 446 ++++++++---------- 2 files changed, 217 insertions(+), 248 deletions(-) diff --git a/test/scenario/lido_happy_path.js b/test/scenario/lido_happy_path.js index 8b844aecd..70a3ba5ff 100644 --- a/test/scenario/lido_happy_path.js +++ b/test/scenario/lido_happy_path.js @@ -413,14 +413,8 @@ contract('Lido: happy path', (addresses) => { // Fee, in the form of minted tokens, was distributed between treasury, insurance fund // and node operators // treasuryTokenBalance ~= mintedAmount * treasuryFeePoints / 10000 - // insuranceTokenBalance ~= mintedAmount * insuranceFeePoints / 10000 assert.equalsDelta(await token.balanceOf(treasuryAddr), '16000000000000000', 1, 'treasury tokens') - assert.equalsDelta( - await token.balanceOf(nodeOperatorsRegistry.address), - '16000000000000000', - 1, - 'insurance tokens' - ) + assert.equalsDelta(await token.balanceOf(nodeOperatorsRegistry.address), 0, 1, 'staking module tokens') // The node operators' fee is distributed between all active node operators, // proportional to their effective stake (the amount of Ether staked by the operator's @@ -429,13 +423,18 @@ contract('Lido: happy path', (addresses) => { // In our case, both node operators received the same fee since they have the same // effective stake (one signing key used from each operator, staking 32 ETH) - assertBn(await token.balanceOf(nodeOperator1.address), 0, 'operator_1 tokens') - assertBn(await token.balanceOf(nodeOperator2.address), 0, 'operator_2 tokens') + assert.equalsDelta(await token.balanceOf(nodeOperator1.address), '8000000000000000', 1, 'operator_1 tokens') + assert.equalsDelta(await token.balanceOf(nodeOperator2.address), '8000000000000000', 1, 'operator_2 tokens') // Real minted amount should be a bit less than calculated caused by round errors on mint and transfer operations assert( mintedAmount - .sub(new BN(0).add(await token.balanceOf(treasuryAddr)).add(await token.balanceOf(nodeOperatorsRegistry.address))) + .sub( + new BN(0) + .add(await token.balanceOf(treasuryAddr)) + .add(await token.balanceOf(nodeOperator1.address)) + .add(await token.balanceOf(nodeOperator2.address)) + ) .lt(mintedAmount.divn(100)) ) }) diff --git a/test/scenario/lido_rewards_distribution_math.js b/test/scenario/lido_rewards_distribution_math.js index c55dcd4f9..0a1d43672 100644 --- a/test/scenario/lido_rewards_distribution_math.js +++ b/test/scenario/lido_rewards_distribution_math.js @@ -16,15 +16,6 @@ const Lido = artifacts.require('Lido') const initialHolderBalanceETH = 1 -const tenKBN = new BN(10000) -// Fee and its distribution are in basis points, 10000 corresponding to 100% - -// Total max fee is 10% -const totalFeePoints = 0.1 * 10000 - -// 50% goes to node operators -const nodeOperatorsFeePoints = 0.5 * 10000 - const StakingModuleStatus = { Active: 0, // deposits and rewards allowed DepositsPaused: 1, // deposits NOT allowed, rewards allowed @@ -32,7 +23,7 @@ const StakingModuleStatus = { } contract('Lido: rewards distribution math', (addresses) => { - const [, , , , , , , , , , , , , operator_1, operator_2, user1, user2, nobody] = addresses + const [, , , , , , , , , , , , , operator_1, operator_2, operator_3, user1, user2, nobody] = addresses let pool, nodeOperatorsRegistry, token let stakingRouter @@ -69,12 +60,21 @@ contract('Lido: rewards distribution math', (addresses) => { ] } + const nodeOperator3 = { + name: 'operator', + address: operator_3, + validators: [...Array(10).keys()].map((i) => ({ + key: pad('0xaa01' + i.toString(16), 48), + sig: pad('0x' + i.toString(16), 96) + })) + } + async function reportBeacon(validatorsCount, balance) { - const { submitDataTx } = await pushOracleReport(consensus, oracle, validatorsCount, balance) + const receipts = await pushOracleReport(consensus, oracle, validatorsCount, balance) await ethers.provider.send('evm_increaseTime', [SECONDS_PER_FRAME + 1000]) await ethers.provider.send('evm_mine') - return submitDataTx + return receipts } before(async () => { @@ -240,12 +240,10 @@ contract('Lido: rewards distribution math', (addresses) => { const nodeOperator1TokenBefore = await token.balanceOf(operator_1) // for some reason there's nothing in this receipt's log, so we're not going to use it - const treasuryBalanceBefore = await pool.balanceOf(treasuryAddr) - const nodeOperatorsRegistryBalanceBefore = await pool.balanceOf(nodeOperatorsRegistry.address) const treasurySharesBefore = await pool.sharesOf(treasuryAddr) - const nodeOperatorsRegistrySharesBefore = await pool.sharesOf(nodeOperatorsRegistry.address) + const nodeOperator1SharesBefore = await pool.sharesOf(nodeOperator1.address) - const receipt = await reportBeacon(1, reportingValue) + const { submitDataTx, submitExtraDataTx } = await reportBeacon(1, reportingValue) const sharesMintedAsFees = calcSharesMintedAsFees( profitAmount, @@ -261,9 +259,10 @@ contract('Lido: rewards distribution math', (addresses) => { const nodeOperatorsFeeToMint = await pool.getPooledEthByShares(nodeOperatorsSharesToMint) const treasuryFeeMint = await pool.getPooledEthByShares(treasurySharesToMint) + assert.equalsDelta(await pool.sharesOf(nodeOperatorsRegistry.address), 0, 1) assert.equals( - await pool.sharesOf(nodeOperatorsRegistry.address), - nodeOperatorsRegistrySharesBefore.add(nodeOperatorsSharesToMint), + await pool.sharesOf(nodeOperator1.address), + nodeOperator1SharesBefore.add(nodeOperatorsSharesToMint), 'nodeOperator1 shares are correct' ) assert.equals( @@ -273,19 +272,19 @@ contract('Lido: rewards distribution math', (addresses) => { ) assert.equalsDelta( await pool.balanceOf(treasuryAddr), - treasuryBalanceBefore.add(treasuryFeeMint), + await pool.getPooledEthByShares(treasurySharesBefore.add(treasurySharesToMint)), 1, 'reported the expected total fee' ) assert.equalsDelta( - await pool.balanceOf(nodeOperatorsRegistry.address), - nodeOperatorsRegistryBalanceBefore.add(nodeOperatorsFeeToMint), + await pool.balanceOf(nodeOperator1.address), + await pool.getPooledEthByShares(nodeOperator1SharesBefore.add(nodeOperatorsSharesToMint)), 1, 'reported the expected total fee' ) assert.emits( - receipt, + submitDataTx, 'Transfer', { to: nodeOperatorsRegistry.address, @@ -294,7 +293,7 @@ contract('Lido: rewards distribution math', (addresses) => { { abi: Lido.abi } ) assert.emits( - receipt, + submitDataTx, 'Transfer', { to: treasuryAddr, @@ -303,7 +302,7 @@ contract('Lido: rewards distribution math', (addresses) => { { abi: Lido.abi } ) assert.emits( - receipt, + submitDataTx, 'TransferShares', { to: nodeOperatorsRegistry.address, @@ -312,7 +311,7 @@ contract('Lido: rewards distribution math', (addresses) => { { abi: Lido.abi } ) assert.emits( - receipt, + submitDataTx, 'TransferShares', { to: treasuryAddr, @@ -320,6 +319,26 @@ contract('Lido: rewards distribution math', (addresses) => { }, { abi: Lido.abi } ) + assert.emits( + submitExtraDataTx, + 'Transfer', + { + from: nodeOperatorsRegistry.address, + to: nodeOperator1.address, + value: nodeOperatorsFeeToMint + }, + { abi: Lido.abi } + ) + assert.emits( + submitExtraDataTx, + 'TransferShares', + { + from: nodeOperatorsRegistry.address, + to: nodeOperator1.address, + sharesValue: nodeOperatorsSharesToMint.toString() + }, + { abi: Lido.abi } + ) assert.equalsDelta( await token.balanceOf(user1), @@ -331,20 +350,6 @@ contract('Lido: rewards distribution math', (addresses) => { assertBn(await token.totalSupply(), ETH(36), 'token total supply') assert.equals(await pool.getTotalShares(), prevTotalShares.add(sharesMintedAsFees)) - - // TODO: check math after rewards distribution fixes - await stakingRouter.reportStakingModuleExitedValidatorsCountByNodeOperator(1, [], [], { from: voting }) - - assert.equalsDelta( - await token.balanceOf(nodeOperator1.address), - nodeOperatorsFeeToMint, - 1, - 'nodeOperator1 balance = fee' - ) - - const nodeOperator1TokenDelta = (await token.balanceOf(operator_1)) - nodeOperator1TokenBefore - - assert.equalsDelta(nodeOperator1TokenDelta, nodeOperatorsFeeToMint, 1, 'nodeOperator1 balance = fee') }) it(`adds another node operator`, async () => { @@ -487,18 +492,16 @@ contract('Lido: rewards distribution math', (addresses) => { it(`balances change correctly on second profit`, async () => { const profitAmountEth = 2 const profitAmount = ETH(profitAmountEth) - const bufferedAmount = ETH(2) const reportingValue = ETH(65 + profitAmountEth) const prevTotalShares = await pool.getTotalShares() const treasurySharesBefore = await pool.sharesOf(treasuryAddr) - const nodeOperatorsRegistrySharesBefore = await pool.sharesOf(nodeOperatorsRegistry.address) const nodeOperator1SharesBefore = await pool.sharesOf(nodeOperator1.address) const nodeOperator2SharesBefore = await pool.sharesOf(nodeOperator2.address) - const receipt = await reportBeacon(2, reportingValue) + const { submitDataTx, submitExtraDataTx } = await reportBeacon(2, reportingValue) const sharesMintedAsFees = calcSharesMintedAsFees( profitAmount, @@ -507,16 +510,25 @@ contract('Lido: rewards distribution math', (addresses) => { prevTotalShares, await pool.getTotalPooledEther() ) - const totalFeeToDistribute = await pool.getPooledEthByShares(sharesMintedAsFees) const nodeOperatorsSharesToMint = sharesMintedAsFees.div(toBN(2)) + const nodeOperatorSharesToMint = nodeOperatorsSharesToMint.div(toBN(2)) const treasurySharesToMint = sharesMintedAsFees.sub(nodeOperatorsSharesToMint) const nodeOperatorsFeeToMint = await pool.getPooledEthByShares(nodeOperatorsSharesToMint) + const nodeOperatorFeeToMint = await pool.getPooledEthByShares(nodeOperatorSharesToMint) const treasuryFeeMint = await pool.getPooledEthByShares(treasurySharesToMint) + assert.equalsDelta(await pool.sharesOf(nodeOperatorsRegistry.address), 0, 1) + + assert.equals( + await pool.sharesOf(nodeOperator1.address), + nodeOperator1SharesBefore.add(nodeOperatorSharesToMint), + 'nodeOperator1 shares are correct' + ) + assert.equals( - await pool.sharesOf(nodeOperatorsRegistry.address), - nodeOperatorsRegistrySharesBefore.add(nodeOperatorsSharesToMint), - 'nodeOperatorRegistry shares are correct' + await pool.sharesOf(nodeOperator2.address), + nodeOperator2SharesBefore.add(nodeOperatorSharesToMint), + 'nodeOperator2 shares are correct' ) assert.equals( await pool.sharesOf(treasuryAddr), @@ -527,17 +539,23 @@ contract('Lido: rewards distribution math', (addresses) => { await pool.balanceOf(treasuryAddr), await pool.getPooledEthByShares(treasurySharesBefore.add(treasurySharesToMint)), 1, - 'treasury fee' + 'reported the expected treasury fee' + ) + assert.equalsDelta( + await pool.balanceOf(nodeOperator1.address), + await pool.getPooledEthByShares(nodeOperator1SharesBefore.add(nodeOperatorSharesToMint)), + 1, + 'reported the expected nodeOperator1 fee' ) assert.equalsDelta( - await pool.balanceOf(nodeOperatorsRegistry.address), - await pool.getPooledEthByShares(nodeOperatorsRegistrySharesBefore.add(nodeOperatorsSharesToMint)), + await pool.balanceOf(nodeOperator2.address), + await pool.getPooledEthByShares(nodeOperator2SharesBefore.add(nodeOperatorSharesToMint)), 1, - 'nodeOperatorRegistry fee' + 'reported the expected nodeOperator2 fee' ) assert.emits( - receipt, + submitDataTx, 'Transfer', { to: nodeOperatorsRegistry.address, @@ -546,7 +564,7 @@ contract('Lido: rewards distribution math', (addresses) => { { abi: Lido.abi } ) assert.emits( - receipt, + submitDataTx, 'Transfer', { to: treasuryAddr, @@ -555,7 +573,7 @@ contract('Lido: rewards distribution math', (addresses) => { { abi: Lido.abi } ) assert.emits( - receipt, + submitDataTx, 'TransferShares', { to: nodeOperatorsRegistry.address, @@ -564,7 +582,7 @@ contract('Lido: rewards distribution math', (addresses) => { { abi: Lido.abi } ) assert.emits( - receipt, + submitDataTx, 'TransferShares', { to: treasuryAddr, @@ -572,6 +590,46 @@ contract('Lido: rewards distribution math', (addresses) => { }, { abi: Lido.abi } ) + assert.emits( + submitExtraDataTx, + 'Transfer', + { + from: nodeOperatorsRegistry.address, + to: nodeOperator1.address, + value: nodeOperatorFeeToMint + }, + { abi: Lido.abi } + ) + assert.emits( + submitExtraDataTx, + 'TransferShares', + { + from: nodeOperatorsRegistry.address, + to: nodeOperator1.address, + sharesValue: nodeOperatorSharesToMint + }, + { abi: Lido.abi } + ) + assert.emits( + submitExtraDataTx, + 'Transfer', + { + from: nodeOperatorsRegistry.address, + to: nodeOperator2.address, + value: nodeOperatorFeeToMint + }, + { abi: Lido.abi } + ) + assert.emits( + submitExtraDataTx, + 'TransferShares', + { + from: nodeOperatorsRegistry.address, + to: nodeOperator2.address, + sharesValue: nodeOperatorSharesToMint + }, + { abi: Lido.abi } + ) assert.equalsDelta( await token.balanceOf(user1), @@ -583,72 +641,6 @@ contract('Lido: rewards distribution math', (addresses) => { assertBn(await token.totalSupply(), ETH(70), 'token total supply') assert.equals(await pool.getTotalShares(), prevTotalShares.add(sharesMintedAsFees)) - - // TODO: check math after rewards distribution fixes - await stakingRouter.reportStakingModuleExitedValidatorsCountByNodeOperator(1, [], [], { from: voting }) - - const nodeOperator1SharesDelta = (await token.sharesOf(nodeOperator1.address)).sub(nodeOperator1SharesBefore) - const nodeOperator2SharesDelta = (await token.sharesOf(nodeOperator2.address)).sub(nodeOperator2SharesBefore) - - assertBn( - nodeOperator2SharesDelta, - await pool.sharesOf(nodeOperator2.address), - 'node operator 2 got only fee on balance' - ) - - assertBn( - nodeOperator1SharesDelta.add(nodeOperator2SharesDelta), - nodeOperatorsSharesToMint, - 'nodeOperator1 shares are correct' - ) - assertBn(treasurySharesDelta, treasurySharesToMint, 'treasury shares are correct') - - assertBn( - nodeOperator1SharesDelta, - nodeOperator2SharesDelta, - 'operators with equal amount of validators received equal shares' - ) - - const reportingValueBN = new BN(reportingValue) - const totalSupply = reportingValueBN.add(new BN(bufferedAmount)) - - const treasuryBalanceAfter = valuesAfter[0] - const treasuryShareBefore = valuesBefore[1] - const user1BalanceAfter = valuesAfter[2] - const user1SharesBefore = valuesBefore[3] - const user2BalanceAfter = valuesAfter[4] - const user2SharesBefore = valuesBefore[5] - const singleNodeOperatorFeeShare = nodeOperatorsSharesToMint.div(new BN(2)) - - const awaitingTotalShares = prevTotalShares.add(sharesToMint) - - assertBn( - await token.balanceOf(nodeOperator1.address), - nodeOperator1SharesBefore.add(singleNodeOperatorFeeShare).mul(totalSupply).div(awaitingTotalShares), - `first node operator token balance is correct` - ) - assertBn( - await token.balanceOf(nodeOperator2.address), - nodeOperator2SharesBefore.add(singleNodeOperatorFeeShare).mul(totalSupply).div(awaitingTotalShares), - `first node operator token balance is correct` - ) - assertBn( - treasuryBalanceAfter, - treasuryShareBefore.add(treasurySharesToMint).mul(totalSupply).div(awaitingTotalShares), - 'treasury token balance changed correctly' - ) - assertBn(user1SharesDelta, new BN(0), `user1 didn't get any shares from profit`) - assertBn( - user1BalanceAfter, - user1SharesBefore.mul(totalSupply).div(awaitingTotalShares), - `user1 token balance increased` - ) - assertBn(user2SharesDelta, new BN(0), `user2 didn't get any shares from profit`) - assertBn( - user2BalanceAfter, - user2SharesBefore.mul(totalSupply).div(awaitingTotalShares), - `user2 token balance increased` - ) }) it(`add another staking module`, async () => { @@ -657,8 +649,8 @@ contract('Lido: rewards distribution math', (addresses) => { 'Curated limited', anotherCuratedModule.address, 5_000, // 50 % _targetShare - 100, // 1 % _moduleFee - 100, // 1 % _treasuryFee + 2000, // 20 % _moduleFee + 2000, // 20 % _treasuryFee { from: voting } ) @@ -666,23 +658,15 @@ contract('Lido: rewards distribution math', (addresses) => { assert(modulesList.length, 2, 'module added') - const operator = { - name: 'operator', - address: operator_2, - validators: [...Array(10).keys()].map((i) => ({ - key: pad('0xaa01' + i.toString(16), 48), - sig: pad('0x' + i.toString(16), 96) - })) - } const validatorsCount = 10 - await anotherCuratedModule.addNodeOperator(operator.name, operator.address, { from: voting }) + await anotherCuratedModule.addNodeOperator(nodeOperator3.name, nodeOperator3.address, { from: voting }) await anotherCuratedModule.addSigningKeysOperatorBH( 0, validatorsCount, - hexConcat(...operator.validators.map((v) => v.key)), - hexConcat(...operator.validators.map((v) => v.sig)), + hexConcat(...nodeOperator3.validators.map((v) => v.key)), + hexConcat(...nodeOperator3.validators.map((v) => v.sig)), { - from: operator.address + from: nodeOperator3.address } ) await anotherCuratedModule.setNodeOperatorStakingLimit(0, validatorsCount, { from: voting }) @@ -742,133 +726,135 @@ contract('Lido: rewards distribution math', (addresses) => { it(`rewards distribution`, async () => { const bufferedBefore = await token.getBufferedEther() + const totalSharesBefore = await token.getTotalShares() const totalPooledEtherBefore = await token.getTotalPooledEther() - // FIXME: oracle doesn't support reporting anything smaller than 1 gwei, here we're trying to report 2 wei - const newBeaconBalance = totalPooledEtherBefore.sub(bufferedBefore).add(new BN(2)) + const rewardsAmount = ETH(1) + const newBeaconBalance = totalPooledEtherBefore.sub(bufferedBefore).add(toBN(rewardsAmount)) - const firstModuleSharesBefore = await token.sharesOf(nodeOperatorsRegistry.address) - const secondModuleSharesBefore = await token.sharesOf(anotherCuratedModule.address) const treasurySharesBefore = await await token.sharesOf(treasuryAddr) + const nodeOperator1SharesBefore = await await token.sharesOf(nodeOperator1.address) + const nodeOperator2SharesBefore = await await token.sharesOf(nodeOperator2.address) + const nodeOperator3SharesBefore = await await token.sharesOf(nodeOperator3.address) await reportBeacon(3, newBeaconBalance) - assert.equalsDelta(await token.totalSupply(), newBeaconBalance.add(bufferedBefore), 1, 'token total supply') + assert.equals(await token.totalSupply(), totalPooledEtherBefore.add(toBN(rewardsAmount)), 'token total supply') - const rewardsToDistribute = await token.getSharesByPooledEth( - newBeaconBalance.add(bufferedBefore).sub(totalPooledEtherBefore) + const sharesMintedAsFees = calcSharesMintedAsFees( + rewardsAmount, + 2000, + 10000, + totalSharesBefore, + await pool.getTotalPooledEther() ) + const treasureRewardsShares = sharesMintedAsFees.div(toBN(2)) + const nodeOperator1RewardsShares = sharesMintedAsFees.div(toBN(12)) + const nodeOperator2RewardsShares = sharesMintedAsFees.div(toBN(12)) + const nodeOperator3RewardsShares = sharesMintedAsFees.div(toBN(3)) - const { treasuryFee } = await stakingRouter.getStakingFeeAggregateDistribution() - const { stakingModuleFees, precisionPoints } = await stakingRouter.getStakingRewardsDistribution() - const [firstModuleFee, secondModuleFee] = stakingModuleFees - const expectedRewardsDistribution = { - firstModule: rewardsToDistribute.mul(firstModuleFee).div(precisionPoints), - secondModule: rewardsToDistribute.mul(secondModuleFee).div(precisionPoints), - treasury: rewardsToDistribute.mul(treasuryFee).div(precisionPoints) - } - - const firstModuleSharesAfter = await token.sharesOf(nodeOperatorsRegistry.address) - const secondModuleSharesAfter = await token.sharesOf(anotherCuratedModule.address) - const treasurySharesAfter = await await token.sharesOf(treasuryAddr) + assert.equalsDelta(await token.sharesOf(nodeOperatorsRegistry.address), 0, 1, 'first module balance') + assert.equalsDelta(await token.sharesOf(anotherCuratedModule.address), 0, 1, 'second module balance') - assertBn( - firstModuleSharesAfter, - firstModuleSharesBefore.add(expectedRewardsDistribution.firstModule), - 'first module balance' + assert.equalsDelta( + await pool.sharesOf(treasuryAddr), + treasurySharesBefore.add(treasureRewardsShares), + 1, + 'treasury shares' ) - assertBn( - secondModuleSharesAfter, - secondModuleSharesBefore.add(expectedRewardsDistribution.secondModule), - 'second module balance' + assert.equals( + await pool.sharesOf(nodeOperator1.address), + nodeOperator1SharesBefore.add(nodeOperator1RewardsShares), + 'nodeOperator1 shares' + ) + assert.equals( + await pool.sharesOf(nodeOperator2.address), + nodeOperator2SharesBefore.add(nodeOperator2RewardsShares), + 'nodeOperator2 shares' + ) + assert.equals( + await pool.sharesOf(nodeOperator3.address), + nodeOperator3SharesBefore.add(nodeOperator3RewardsShares), + 'nodeOperator3 shares' ) - assertBn(treasurySharesAfter, treasurySharesBefore.add(expectedRewardsDistribution.treasury), 'treasury balance') }) it(`module rewards should received by treasury if module stopped`, async () => { const [firstModule] = await stakingRouter.getStakingModules() + const totalSharesBefore = await token.getTotalShares() const totalPooledEtherBefore = await token.getTotalPooledEther() const bufferedBefore = await token.getBufferedEther() - // FIXME: oracle doesn't support reporting anything smaller than 1 gwei, here we're trying to report 1 wei - const newBeaconBalance = totalPooledEtherBefore.sub(bufferedBefore).add(new BN(1)) + const rewardsAmount = ETH(1) + const newBeaconBalance = totalPooledEtherBefore.sub(bufferedBefore).add(toBN(rewardsAmount)) await stakingRouter.setStakingModuleStatus(firstModule.id, StakingModuleStatus.Stopped, { from: voting }) - const firstModuleSharesBefore = await token.sharesOf(nodeOperatorsRegistry.address) - const secondModuleSharesBefore = await token.sharesOf(anotherCuratedModule.address) const treasurySharesBefore = await await token.sharesOf(treasuryAddr) + const nodeOperator1SharesBefore = await await token.sharesOf(nodeOperator1.address) + const nodeOperator2SharesBefore = await await token.sharesOf(nodeOperator2.address) + const nodeOperator3SharesBefore = await await token.sharesOf(nodeOperator3.address) await reportBeacon(3, newBeaconBalance) - assert.equalsDelta(await token.totalSupply(), newBeaconBalance.add(bufferedBefore), 1, 'token total supply') + assert.equals(await token.totalSupply(), totalPooledEtherBefore.add(toBN(rewardsAmount)), 'token total supply') - const rewardsToDistribute = await token.getSharesByPooledEth( - newBeaconBalance.add(bufferedBefore).sub(totalPooledEtherBefore) + const sharesMintedAsFees = calcSharesMintedAsFees( + rewardsAmount, + 2000, + 10000, + totalSharesBefore, + await pool.getTotalPooledEther() ) - const { treasuryFee } = await stakingRouter.getStakingFeeAggregateDistribution() - const { stakingModuleFees, precisionPoints } = await stakingRouter.getStakingRewardsDistribution() - const [firstModuleFee, secondModuleFee] = stakingModuleFees - const expectedRewardsDistribution = { - firstModule: new BN(0), - secondModule: rewardsToDistribute.mul(secondModuleFee).div(precisionPoints), - treasury: rewardsToDistribute.mul(treasuryFee.add(firstModuleFee)).div(precisionPoints) - } + const treasureRewardsShares = sharesMintedAsFees.mul(toBN(2)).div(toBN(3)) + const nodeOperator3RewardsShares = sharesMintedAsFees.div(toBN(3)) - const firstModuleSharesAfter = await token.sharesOf(nodeOperatorsRegistry.address) - const secondModuleSharesAfter = await token.sharesOf(anotherCuratedModule.address) - const treasurySharesAfter = await token.sharesOf(treasuryAddr) + assert.equalsDelta(await token.sharesOf(nodeOperatorsRegistry.address), 0, 1, 'first module balance') + assert.equalsDelta(await token.sharesOf(anotherCuratedModule.address), 0, 1, 'second module balance') - assertBn( - firstModuleSharesAfter, - firstModuleSharesBefore.add(expectedRewardsDistribution.firstModule), - 'first module balance' - ) - assertBn( - secondModuleSharesAfter, - secondModuleSharesBefore.add(expectedRewardsDistribution.secondModule), - 'second module balance' + assert.equals(await pool.sharesOf(treasuryAddr), treasurySharesBefore.add(treasureRewardsShares), 'treasury shares') + assert.equals(await pool.sharesOf(nodeOperator1.address), nodeOperator1SharesBefore, 'nodeOperator1 shares') + assert.equals(await pool.sharesOf(nodeOperator2.address), nodeOperator2SharesBefore, 'nodeOperator2 shares') + assert.equals( + await pool.sharesOf(nodeOperator3.address), + nodeOperator3SharesBefore.add(nodeOperator3RewardsShares), + 'nodeOperator3 shares' ) - assertBn(treasurySharesAfter, treasurySharesBefore.add(expectedRewardsDistribution.treasury), 'treasury balance') }) - // test multiple staking modules reward distribution - async function getAwaitedFeesSharesTokensDeltas(profitAmount, prevTotalShares, validatorsCount) { - const totalPooledEther = await pool.getTotalPooledEther() - const totalShares = await pool.getTotalShares() - - const totalFeeToDistribute = new BN(profitAmount).mul(new BN(totalFeePoints)).div(tenKBN) + it(`module rewards should received by treasury if all modules stopped`, async () => { + const [, secondModule] = await stakingRouter.getStakingModules() + const totalSharesBefore = await token.getTotalShares() + const totalPooledEtherBefore = await token.getTotalPooledEther() + const bufferedBefore = await token.getBufferedEther() + const rewardsAmount = ETH(1) + const newBeaconBalance = totalPooledEtherBefore.sub(bufferedBefore).add(toBN(rewardsAmount)) - const sharesToMintSol = new BN(profitAmount) - .mul(new BN(totalFeePoints)) - .mul(prevTotalShares) - .div(totalPooledEther.mul(tenKBN).sub(new BN(profitAmount).mul(new BN(totalFeePoints)))) + await stakingRouter.setStakingModuleStatus(secondModule.id, StakingModuleStatus.Stopped, { from: voting }) - const sharesToMint = totalFeeToDistribute.mul(prevTotalShares).div(totalPooledEther.sub(totalFeeToDistribute)) + const treasurySharesBefore = await await token.sharesOf(treasuryAddr) + const nodeOperator1SharesBefore = await await token.sharesOf(nodeOperator1.address) + const nodeOperator2SharesBefore = await await token.sharesOf(nodeOperator2.address) + const nodeOperator3SharesBefore = await await token.sharesOf(nodeOperator3.address) - assert.equals(sharesToMintSol, sharesToMint) + await reportBeacon(3, newBeaconBalance) - const nodeOperatorsSharesToMint = sharesToMint.mul(new BN(nodeOperatorsFeePoints)).div(tenKBN) - const treasurySharesToMint = sharesToMint.sub(nodeOperatorsSharesToMint) + assert.equals(await token.totalSupply(), totalPooledEtherBefore.add(toBN(rewardsAmount)), 'token total supply') - const validatorsCountBN = new BN(validatorsCount) + const sharesMintedAsFees = calcSharesMintedAsFees( + rewardsAmount, + 2000, + 10000, + totalSharesBefore, + await pool.getTotalPooledEther() + ) - const nodeOperatorsFeeToMint = nodeOperatorsSharesToMint - .mul(totalPooledEther) - .div(totalShares) - .div(validatorsCountBN) - .mul(validatorsCountBN) - const treasuryFeeToMint = treasurySharesToMint.mul(totalPooledEther).div(totalShares) + assert.equalsDelta(await token.sharesOf(nodeOperatorsRegistry.address), 0, 1, 'first module balance') + assert.equalsDelta(await token.sharesOf(anotherCuratedModule.address), 0, 1, 'second module balance') - return { - totalPooledEther, - totalShares, - totalFeeToDistribute, - sharesToMint, - nodeOperatorsSharesToMint, - treasurySharesToMint, - nodeOperatorsFeeToMint, - treasuryFeeToMint - } - } + assert.equals(await pool.sharesOf(treasuryAddr), treasurySharesBefore.add(sharesMintedAsFees), 'treasury shares') + assert.equals(await pool.sharesOf(nodeOperator1.address), nodeOperator1SharesBefore, 'nodeOperator1 shares') + assert.equals(await pool.sharesOf(nodeOperator2.address), nodeOperator2SharesBefore, 'nodeOperator2 shares') + assert.equals(await pool.sharesOf(nodeOperator3.address), nodeOperator3SharesBefore, 'nodeOperator3 shares') + }) async function getSharesTokenDeltas(tx, ...addresses) { const valuesBefore = await Promise.all(addresses.flatMap((addr) => [token.balanceOf(addr), token.sharesOf(addr)])) @@ -877,20 +863,4 @@ contract('Lido: rewards distribution math', (addresses) => { return [{ receipt, valuesBefore, valuesAfter }, valuesAfter.map((val, i) => val.sub(valuesBefore[i]))] } - async function readLastPoolEventLog() { - const events = await pool.getPastEvents('Transfer') - let reportedMintAmount = new BN(0) - const tos = [] - const values = [] - events.forEach(({ args }) => { - reportedMintAmount = reportedMintAmount.add(args.value) - tos.push(args.to) - values.push(args.value) - }) - return { - reportedMintAmount, - tos, - values - } - } }) From ee0af1204ba0efefa0f81c626a09a96987373bf7 Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Tue, 21 Feb 2023 14:46:09 +0200 Subject: [PATCH 193/199] staking router: fix: check the reported exited/stuck validators data --- contracts/0.8.9/StakingRouter.sol | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/contracts/0.8.9/StakingRouter.sol b/contracts/0.8.9/StakingRouter.sol index 038d33429..1ec148083 100644 --- a/contracts/0.8.9/StakingRouter.sol +++ b/contracts/0.8.9/StakingRouter.sol @@ -36,7 +36,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version error StakingModuleNotPaused(); error EmptyWithdrawalsCredentials(); error DirectETHTransfer(); - error InvalidReportData(); + error InvalidReportData(uint256 code); error ExitedValidatorsCountCannotDecrease(); error StakingModulesLimitExceeded(); error StakingModuleIdTooLarge(); @@ -311,6 +311,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version onlyRole(REPORT_EXITED_VALIDATORS_ROLE) { address moduleAddr = _getStakingModuleById(_stakingModuleId).stakingModuleAddress; + _checkValidatorsByNodeOperatorReportData(_nodeOperatorIds, _exitedValidatorsCounts); IStakingModule(moduleAddr).updateExitedValidatorsCount( _nodeOperatorIds, _exitedValidatorsCounts @@ -411,6 +412,7 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version onlyRole(REPORT_EXITED_VALIDATORS_ROLE) { address moduleAddr = _getStakingModuleById(_stakingModuleId).stakingModuleAddress; + _checkValidatorsByNodeOperatorReportData(_nodeOperatorIds, _stuckValidatorsCounts); IStakingModule(moduleAddr).updateStuckValidatorsCount(_nodeOperatorIds, _stuckValidatorsCounts); } @@ -1021,6 +1023,22 @@ contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Version return WITHDRAWAL_CREDENTIALS_POSITION.getStorageBytes32(); } + function _checkValidatorsByNodeOperatorReportData( + bytes calldata _nodeOperatorIds, + bytes calldata _validatorsCounts + ) internal { + if (_nodeOperatorIds.length % 8 != 0 || _validatorsCounts.length % 16 != 0) { + revert InvalidReportData(3); + } + uint256 nodeOperatorsCount = _nodeOperatorIds.length / 8; + if (_validatorsCounts.length / 16 != nodeOperatorsCount) { + revert InvalidReportData(2); + } + if (nodeOperatorsCount == 0) { + revert InvalidReportData(1); + } + } + /** * @dev load modules into a memory cache * From 88b7cfa42f76b5c5b33952e024da10060cfe20bc Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Tue, 21 Feb 2023 14:47:06 +0200 Subject: [PATCH 194/199] staking router: add basic tests for exited/stuck validators reporting --- .../0.8.9/test_helpers/StakingModuleMock.sol | 36 +- .../staking-router-keys-reporting.test.js | 714 ++++++++++++++++++ 2 files changed, 745 insertions(+), 5 deletions(-) create mode 100644 test/0.8.9/staking-router-keys-reporting.test.js diff --git a/contracts/0.8.9/test_helpers/StakingModuleMock.sol b/contracts/0.8.9/test_helpers/StakingModuleMock.sol index f26bbbc4f..00d1227ad 100644 --- a/contracts/0.8.9/test_helpers/StakingModuleMock.sol +++ b/contracts/0.8.9/test_helpers/StakingModuleMock.sol @@ -7,6 +7,7 @@ pragma solidity 0.8.9; import {IStakingModule} from "../interfaces/IStakingModule.sol"; contract StakingModuleMock is IStakingModule { + uint256 internal _exitedValidatorsCount; uint256 private _activeValidatorsCount; uint256 private _availableValidatorsCount; uint256 private _nonce; @@ -26,7 +27,7 @@ contract StakingModuleMock is IStakingModule { uint256 totalDepositedValidators, uint256 depositableValidatorsCount ) { - totalExitedValidators = 0; + totalExitedValidators = _exitedValidatorsCount; totalDepositedValidators = _activeValidatorsCount; depositableValidatorsCount = _availableValidatorsCount; } @@ -63,19 +64,40 @@ contract StakingModuleMock is IStakingModule { function onRewardsMinted(uint256 _totalShares) external {} + struct Call_updateValidatorsCount { + bytes nodeOperatorIds; + bytes validatorsCounts; + uint256 callCount; + } + + Call_updateValidatorsCount public lastCall_updateStuckValidatorsCount; + Call_updateValidatorsCount public lastCall_updateExitedValidatorsCount; + function updateStuckValidatorsCount( bytes calldata _nodeOperatorIds, bytes calldata _stuckValidatorsCounts - ) external {} + ) external { + lastCall_updateStuckValidatorsCount.nodeOperatorIds = _nodeOperatorIds; + lastCall_updateStuckValidatorsCount.validatorsCounts = _stuckValidatorsCounts; + ++lastCall_updateStuckValidatorsCount.callCount; + } function updateExitedValidatorsCount( bytes calldata _nodeOperatorIds, - bytes calldata _stuckValidatorsCounts - ) external {} + bytes calldata _exitedValidatorsCounts + ) external { + lastCall_updateExitedValidatorsCount.nodeOperatorIds = _nodeOperatorIds; + lastCall_updateExitedValidatorsCount.validatorsCounts = _exitedValidatorsCounts; + ++lastCall_updateExitedValidatorsCount.callCount; + } function updateRefundedValidatorsCount(uint256 _nodeOperatorId, uint256 _refundedValidatorsCount) external {} - function onExitedAndStuckValidatorsCountsUpdated() external {} + uint256 public callCount_onExitedAndStuckValidatorsCountsUpdated; + + function onExitedAndStuckValidatorsCountsUpdated() external { + ++callCount_onExitedAndStuckValidatorsCountsUpdated; + } function unsafeUpdateValidatorsCount( uint256 /* _nodeOperatorId */, @@ -95,6 +117,10 @@ contract StakingModuleMock is IStakingModule { ) {} + function setTotalExitedValidatorsCount(uint256 newExitedValidatorsCount) external { + _exitedValidatorsCount = newExitedValidatorsCount; + } + function setActiveValidatorsCount(uint256 _newActiveValidatorsCount) external { _activeValidatorsCount = _newActiveValidatorsCount; } diff --git a/test/0.8.9/staking-router-keys-reporting.test.js b/test/0.8.9/staking-router-keys-reporting.test.js new file mode 100644 index 000000000..5da7ef45f --- /dev/null +++ b/test/0.8.9/staking-router-keys-reporting.test.js @@ -0,0 +1,714 @@ +const hre = require('hardhat') +const { EvmSnapshot } = require('../helpers/blockchain') +const { assert } = require('../helpers/assert') +const { hex, hexConcat, toNum } = require('../helpers/utils') + +const StakingRouter = artifacts.require('StakingRouterMock.sol') +const StakingModuleMock = artifacts.require('StakingModuleMock.sol') +const DepositContractMock = artifacts.require('DepositContractMock.sol') + + +contract('StakingRouter', ([deployer, lido, admin]) => { + const evmSnapshot = new EvmSnapshot(hre.ethers.provider) + + let depositContract, router + let module1, module2 + + before(async () => { + depositContract = await DepositContractMock.new({ from: deployer }) + router = await StakingRouter.new(depositContract.address, { from: deployer }) + + ;[module1, module2] = await Promise.all([ + StakingModuleMock.new({ from: deployer }), + StakingModuleMock.new({ from: deployer }) + ]) + + const wc = '0x'.padEnd(66, '1234') + await router.initialize(admin, lido, wc, { from: deployer }) + + await router.grantRole(await router.MANAGE_WITHDRAWAL_CREDENTIALS_ROLE(), admin, { from: admin }) + await router.grantRole(await router.STAKING_MODULE_PAUSE_ROLE(), admin, { from: admin }) + await router.grantRole(await router.STAKING_MODULE_MANAGE_ROLE(), admin, { from: admin }) + await router.grantRole(await router.REPORT_EXITED_VALIDATORS_ROLE(), admin, { from: admin }) + }) + + const getCallInfo = async (sModule) => { + const callCountToNum = (callInfo) => { + return { ...callInfo, callCount: +callInfo.callCount } + } + return { + updateStuckValidatorsCount: callCountToNum(await sModule.lastCall_updateStuckValidatorsCount()), + updateExitedValidatorsCount: callCountToNum(await sModule.lastCall_updateExitedValidatorsCount()), + onExitedAndStuckValidatorsCountsUpdated: { + callCount: +await sModule.callCount_onExitedAndStuckValidatorsCountsUpdated() + } + } + } + + before(async () => { + for await (moduleI of [module1, module2]) { + const callInfo = await getCallInfo(moduleI) + assert.equal(callInfo.updateStuckValidatorsCount.callCount, 0) + assert.equal(callInfo.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + } + }) + + const snapshot = () => evmSnapshot.make() + const revert = () => evmSnapshot.revert() + + describe('exited/stuck keys reporting', () => { + + describe('one staking module', async () => { + before(snapshot) + after(revert) + + let module1Id + + it('adding the only module', async () => { + await router.addStakingModule( + 'module 1', + module1.address, + 10_000, // target share 100 % + 1_000, // module fee 10 % + 5_000, // treasury fee 5 % + { from: admin } + ) + module1Id = +(await router.getStakingModuleIds())[0] + }) + + it('initially, router assumes no staking modules have exited validators', async () => { + const info = await router.getStakingModule(module1Id) + assert.equal(+info.exitedValidatorsCount, 0) + + const totalExited = await router.getExitedValidatorsCountAcrossAllModules() + assert.equal(+totalExited, 0) + }) + + it('reporting total exited validators of a non-existent module reverts', async () => { + await assert.reverts( + router.updateExitedValidatorsCountByStakingModule([module1Id + 1], [1], { from: admin }), + 'StakingModuleUnregistered()' + ) + await assert.reverts( + router.updateExitedValidatorsCountByStakingModule([module1Id, module1Id + 1], [1, 1], { from: admin }), + 'StakingModuleUnregistered()' + ) + }) + + it('reporting module 1 to have total 3 exited validators', async () => { + await router.updateExitedValidatorsCountByStakingModule([module1Id], [3], { from: admin }) + }) + + it('staking module info gets updated', async () => { + const info = await router.getStakingModule(module1Id) + assert.equal(+info.exitedValidatorsCount, 3) + }) + + it('exited validators count accross all modules gets updated', async () => { + const totalExited = await router.getExitedValidatorsCountAcrossAllModules() + assert.equal(+totalExited, 3) + }) + + it('no functions were called on the module', async () => { + const callInfo = await getCallInfo(module1) + assert.equal(callInfo.updateStuckValidatorsCount.callCount, 0) + assert.equal(callInfo.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it(`calling onValidatorsCountsByNodeOperatorReportingFinished doesn't call ` + + `anything on the module`, async () => + { + await router.onValidatorsCountsByNodeOperatorReportingFinished({ from: admin }) + + const callInfo = await getCallInfo(module1) + assert.equal(callInfo.updateStuckValidatorsCount.callCount, 0) + assert.equal(callInfo.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it('reporting stuck validators by node op of a non-existent module reverts', async () => { + const nonExistentModuleId = module1Id + 1 + const nodeOpIdsData = hexConcat(hex(1, 8)) + const validatorsCountsData = hexConcat(hex(1, 16)) + await assert.reverts( + router.reportStakingModuleStuckValidatorsCountByNodeOperator( + nonExistentModuleId, nodeOpIdsData, validatorsCountsData, + { from: admin } + ), + 'StakingModuleUnregistered()' + ) + }) + + it('passing empty data while reporting stuck validators by node operator reverts', async () => { + await assert.reverts( + router.reportStakingModuleStuckValidatorsCountByNodeOperator( + module1Id, '0x', '0x', + { from: admin } + ), + 'InvalidReportData(1)' + ) + }) + + const mismatchedLengthData = [ + { + nodeOpIds: '0x', + validatorsCounts: hexConcat(hex(1, 16)), + }, + { + nodeOpIds: hexConcat(hex(1, 8)), + validatorsCounts: '0x', + }, + { + nodeOpIds: hexConcat(hex(1, 8), hex(2, 8)), + validatorsCounts: hexConcat(hex(1, 16)), + }, + { + nodeOpIds: hexConcat(hex(1, 8)), + validatorsCounts: hexConcat(hex(1, 16), hex(1, 16)), + }, + ] + + it('passing data with mismatched length while reporting stuck validators by node operator ' + + 'reverts', async () => + { + await Promise.all(mismatchedLengthData.map(data => assert.reverts( + router.reportStakingModuleStuckValidatorsCountByNodeOperator( + module1Id, data.nodeOpIds, data.validatorsCounts, + { from: admin } + ), + 'InvalidReportData(2)' + ))) + }) + + const invalidLengthData = [ + { + nodeOpIds: '0x00', + validatorsCounts: '0x', + }, + { + nodeOpIds: '0x', + validatorsCounts: '0x00', + }, + { + nodeOpIds: '0x00', + validatorsCounts: '0x00', + }, + { + nodeOpIds: hexConcat(hex(1, 8), '0x00'), + validatorsCounts: hexConcat(hex(1, 16)), + }, + { + nodeOpIds: hexConcat(hex(1, 8), '0x00'), + validatorsCounts: hexConcat(hex(1, 16), '0x00'), + }, + { + nodeOpIds: hexConcat(hex(1, 8)), + validatorsCounts: hexConcat(hex(1, 16), '0x00'), + }, + { + nodeOpIds: hexConcat(hex(1, 8), hex(2, 8), '0x00'), + validatorsCounts: hexConcat(hex(1, 16)), + }, + { + nodeOpIds: hexConcat(hex(1, 8), hex(2, 8)), + validatorsCounts: hexConcat(hex(1, 16), '0x00'), + }, + { + nodeOpIds: hexConcat(hex(1, 8), '0x00'), + validatorsCounts: hexConcat(hex(1, 16), hex(1, 16)), + }, + { + nodeOpIds: hexConcat(hex(1, 8)), + validatorsCounts: hexConcat(hex(1, 16), hex(1, 16), '0x00'), + }, + ] + + it('passing data with invalid length while reporting stuck validators by node operator ' + + 'reverts', async () => + { + await Promise.all(invalidLengthData.map(data => assert.reverts( + router.reportStakingModuleStuckValidatorsCountByNodeOperator( + module1Id, data.nodeOpIds, data.validatorsCounts, + { from: admin } + ), + 'InvalidReportData(3)' + ))) + }) + + it('reporting stuck validators by node operator passes the info to the module', async () => { + const nodeOpIds = [3, 5] + const validatorsCounts = [1, 1] + + const nodeOpIdsData = hexConcat(...nodeOpIds.map(i => hex(i, 8))) + const validatorsCountsData = hexConcat(...validatorsCounts.map(c => hex(c, 16))) + + await router.reportStakingModuleStuckValidatorsCountByNodeOperator( + module1Id, nodeOpIdsData, validatorsCountsData, + { from: admin } + ) + + const callInfo = await getCallInfo(module1) + assert.equal(callInfo.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo.updateStuckValidatorsCount.nodeOperatorIds, nodeOpIdsData) + assert.equal(callInfo.updateStuckValidatorsCount.validatorsCounts, validatorsCountsData) + + assert.equal(callInfo.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it(`calling onValidatorsCountsByNodeOperatorReportingFinished still doesn't call ` + + `anything on the module`, async () => + { + await router.onValidatorsCountsByNodeOperatorReportingFinished({ from: admin }) + + const callInfo = await getCallInfo(module1) + assert.equal(callInfo.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + assert.equal(callInfo.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo.updateExitedValidatorsCount.callCount, 0) + }) + + it('reporting exited validators by node op of a non-existent module reverts', async () => { + const nonExistentModuleId = module1Id + 1 + const nodeOpIdsData = hexConcat(hex(1, 8)) + const validatorsCountsData = hexConcat(hex(1, 16)) + await assert.reverts( + router.reportStakingModuleExitedValidatorsCountByNodeOperator( + nonExistentModuleId, nodeOpIdsData, validatorsCountsData, + { from: admin } + ), + 'StakingModuleUnregistered()' + ) + }) + + it('passing empty data while reporting exited validators by node operator reverts', async () => { + await assert.reverts( + router.reportStakingModuleExitedValidatorsCountByNodeOperator( + module1Id, '0x', '0x', + { from: admin } + ), + 'InvalidReportData(1)' + ) + }) + + it('passing data with mismatched length while reporting exited validators by node operator ' + + 'reverts', async () => + { + await Promise.all(mismatchedLengthData.map(data => assert.reverts( + router.reportStakingModuleExitedValidatorsCountByNodeOperator( + module1Id, data.nodeOpIds, data.validatorsCounts, + { from: admin } + ), + 'InvalidReportData(2)' + ))) + }) + + it('passing data with invalid length while reporting exited validators by node operator ' + + 'reverts', async () => + { + await Promise.all(invalidLengthData.map(data => assert.reverts( + router.reportStakingModuleExitedValidatorsCountByNodeOperator( + module1Id, data.nodeOpIds, data.validatorsCounts, + { from: admin } + ), + 'InvalidReportData(3)' + ))) + }) + + it('reporting exited validators by node operator (total 2) passes the info to the module', + async () => + { + const nodeOpIds = [1, 2] + const validatorsCounts = [1, 1] + + const nodeOpIdsData = hexConcat(...nodeOpIds.map(i => hex(i, 8))) + const validatorsCountsData = hexConcat(...validatorsCounts.map(c => hex(c, 16))) + + await router.reportStakingModuleExitedValidatorsCountByNodeOperator( + module1Id, nodeOpIdsData, validatorsCountsData, + { from: admin } + ) + + const callInfo = await getCallInfo(module1) + assert.equal(callInfo.updateStuckValidatorsCount.callCount, 1) + + assert.equal(callInfo.updateExitedValidatorsCount.callCount, 1) + assert.equal(callInfo.updateExitedValidatorsCount.nodeOperatorIds, nodeOpIdsData) + assert.equal(callInfo.updateExitedValidatorsCount.validatorsCounts, validatorsCountsData) + + assert.equal(callInfo.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it('the staking module updates its internal total exited counter to 2', async () => { + await module1.setTotalExitedValidatorsCount(2) + }) + + it(`router's view on exited validators count accross all modules stays the same`, async () => { + const totalExited = await router.getExitedValidatorsCountAcrossAllModules() + assert.equal(+totalExited, 3) + }) + + it(`calling onValidatorsCountsByNodeOperatorReportingFinished still doesn't call ` + + `anything on the module`, async () => + { + await router.onValidatorsCountsByNodeOperatorReportingFinished({ from: admin }) + + const callInfo = await getCallInfo(module1) + assert.equal(callInfo.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + assert.equal(callInfo.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo.updateExitedValidatorsCount.callCount, 1) + }) + + it('reporting one more exited validator by node operator passes the info to the module', + async () => + { + const nodeOpIds = [3] + const validatorsCounts = [1] + + const nodeOpIdsData = hexConcat(...nodeOpIds.map(i => hex(i, 8))) + const validatorsCountsData = hexConcat(...validatorsCounts.map(c => hex(c, 16))) + + await router.reportStakingModuleExitedValidatorsCountByNodeOperator( + module1Id, nodeOpIdsData, validatorsCountsData, + { from: admin } + ) + + const callInfo = await getCallInfo(module1) + assert.equal(callInfo.updateStuckValidatorsCount.callCount, 1) + + assert.equal(callInfo.updateExitedValidatorsCount.callCount, 2) + assert.equal(callInfo.updateExitedValidatorsCount.nodeOperatorIds, nodeOpIdsData) + assert.equal(callInfo.updateExitedValidatorsCount.validatorsCounts, validatorsCountsData) + + assert.equal(callInfo.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it('the staking module updates its internal total exited counter to 3', async () => { + await module1.setTotalExitedValidatorsCount(3) + }) + + it(`now that exited validators totals in the router and in the module match, calling` + + `onValidatorsCountsByNodeOperatorReportingFinished calls ` + + `onExitedAndStuckValidatorsCountsUpdated on the module`, async () => + { + await router.onValidatorsCountsByNodeOperatorReportingFinished({ from: admin }) + + const callInfo = await getCallInfo(module1) + assert.equal(callInfo.onExitedAndStuckValidatorsCountsUpdated.callCount, 1) + + assert.equal(callInfo.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo.updateExitedValidatorsCount.callCount, 2) + }) + + it(`calling onValidatorsCountsByNodeOperatorReportingFinished one more time calls ` + + `onExitedAndStuckValidatorsCountsUpdated on the module again`, async () => + { + await router.onValidatorsCountsByNodeOperatorReportingFinished({ from: admin }) + + const callInfo = await getCallInfo(module1) + assert.equal(callInfo.onExitedAndStuckValidatorsCountsUpdated.callCount, 2) + + assert.equal(callInfo.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo.updateExitedValidatorsCount.callCount, 2) + }) + }) + + describe('two staking modules', async () => { + before(snapshot) + after(revert) + + let moduleIds + + it('adding the two modules', async () => { + await router.addStakingModule( + 'module 1', + module1.address, + 10_000, // 100 % _targetShare + 1_000, // 10 % _moduleFee + 5_000, // 50 % _treasuryFee + { from: admin } + ) + await router.addStakingModule( + 'module 2', + module2.address, + 200, // 2 % _targetShare + 5_000, // 50 % _moduleFee + 0, // 0 % _treasuryFee + { from: admin } + ) + moduleIds = toNum(await router.getStakingModuleIds()) + }) + + it('initially, router assumes no staking modules have exited validators', async () => { + const info1 = await router.getStakingModule(moduleIds[0]) + assert.equal(+info1.exitedValidatorsCount, 0) + + const info2 = await router.getStakingModule(moduleIds[1]) + assert.equal(+info2.exitedValidatorsCount, 0) + + const totalExited = await router.getExitedValidatorsCountAcrossAllModules() + assert.equal(+totalExited, 0) + }) + + it('reporting 3 exited keys total for module 1 and 2 exited keys total for module 2', async () => { + await router.updateExitedValidatorsCountByStakingModule(moduleIds, [3, 2], { from: admin }) + }) + + it('staking modules info gets updated', async () => { + const info1 = await router.getStakingModule(moduleIds[0]) + assert.equal(+info1.exitedValidatorsCount, 3) + + const info2 = await router.getStakingModule(moduleIds[1]) + assert.equal(+info2.exitedValidatorsCount, 2) + }) + + it('exited validators count accross all modules gets updated', async () => { + const totalExited = await router.getExitedValidatorsCountAcrossAllModules() + assert.equal(+totalExited, 5) + }) + + it('no functions were called on any module', async () => { + const callInfo1 = await getCallInfo(module1) + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 0) + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + const callInfo2 = await getCallInfo(module2) + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 0) + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it(`calling onValidatorsCountsByNodeOperatorReportingFinished doesn't call ` + + `anything on any module`, async () => + { + await router.onValidatorsCountsByNodeOperatorReportingFinished({ from: admin }) + + const callInfo1 = await getCallInfo(module1) + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 0) + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + const callInfo2 = await getCallInfo(module2) + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 0) + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it('reporting stuck validators by node operator passes the info to the module 1', async () => { + const nodeOpIds = [1] + const validatorsCounts = [3] + + const nodeOpIdsData = hexConcat(...nodeOpIds.map(i => hex(i, 8))) + const validatorsCountsData = hexConcat(...validatorsCounts.map(c => hex(c, 16))) + + await router.reportStakingModuleStuckValidatorsCountByNodeOperator( + moduleIds[0], nodeOpIdsData, validatorsCountsData, + { from: admin } + ) + + const callInfo1 = await getCallInfo(module1) + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo1.updateStuckValidatorsCount.nodeOperatorIds, nodeOpIdsData) + assert.equal(callInfo1.updateStuckValidatorsCount.validatorsCounts, validatorsCountsData) + + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + const callInfo2 = await getCallInfo(module2) + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 0) + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it('reporting stuck validators by node operator passes the info to the module 2', async () => { + const nodeOpIds = [33] + const validatorsCounts = [7] + + const nodeOpIdsData = hexConcat(...nodeOpIds.map(i => hex(i, 8))) + const validatorsCountsData = hexConcat(...validatorsCounts.map(c => hex(c, 16))) + + await router.reportStakingModuleStuckValidatorsCountByNodeOperator( + moduleIds[1], nodeOpIdsData, validatorsCountsData, + { from: admin } + ) + + const callInfo2 = await getCallInfo(module2) + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo2.updateStuckValidatorsCount.nodeOperatorIds, nodeOpIdsData) + assert.equal(callInfo2.updateStuckValidatorsCount.validatorsCounts, validatorsCountsData) + + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + const callInfo1 = await getCallInfo(module1) + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it(`calling onValidatorsCountsByNodeOperatorReportingFinished still doesn't call ` + + `anything on any module`, async () => + { + await router.onValidatorsCountsByNodeOperatorReportingFinished({ from: admin }) + + const callInfo1 = await getCallInfo(module1) + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + const callInfo2 = await getCallInfo(module2) + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it('reporting exited validators by node operator passes the info to the module 1', async () => { + const nodeOpIds = [3, 4] + const validatorsCounts = [1, 1] + + const nodeOpIdsData = hexConcat(...nodeOpIds.map(i => hex(i, 8))) + const validatorsCountsData = hexConcat(...validatorsCounts.map(c => hex(c, 16))) + + await router.reportStakingModuleExitedValidatorsCountByNodeOperator( + moduleIds[0], nodeOpIdsData, validatorsCountsData, + { from: admin } + ) + + const callInfo1 = await getCallInfo(module1) + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 1) + assert.equal(callInfo1.updateExitedValidatorsCount.nodeOperatorIds, nodeOpIdsData) + assert.equal(callInfo1.updateExitedValidatorsCount.validatorsCounts, validatorsCountsData) + + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + const callInfo2 = await getCallInfo(module2) + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it('the staking module 1 updates its internal total exited counter to 2', async () => { + await module1.setTotalExitedValidatorsCount(2) + }) + + it(`calling onValidatorsCountsByNodeOperatorReportingFinished still doesn't call ` + + `anything on any module`, async () => + { + await router.onValidatorsCountsByNodeOperatorReportingFinished({ from: admin }) + + const callInfo1 = await getCallInfo(module1) + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 1) + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + const callInfo2 = await getCallInfo(module2) + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 0) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it('reporting exited validators by node operator passes the info to the module 2', async () => { + const nodeOpIds = [20] + const validatorsCounts = [1] + + const nodeOpIdsData = hexConcat(...nodeOpIds.map(i => hex(i, 8))) + const validatorsCountsData = hexConcat(...validatorsCounts.map(c => hex(c, 16))) + + await router.reportStakingModuleExitedValidatorsCountByNodeOperator( + moduleIds[1], nodeOpIdsData, validatorsCountsData, + { from: admin } + ) + + const callInfo2 = await getCallInfo(module2) + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 1) + assert.equal(callInfo2.updateExitedValidatorsCount.nodeOperatorIds, nodeOpIdsData) + assert.equal(callInfo2.updateExitedValidatorsCount.validatorsCounts, validatorsCountsData) + + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + const callInfo1 = await getCallInfo(module1) + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 1) + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + }) + + it('the staking module 2 updates its internal total exited counter to 2', async () => { + await module2.setTotalExitedValidatorsCount(2) + }) + + it(`now that router's view on exited validators total match the module 2's view,` + + `calling onValidatorsCountsByNodeOperatorReportingFinished calls ` + + `onExitedAndStuckValidatorsCountsUpdated on the module 2`, async () => + { + await router.onValidatorsCountsByNodeOperatorReportingFinished({ from: admin }) + + const callInfo1 = await getCallInfo(module1) + const callInfo2 = await getCallInfo(module2) + + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 1) + + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 1) + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 1) + + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 1) + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 1) + }) + + it('reporting exited validators by node operator passes the info to the module 1', async () => { + const nodeOpIds = [55] + const validatorsCounts = [1] + + const nodeOpIdsData = hexConcat(...nodeOpIds.map(i => hex(i, 8))) + const validatorsCountsData = hexConcat(...validatorsCounts.map(c => hex(c, 16))) + + await router.reportStakingModuleExitedValidatorsCountByNodeOperator( + moduleIds[0], nodeOpIdsData, validatorsCountsData, + { from: admin } + ) + + const callInfo1 = await getCallInfo(module1) + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 2) + assert.equal(callInfo1.updateExitedValidatorsCount.nodeOperatorIds, nodeOpIdsData) + assert.equal(callInfo1.updateExitedValidatorsCount.validatorsCounts, validatorsCountsData) + + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 0) + + const callInfo2 = await getCallInfo(module2) + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 1) + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 1) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 1) + }) + + it('the staking module 1 updates its internal total exited counter to 3', async () => { + await module1.setTotalExitedValidatorsCount(3) + }) + + it(`now that router's view on exited validators total match the both modules' view,` + + `calling onValidatorsCountsByNodeOperatorReportingFinished calls ` + + `onExitedAndStuckValidatorsCountsUpdated on both modules`, async () => + { + await router.onValidatorsCountsByNodeOperatorReportingFinished({ from: admin }) + + const callInfo1 = await getCallInfo(module1) + const callInfo2 = await getCallInfo(module2) + + assert.equal(callInfo1.onExitedAndStuckValidatorsCountsUpdated.callCount, 1) + assert.equal(callInfo2.onExitedAndStuckValidatorsCountsUpdated.callCount, 2) + + assert.equal(callInfo1.updateExitedValidatorsCount.callCount, 2) + assert.equal(callInfo1.updateStuckValidatorsCount.callCount, 1) + + assert.equal(callInfo2.updateExitedValidatorsCount.callCount, 1) + assert.equal(callInfo2.updateStuckValidatorsCount.callCount, 1) + }) + }) + }) +}) From fcfad6c57011ccf5a123db0ffa2520c2a78e6d90 Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 21 Feb 2023 15:33:38 +0200 Subject: [PATCH 195/199] test: fix fails on coverage run --- test/0.8.9/withdrawal-queue.test.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test/0.8.9/withdrawal-queue.test.js b/test/0.8.9/withdrawal-queue.test.js index 12ea31350..1601cf401 100644 --- a/test/0.8.9/withdrawal-queue.test.js +++ b/test/0.8.9/withdrawal-queue.test.js @@ -27,7 +27,8 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { await withdrawalQueue.resume({ from: daoAgent }) await steth.setTotalPooledEther(ETH(600)) - await setBalance(steth.address, ETH(600)) + // we need 1 ETH additionally to pay gas on finalization because coverage ingnores gasPrice=0 + await setBalance(steth.address, ETH(600 + 1)) await steth.mintShares(user, shares(1)) await steth.approve(withdrawalQueue.address, StETH(300), { from: user }) @@ -310,9 +311,10 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { const balanceBefore = bn(await ethers.provider.getBalance(owner)) - await withdrawalQueue.claimWithdrawal(1, { from: owner }) + const tx = await withdrawalQueue.claimWithdrawal(1, { from: owner }) - assert.equals(await ethers.provider.getBalance(owner), balanceBefore.add(bn(amount))) + // tx.receipt.gasUsed is a workaround for coverage, because it ignores gasPrice=0 + assert.almostEqual(await ethers.provider.getBalance(owner), balanceBefore.add(bn(amount)), tx.receipt.gasUsed) }) it('One cant claim not finalized or not existed request', async () => { @@ -346,10 +348,11 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { const balanceBefore = bn(await ethers.provider.getBalance(owner)) assert.equals(await withdrawalQueue.getLockedEtherAmount(), ETH(150)) - await withdrawalQueue.claimWithdrawal(1, { from: owner }) + const tx = await withdrawalQueue.claimWithdrawal(1, { from: owner }) assert.equals(await withdrawalQueue.getLockedEtherAmount(), ETH(0)) - assert.equals(bn(await ethers.provider.getBalance(owner)).sub(balanceBefore), ETH(150)) + // tx.receipt.gasUsed is a workaround for coverage, because it ignores gasPrice=0 + assert.almostEqual(bn(await ethers.provider.getBalance(owner)).sub(balanceBefore), ETH(150), tx.receipt.gasUsed) }) it('One can claim a lot of withdrawals with different discounts', async () => { @@ -698,8 +701,9 @@ contract('WithdrawalQueue', ([owner, stranger, daoAgent, user]) => { await withdrawalQueue.finalize(secondRequestId, { from: steth.address, value: ETH(30) }) const balanceBefore = bn(await ethers.provider.getBalance(owner)) - await withdrawalQueue.claimWithdrawals([1, 2], [1, 1], { from: owner }) - assert.equals(await ethers.provider.getBalance(owner), balanceBefore.add(bn(ETH(30)))) + const tx = await withdrawalQueue.claimWithdrawals([1, 2], [1, 1], { from: owner }) + // tx.receipt.gasUsed is a workaround for coverage, because it ignores gasPrice=0 + assert.almostEqual(await ethers.provider.getBalance(owner), balanceBefore.add(bn(ETH(30))), tx.receipt.gasUsed) }) }) From 2f3efae841f9b6abd35d8a13c695167053cc947d Mon Sep 17 00:00:00 2001 From: Alexey Potapkin Date: Tue, 21 Feb 2023 15:34:18 +0200 Subject: [PATCH 196/199] chore: abi --- lib/abi/AccountingOracle.json | 2 +- lib/abi/IStakingRouter.json | 2 +- lib/abi/NodeOperatorsRegistry.json | 2 +- lib/abi/StakingRouter.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/abi/AccountingOracle.json b/lib/abi/AccountingOracle.json index dadcadb73..6def379da 100644 --- a/lib/abi/AccountingOracle.json +++ b/lib/abi/AccountingOracle.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"lidoLocator","type":"address"},{"internalType":"address","name":"lido","type":"address"},{"internalType":"address","name":"legacyOracle","type":"address"},{"internalType":"uint256","name":"secondsPerSlot","type":"uint256"},{"internalType":"uint256","name":"genesisTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressCannotBeSame","type":"error"},{"inputs":[],"name":"AddressCannotBeZero","type":"error"},{"inputs":[],"name":"AdminCannotBeZero","type":"error"},{"inputs":[],"name":"CannotSubmitExtraDataBeforeMainData","type":"error"},{"inputs":[],"name":"ExtraDataAlreadyProcessed","type":"error"},{"inputs":[],"name":"ExtraDataHashCannotBeZeroForNonEmptyData","type":"error"},{"inputs":[],"name":"ExtraDataItemsCountCannotBeZeroForNonEmptyData","type":"error"},{"inputs":[],"name":"ExtraDataListOnlySupportsSingleTx","type":"error"},{"inputs":[{"internalType":"uint256","name":"code","type":"uint256"}],"name":"IncorrectOracleMigration","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidExitedValidatorsData","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"name":"InvalidExtraDataItem","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"name":"InvalidExtraDataSortOrder","type":"error"},{"inputs":[],"name":"LegacyOracleCannotBeZero","type":"error"},{"inputs":[],"name":"LidoLocatorCannotBeZero","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NumExitedValidatorsCannotDecrease","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","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":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"SenderNotAllowed","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":"expectedFormat","type":"uint256"},{"internalType":"uint256","name":"receivedFormat","type":"uint256"}],"name":"UnexpectedExtraDataFormat","type":"error"},{"inputs":[{"internalType":"bytes32","name":"consensusHash","type":"bytes32"},{"internalType":"bytes32","name":"receivedHash","type":"bytes32"}],"name":"UnexpectedExtraDataHash","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedIndex","type":"uint256"},{"internalType":"uint256","name":"receivedIndex","type":"uint256"}],"name":"UnexpectedExtraDataIndex","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedCount","type":"uint256"},{"internalType":"uint256","name":"receivedCount","type":"uint256"}],"name":"UnexpectedExtraDataItemsCount","type":"error"},{"inputs":[{"internalType":"uint256","name":"consensusRefSlot","type":"uint256"},{"internalType":"uint256","name":"dataRefSlot","type":"uint256"}],"name":"UnexpectedRefSlot","type":"error"},{"inputs":[{"internalType":"uint256","name":"format","type":"uint256"}],"name":"UnsupportedExtraDataFormat","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"},{"internalType":"uint256","name":"dataType","type":"uint256"}],"name":"UnsupportedExtraDataType","type":"error"},{"inputs":[],"name":"VersionCannotBeSame","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":true,"internalType":"uint256","name":"refSlot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsProcessed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsCount","type":"uint256"}],"name":"ExtraDataSubmitted","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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"refSlot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"processedItemsCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsCount","type":"uint256"}],"name":"WarnExtraDataIncompleteProcessing","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refSlot","type":"uint256"}],"name":"WarnProcessingMissed","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_FORMAT_EMPTY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_FORMAT_LIST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_TYPE_EXITED_VALIDATORS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_TYPE_STUCK_VALIDATORS","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":"LEGACY_ORACLE","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":"LOCATOR","outputs":[{"internalType":"contract ILidoLocator","name":"","type":"address"}],"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":"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":"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":[],"name":"getLastProcessingRefSlot","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":"mainDataHash","type":"bytes32"},{"internalType":"bool","name":"mainDataSubmitted","type":"bool"},{"internalType":"bytes32","name":"extraDataHash","type":"bytes32"},{"internalType":"uint256","name":"extraDataFormat","type":"uint256"},{"internalType":"uint256","name":"extraDataItemsCount","type":"uint256"},{"internalType":"uint256","name":"extraDataItemsSubmitted","type":"uint256"}],"internalType":"struct AccountingOracle.ProcessingState","name":"result","type":"tuple"}],"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":"admin","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","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"}],"name":"initializeWithoutMigration","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":[{"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":"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":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"numValidators","type":"uint256"},{"internalType":"uint256","name":"clBalanceGwei","type":"uint256"},{"internalType":"uint256[]","name":"stakingModuleIdsWithNewlyExitedValidators","type":"uint256[]"},{"internalType":"uint256[]","name":"numExitedValidatorsByStakingModule","type":"uint256[]"},{"internalType":"uint256","name":"withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"lastFinalizableWithdrawalRequestId","type":"uint256"},{"internalType":"uint256","name":"simulatedShareRate","type":"uint256"},{"internalType":"bool","name":"isBunkerMode","type":"bool"},{"internalType":"uint256","name":"extraDataFormat","type":"uint256"},{"internalType":"bytes32","name":"extraDataHash","type":"bytes32"},{"internalType":"uint256","name":"extraDataItemsCount","type":"uint256"}],"internalType":"struct AccountingOracle.ReportData","name":"data","type":"tuple"},{"internalType":"uint256","name":"contractVersion","type":"uint256"}],"name":"submitReportData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"items","type":"bytes"}],"name":"submitReportExtraDataList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"lidoLocator","type":"address"},{"internalType":"address","name":"lido","type":"address"},{"internalType":"address","name":"legacyOracle","type":"address"},{"internalType":"uint256","name":"secondsPerSlot","type":"uint256"},{"internalType":"uint256","name":"genesisTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressCannotBeSame","type":"error"},{"inputs":[],"name":"AddressCannotBeZero","type":"error"},{"inputs":[],"name":"AdminCannotBeZero","type":"error"},{"inputs":[],"name":"CannotSubmitExtraDataBeforeMainData","type":"error"},{"inputs":[],"name":"ExtraDataAlreadyProcessed","type":"error"},{"inputs":[],"name":"ExtraDataHashCannotBeZeroForNonEmptyData","type":"error"},{"inputs":[],"name":"ExtraDataItemsCountCannotBeZeroForNonEmptyData","type":"error"},{"inputs":[],"name":"ExtraDataListOnlySupportsSingleTx","type":"error"},{"inputs":[{"internalType":"uint256","name":"code","type":"uint256"}],"name":"IncorrectOracleMigration","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[],"name":"InvalidExitedValidatorsData","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"name":"InvalidExtraDataItem","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"name":"InvalidExtraDataSortOrder","type":"error"},{"inputs":[],"name":"LegacyOracleCannotBeZero","type":"error"},{"inputs":[],"name":"LidoLocatorCannotBeZero","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NumExitedValidatorsCannotDecrease","type":"error"},{"inputs":[],"name":"OnlyConsensusContractCanSubmitReport","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":"processingRefSlot","type":"uint256"}],"name":"RefSlotCannotBeLessThanProcessingOne","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":"SenderNotAllowed","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":"expectedFormat","type":"uint256"},{"internalType":"uint256","name":"receivedFormat","type":"uint256"}],"name":"UnexpectedExtraDataFormat","type":"error"},{"inputs":[{"internalType":"bytes32","name":"consensusHash","type":"bytes32"},{"internalType":"bytes32","name":"receivedHash","type":"bytes32"}],"name":"UnexpectedExtraDataHash","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedIndex","type":"uint256"},{"internalType":"uint256","name":"receivedIndex","type":"uint256"}],"name":"UnexpectedExtraDataIndex","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedCount","type":"uint256"},{"internalType":"uint256","name":"receivedCount","type":"uint256"}],"name":"UnexpectedExtraDataItemsCount","type":"error"},{"inputs":[{"internalType":"uint256","name":"consensusRefSlot","type":"uint256"},{"internalType":"uint256","name":"dataRefSlot","type":"uint256"}],"name":"UnexpectedRefSlot","type":"error"},{"inputs":[{"internalType":"uint256","name":"format","type":"uint256"}],"name":"UnsupportedExtraDataFormat","type":"error"},{"inputs":[{"internalType":"uint256","name":"itemIndex","type":"uint256"},{"internalType":"uint256","name":"dataType","type":"uint256"}],"name":"UnsupportedExtraDataType","type":"error"},{"inputs":[],"name":"VersionCannotBeSame","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":true,"internalType":"uint256","name":"refSlot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsProcessed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsCount","type":"uint256"}],"name":"ExtraDataSubmitted","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"},{"indexed":false,"internalType":"uint256","name":"processingDeadlineTime","type":"uint256"}],"name":"ReportSubmitted","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":"refSlot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"processedItemsCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsCount","type":"uint256"}],"name":"WarnExtraDataIncompleteProcessing","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refSlot","type":"uint256"}],"name":"WarnProcessingMissed","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_FORMAT_EMPTY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_FORMAT_LIST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_TYPE_EXITED_VALIDATORS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_DATA_TYPE_STUCK_VALIDATORS","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":"LEGACY_ORACLE","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":"LOCATOR","outputs":[{"internalType":"contract ILidoLocator","name":"","type":"address"}],"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":"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":"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":[],"name":"getLastProcessingRefSlot","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":"mainDataHash","type":"bytes32"},{"internalType":"bool","name":"mainDataSubmitted","type":"bool"},{"internalType":"bytes32","name":"extraDataHash","type":"bytes32"},{"internalType":"uint256","name":"extraDataFormat","type":"uint256"},{"internalType":"bool","name":"extraDataSubmitted","type":"bool"},{"internalType":"uint256","name":"extraDataItemsCount","type":"uint256"},{"internalType":"uint256","name":"extraDataItemsSubmitted","type":"uint256"}],"internalType":"struct AccountingOracle.ProcessingState","name":"result","type":"tuple"}],"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":"admin","type":"address"},{"internalType":"address","name":"consensusContract","type":"address"},{"internalType":"uint256","name":"consensusVersion","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","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"}],"name":"initializeWithoutMigration","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":[{"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":"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":"uint256","name":"consensusVersion","type":"uint256"},{"internalType":"uint256","name":"refSlot","type":"uint256"},{"internalType":"uint256","name":"numValidators","type":"uint256"},{"internalType":"uint256","name":"clBalanceGwei","type":"uint256"},{"internalType":"uint256[]","name":"stakingModuleIdsWithNewlyExitedValidators","type":"uint256[]"},{"internalType":"uint256[]","name":"numExitedValidatorsByStakingModule","type":"uint256[]"},{"internalType":"uint256","name":"withdrawalVaultBalance","type":"uint256"},{"internalType":"uint256","name":"elRewardsVaultBalance","type":"uint256"},{"internalType":"uint256","name":"lastFinalizableWithdrawalRequestId","type":"uint256"},{"internalType":"uint256","name":"simulatedShareRate","type":"uint256"},{"internalType":"bool","name":"isBunkerMode","type":"bool"},{"internalType":"uint256","name":"extraDataFormat","type":"uint256"},{"internalType":"bytes32","name":"extraDataHash","type":"bytes32"},{"internalType":"uint256","name":"extraDataItemsCount","type":"uint256"}],"internalType":"struct AccountingOracle.ReportData","name":"data","type":"tuple"},{"internalType":"uint256","name":"contractVersion","type":"uint256"}],"name":"submitReportData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"submitReportExtraDataEmpty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"items","type":"bytes"}],"name":"submitReportExtraDataList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/lib/abi/IStakingRouter.json b/lib/abi/IStakingRouter.json index 546692e99..4cdff3a03 100644 --- a/lib/abi/IStakingRouter.json +++ b/lib/abi/IStakingRouter.json @@ -1 +1 @@ -[{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"moduleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"onValidatorsCountsByNodeOperatorReportingFinished","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"moduleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/lib/abi/NodeOperatorsRegistry.json b/lib/abi/NodeOperatorsRegistry.json index cdcfc9ae4..6efc49363 100644 --- a/lib/abi/NodeOperatorsRegistry.json +++ b/lib/abi/NodeOperatorsRegistry.json @@ -1 +1 @@ -[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onAllValidatorCountersUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"handleRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"},{"indexed":false,"name":"refundedValidatorsCount","type":"uint256"},{"indexed":false,"name":"stuckPenaltyEndTimestamp","type":"uint256"}],"name":"StuckPenaltyStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file +[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint64"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"onRewardsMinted","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"stakingLimit","type":"uint64"},{"name":"stoppedValidators","type":"uint64"},{"name":"totalSigningKeys","type":"uint64"},{"name":"usedSigningKeys","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"isTargetLimitActive","type":"bool"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onExitedAndStuckValidatorsCountsUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"},{"indexed":false,"name":"refundedValidatorsCount","type":"uint256"},{"indexed":false,"name":"stuckPenaltyEndTimestamp","type":"uint256"}],"name":"StuckPenaltyStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}] \ No newline at end of file diff --git a/lib/abi/StakingRouter.json b/lib/abi/StakingRouter.json index 99f1d1315..756ae6ed7 100644 --- a/lib/abi/StakingRouter.json +++ b/lib/abi/StakingRouter.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"EmptyWithdrawalsCredentials","type":"error"},{"inputs":[],"name":"ExitedValidatorsCountCannotDecrease","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"etherValue","type":"uint256"}],"name":"InvalidDepositsValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidPublicKeysBatchLength","type":"error"},{"inputs":[],"name":"InvalidReportData","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidSignaturesBatchLength","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"StakingModuleAddressExists","type":"error"},{"inputs":[],"name":"StakingModuleIdTooLarge","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","type":"error"},{"inputs":[],"name":"StakingModuleNotPaused","type":"error"},{"inputs":[],"name":"StakingModuleStatusTheSame","type":"error"},{"inputs":[],"name":"StakingModuleUnregistered","type":"error"},{"inputs":[],"name":"StakingModuleWrongName","type":"error"},{"inputs":[],"name":"StakingModulesLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpStuckValidatorsCount","type":"uint256"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ValueOver100Percent","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","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":false,"internalType":"address","name":"stakingModule","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"createdBy","type":"address"}],"name":"StakingModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unreportedExitedValidatorsCount","type":"uint256"}],"name":"StakingModuleExitedValidatorsIncompleteReporting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingModuleFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"enum StakingRouter.StakingModuleStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleTargetShareSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingRouterETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalCredentials","type":"bytes32"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"WithdrawalCredentialsSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PRECISION_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_WITHDRAWAL_CREDENTIALS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_REWARDS_MINTED_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_MANAGE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_SET_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_stakingModuleAddress","type":"address"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getAllNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"}],"name":"getDepositsAllocation","outputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256[]","name":"_nodeOperatorIds","type":"uint256[]"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"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":"getStakingFeeAggregateDistribution","outputs":[{"internalType":"uint96","name":"modulesFee","type":"uint96"},{"internalType":"uint96","name":"treasuryFee","type":"uint96"},{"internalType":"uint256","name":"basePrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingFeeAggregateDistributionE4Precision","outputs":[{"internalType":"uint16","name":"modulesFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModule","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleActiveValidatorsCount","outputs":[{"internalType":"uint256","name":"activeValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"}],"name":"getStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleIds","outputs":[{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleLastDepositBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_maxDepositsValue","type":"uint256"}],"name":"getStakingModuleMaxDepositsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleStatus","outputs":[{"internalType":"enum StakingRouter.StakingModuleStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleSummary","outputs":[{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModules","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule[]","name":"res","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingRewardsDistribution","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"},{"internalType":"uint96[]","name":"stakingModuleFees","type":"uint96[]"},{"internalType":"uint96","name":"totalFee","type":"uint96"},{"internalType":"uint256","name":"precisionPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFeeE4Precision","outputs":[{"internalType":"uint16","name":"totalFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalCredentials","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"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"pauseStakingModule","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":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_totalShares","type":"uint256[]"}],"name":"reportRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"resumeStakingModule","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":"_stakingModuleId","type":"uint256"},{"internalType":"enum StakingRouter.StakingModuleStatus","name":"_status","type":"uint8"}],"name":"setStakingModuleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","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":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"_triggerUpdateFinish","type":"bool"},{"components":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorStuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorStuckValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.ValidatorsCountCorrection","name":"_correction","type":"tuple"}],"name":"unsafeSetExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[],"name":"DepositContractZeroAddress","type":"error"},{"inputs":[],"name":"DirectETHTransfer","type":"error"},{"inputs":[],"name":"EmptyWithdrawalsCredentials","type":"error"},{"inputs":[],"name":"ExitedValidatorsCountCannotDecrease","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"etherValue","type":"uint256"}],"name":"InvalidDepositsValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidPublicKeysBatchLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"code","type":"uint256"}],"name":"InvalidReportData","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidSignaturesBatchLength","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"StakingModuleAddressExists","type":"error"},{"inputs":[],"name":"StakingModuleIdTooLarge","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","type":"error"},{"inputs":[],"name":"StakingModuleNotPaused","type":"error"},{"inputs":[],"name":"StakingModuleStatusTheSame","type":"error"},{"inputs":[],"name":"StakingModuleUnregistered","type":"error"},{"inputs":[],"name":"StakingModuleWrongName","type":"error"},{"inputs":[],"name":"StakingModulesLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOpStuckValidatorsCount","type":"uint256"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ValueOver100Percent","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","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":false,"internalType":"address","name":"stakingModule","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"createdBy","type":"address"}],"name":"StakingModuleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unreportedExitedValidatorsCount","type":"uint256"}],"name":"StakingModuleExitedValidatorsIncompleteReporting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakingModuleFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"treasuryFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"enum StakingRouter.StakingModuleStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleTargetShareSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakingRouterETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalCredentials","type":"bytes32"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"WithdrawalCredentialsSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PRECISION_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_WITHDRAWAL_CREDENTIALS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_REWARDS_MINTED_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_MANAGE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_MODULE_RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOTAL_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_SET_EXITED_VALIDATORS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_stakingModuleAddress","type":"address"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getAllNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositsCount","type":"uint256"}],"name":"getDepositsAllocation","outputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitedValidatorsCountAcrossAllModules","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLido","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256[]","name":"_nodeOperatorIds","type":"uint256[]"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getNodeOperatorDigests","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.NodeOperatorDigest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"components":[{"internalType":"bool","name":"isTargetLimitActive","type":"bool"},{"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":"struct StakingRouter.NodeOperatorSummary","name":"summary","type":"tuple"}],"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":"getStakingFeeAggregateDistribution","outputs":[{"internalType":"uint96","name":"modulesFee","type":"uint96"},{"internalType":"uint96","name":"treasuryFee","type":"uint96"},{"internalType":"uint256","name":"basePrecision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingFeeAggregateDistributionE4Precision","outputs":[{"internalType":"uint16","name":"modulesFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModule","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleActiveValidatorsCount","outputs":[{"internalType":"uint256","name":"activeValidatorsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"}],"name":"getStakingModuleDigests","outputs":[{"components":[{"internalType":"uint256","name":"nodeOperatorsCount","type":"uint256"},{"internalType":"uint256","name":"activeNodeOperatorsCount","type":"uint256"},{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule","name":"state","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"internalType":"struct StakingRouter.StakingModuleDigest[]","name":"digests","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModuleIds","outputs":[{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleIsStopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleLastDepositBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_maxDepositsValue","type":"uint256"}],"name":"getStakingModuleMaxDepositsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleStatus","outputs":[{"internalType":"enum StakingRouter.StakingModuleStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleSummary","outputs":[{"components":[{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModuleSummary","name":"summary","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModules","outputs":[{"components":[{"internalType":"uint24","name":"id","type":"uint24"},{"internalType":"address","name":"stakingModuleAddress","type":"address"},{"internalType":"uint16","name":"stakingModuleFee","type":"uint16"},{"internalType":"uint16","name":"treasuryFee","type":"uint16"},{"internalType":"uint16","name":"targetShare","type":"uint16"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint64","name":"lastDepositAt","type":"uint64"},{"internalType":"uint256","name":"lastDepositBlock","type":"uint256"},{"internalType":"uint256","name":"exitedValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.StakingModule[]","name":"res","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingModulesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakingRewardsDistribution","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"stakingModuleIds","type":"uint256[]"},{"internalType":"uint96[]","name":"stakingModuleFees","type":"uint96[]"},{"internalType":"uint96","name":"totalFee","type":"uint96"},{"internalType":"uint256","name":"precisionPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalFeeE4Precision","outputs":[{"internalType":"uint16","name":"totalFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalCredentials","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"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"onValidatorsCountsByNodeOperatorReportingFinished","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"pauseStakingModule","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":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_totalShares","type":"uint256[]"}],"name":"reportRewardsMinted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_exitedValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleExitedValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_stuckValidatorsCounts","type":"bytes"}],"name":"reportStakingModuleStuckValidatorsCountByNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"resumeStakingModule","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":"_stakingModuleId","type":"uint256"},{"internalType":"enum StakingRouter.StakingModuleStatus","name":"_status","type":"uint8"}],"name":"setStakingModuleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","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":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"bool","name":"_triggerUpdateFinish","type":"bool"},{"components":[{"internalType":"uint256","name":"currentModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"currentNodeOperatorStuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorStuckValidatorsCount","type":"uint256"}],"internalType":"struct StakingRouter.ValidatorsCountsCorrection","name":"_correction","type":"tuple"}],"name":"unsafeSetExitedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_stakingModuleIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_exitedValidatorsCounts","type":"uint256[]"}],"name":"updateExitedValidatorsCountByStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_targetShare","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file From d73a951498b4471d2f0770c8a9d513100aa7411b Mon Sep 17 00:00:00 2001 From: ujenjt Date: Tue, 21 Feb 2023 14:55:06 +0100 Subject: [PATCH 197/199] =?UTF-8?q?feat:=20add=20NFTDescriptor=20as=20an?= =?UTF-8?q?=20onchain=20way=20of=20generating=20metadata=20for=20NFT=20for?= =?UTF-8?q?=20WithdrawalQueueERC721=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/0.8.9/WithdrawalQueueERC721.sol | 45 +++++++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueueERC721.sol b/contracts/0.8.9/WithdrawalQueueERC721.sol index 5d95cdfd4..14d364f36 100644 --- a/contracts/0.8.9/WithdrawalQueueERC721.sol +++ b/contracts/0.8.9/WithdrawalQueueERC721.sol @@ -16,6 +16,18 @@ import {Strings} from "@openzeppelin/contracts-v4.4/utils/Strings.sol"; import {IWstETH, WithdrawalQueue} from "./WithdrawalQueue.sol"; import {AccessControlEnumerable} from "./utils/access/AccessControlEnumerable.sol"; import {UnstructuredRefStorage} from "./lib/UnstructuredRefStorage.sol"; +import {UnstructuredStorage} from "./lib/UnstructuredStorage.sol"; + +/** + * @title Interface defining INFTDescriptor to generate ERC721 metadata + */ +interface INFTDescriptor { + /** + * @notice Returns ERC721 metadata + * @param _requestId is an id for particular withdrawal request + */ + function constructTokenURI(uint256 _requestId) external view returns (string memory); +} /// @title NFT implementation on top of {WithdrawalQueue} /// NFT is minted on every request and burned on claim @@ -26,12 +38,14 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { using Strings for uint256; using EnumerableSet for EnumerableSet.UintSet; using UnstructuredRefStorage for bytes32; + using UnstructuredStorage for bytes32; bytes32 internal constant TOKEN_APPROVALS_POSITION = keccak256("lido.WithdrawalQueueERC721.tokenApprovals"); bytes32 internal constant OPERATOR_APPROVALS_POSITION = keccak256("lido.WithdrawalQueueERC721.operatorApprovals"); bytes32 internal constant BASE_URI_POSITION = keccak256("lido.WithdrawalQueueERC721.baseUri"); + bytes32 internal constant NFT_DESCRIPTOR_ADDRESS_POSITION = keccak256("lido.WithdrawalQueueERC721.nftDescriptorAddress"); - bytes32 public constant SET_BASE_URI_ROLE = keccak256("SET_BASE_URI_ROLE"); + bytes32 public constant MANAGE_TOKEN_URI_ROLE = keccak256("MANAGE_TOKEN_URI_ROLE"); // @notion simple wrapper for base URI string // Solidity does not allow to store string in UnstructuredStorage @@ -40,6 +54,7 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { } event BaseURISet(string baseURI); + event NftDescriptorAddressSet(address nftDescriptorAddress); error ApprovalToOwner(); error ApproveToCaller(); @@ -90,11 +105,18 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { } /// @dev See {IERC721Metadata-tokenURI}. + /// @dev If NFTDescriptor address isn't set the `baseURI` would be used for generating erc721 metadata. In case + /// NFTDescriptor address is set it would be used as a priority method. function tokenURI(uint256 _requestId) public view virtual override returns (string memory) { if (!_existsAndNotClaimed(_requestId)) revert InvalidRequestId(_requestId); - string memory baseURI = _getBaseURI().value; - return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, _requestId.toString())) : ""; + address nftDescriptorAddress = NFT_DESCRIPTOR_ADDRESS_POSITION.getStorageAddress(); + if (nftDescriptorAddress != address(0)) { + return INFTDescriptor(nftDescriptorAddress).constructTokenURI(_requestId); + } else { + string memory baseURI = _getBaseURI().value; + return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, _requestId.toString())) : ""; + } } /// @notice Base URI for computing {tokenURI}. If set, the resulting URI for each @@ -104,11 +126,26 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { } /// @notice Sets the Base URI for computing {tokenURI} - function setBaseURI(string calldata _baseURI) external onlyRole(SET_BASE_URI_ROLE) { + /// @dev If NFTDescriptor address isn't set the `baseURI` would be used for generating erc721 metadata. In case + /// NFTDescriptor address is set it would be used as a priority method. + function setBaseURI(string calldata _baseURI) external onlyRole(MANAGE_TOKEN_URI_ROLE) { _getBaseURI().value = _baseURI; emit BaseURISet(_baseURI); } + /// @notice Address of NFTDescriptor contract that is responsible for metadata generation. + function getNFTDescriptorAddress() external view returns (address) { + return NFT_DESCRIPTOR_ADDRESS_POSITION.getStorageAddress(); + } + + /// @notice Sets the address of NFTDescriptor contract that is responsible for metadata generation. + /// @dev If NFTDescriptor address isn't set the `baseURI` would be used for generating erc721 metadata. In case + /// NFTDescriptor address is set it would be used as a priority method. + function setNFTDescriptorAddress(address _nftDescriptorAddress) external onlyRole(MANAGE_TOKEN_URI_ROLE) { + NFT_DESCRIPTOR_ADDRESS_POSITION.setStorageAddress(_nftDescriptorAddress); + emit NftDescriptorAddressSet(_nftDescriptorAddress); + } + /// @dev See {IERC721-balanceOf}. function balanceOf(address _owner) external view override returns (uint256) { if (_owner == address(0)) revert InvalidOwnerAddress(_owner); From b4604dca8b630d4d5fd94caecafcdbd8ab0713b3 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Tue, 21 Feb 2023 17:51:16 +0300 Subject: [PATCH 198/199] abi: bump NFT abis --- lib/abi/INFTDescriptor.json | 1 + lib/abi/WithdrawalQueueERC721.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 lib/abi/INFTDescriptor.json diff --git a/lib/abi/INFTDescriptor.json b/lib/abi/INFTDescriptor.json new file mode 100644 index 000000000..c42b80ece --- /dev/null +++ b/lib/abi/INFTDescriptor.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"constructTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/lib/abi/WithdrawalQueueERC721.json b/lib/abi/WithdrawalQueueERC721.json index ce9a574ad..728ac3391 100644 --- a/lib/abi/WithdrawalQueueERC721.json +++ b/lib/abi/WithdrawalQueueERC721.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"SET_BASE_URI_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":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","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":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"_wstETH","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminZeroAddress","type":"error"},{"inputs":[],"name":"ApprovalToOwner","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"CantSendValueRecipientMayHaveReverted","type":"error"},{"inputs":[],"name":"InvalidContractVersionIncrement","type":"error"},{"inputs":[{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"InvalidHint","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"InvalidOwnerAddress","type":"error"},{"inputs":[],"name":"InvalidReportTimestamp","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"InvalidRequestId","type":"error"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"InvalidRequestIdRange","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[],"name":"NotEnoughEther","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"NotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApproved","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotOwnerOrApprovedForAll","type":"error"},{"inputs":[],"name":"PausedExpected","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestAlreadyClaimed","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"_amountOfStETH","type":"uint256"}],"name":"RequestAmountTooSmall","type":"error"},{"inputs":[],"name":"RequestIdsNotSorted","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"RequestNotFoundOrNotFinalized","type":"error"},{"inputs":[],"name":"ResumedExpected","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"maxExpected","type":"uint256"}],"name":"TooMuchEtherToFinalize","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"realOwner","type":"address"}],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"TransferToNonIERC721Receiver","type":"error"},{"inputs":[],"name":"TransferToThemselves","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"UnexpectedContractVersion","type":"error"},{"inputs":[],"name":"ZeroAmountOfETH","type":"error"},{"inputs":[],"name":"ZeroMetadata","type":"error"},{"inputs":[],"name":"ZeroPauseDuration","type":"error"},{"inputs":[],"name":"ZeroRecipient","type":"error"},{"inputs":[],"name":"ZeroShareRate","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"BunkerModeDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"BunkerModeEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"},{"indexed":false,"internalType":"address","name":"_resumer","type":"address"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"},{"indexed":false,"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"InitializedV1","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"nftDescriptorAddress","type":"address"}],"name":"NftDescriptorAddressSet","type":"event"},{"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfETHLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesToBurn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"WithdrawalBatchFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfETH","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"address","name":"requestor","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfShares","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"BUNKER_MODE_DISABLED_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNKER_MODE_REPORT_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":"E27_PRECISION_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_TOKEN_URI_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"contract IWstETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bunkerModeSinceTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimWithdrawalsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"}],"name":"finalizationBatch","outputs":[{"internalType":"uint256","name":"ethToLock","type":"uint256"},{"internalType":"uint256","name":"sharesToBurn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nextFinalizedRequestId","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256","name":"_firstIndex","type":"uint256"},{"internalType":"uint256","name":"_lastIndex","type":"uint256"}],"name":"findCheckpointHints","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"findCheckpointHintsUnbounded","outputs":[{"internalType":"uint256[]","name":"hintIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"}],"name":"findLastFinalizableRequestId","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethBudget","type":"uint256"},{"internalType":"uint256","name":"_shareRate","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByBudget","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTimestamp","type":"uint256"},{"internalType":"uint256","name":"_startId","type":"uint256"},{"internalType":"uint256","name":"_endId","type":"uint256"}],"name":"findLastFinalizableRequestIdByTimestamp","outputs":[{"internalType":"uint256","name":"finalizableRequestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_hints","type":"uint256[]"}],"name":"getClaimableEther","outputs":[{"internalType":"uint256[]","name":"claimableEthValues","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastCheckpointIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastFinalizedRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLockedEtherAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNFTDescriptorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"address","name":"_owner","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"internalType":"uint256[]","name":"requestsIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"getWithdrawalStatus","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct WithdrawalQueueBase.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"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":"_pauser","type":"address"},{"internalType":"address","name":"_resumer","type":"address"},{"internalType":"address","name":"_finalizer","type":"address"},{"internalType":"address","name":"_bunkerReporter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBunkerModeActive","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":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"pause","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":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawals","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"}],"name":"requestWithdrawalsWstETH","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_owner","type":"address"},{"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 WithdrawalQueue.PermitInput","name":"_permit","type":"tuple"}],"name":"requestWithdrawalsWstETHWithPermit","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"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":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nftDescriptorAddress","type":"address"}],"name":"setNFTDescriptorAddress","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfinalizedRequestNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unfinalizedStETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isBunkerModeNow","type":"bool"},{"internalType":"uint256","name":"_sinceTimestamp","type":"uint256"}],"name":"updateBunkerMode","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file From ff4907919dfc7705c747754d22b9e102408061d9 Mon Sep 17 00:00:00 2001 From: ujenjt Date: Tue, 21 Feb 2023 15:54:29 +0100 Subject: [PATCH 199/199] =?UTF-8?q?fix:=20comments=20and=20docs=20?= =?UTF-8?q?=F0=9F=93=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/0.8.9/WithdrawalQueueERC721.sol | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/contracts/0.8.9/WithdrawalQueueERC721.sol b/contracts/0.8.9/WithdrawalQueueERC721.sol index 14d364f36..e22d8201f 100644 --- a/contracts/0.8.9/WithdrawalQueueERC721.sol +++ b/contracts/0.8.9/WithdrawalQueueERC721.sol @@ -19,11 +19,11 @@ import {UnstructuredRefStorage} from "./lib/UnstructuredRefStorage.sol"; import {UnstructuredStorage} from "./lib/UnstructuredStorage.sol"; /** - * @title Interface defining INFTDescriptor to generate ERC721 metadata + * @title Interface defining INFTDescriptor to generate ERC721 tokenURI */ interface INFTDescriptor { /** - * @notice Returns ERC721 metadata + * @notice Returns ERC721 tokenURI content * @param _requestId is an id for particular withdrawal request */ function constructTokenURI(uint256 _requestId) external view returns (string memory); @@ -105,8 +105,8 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { } /// @dev See {IERC721Metadata-tokenURI}. - /// @dev If NFTDescriptor address isn't set the `baseURI` would be used for generating erc721 metadata. In case - /// NFTDescriptor address is set it would be used as a priority method. + /// @dev If NFTDescriptor address isn't set the `baseURI` would be used for generating erc721 tokenURI. In case + /// NFTDescriptor address is set it would be used as a first-priority method. function tokenURI(uint256 _requestId) public view virtual override returns (string memory) { if (!_existsAndNotClaimed(_requestId)) revert InvalidRequestId(_requestId); @@ -126,21 +126,21 @@ contract WithdrawalQueueERC721 is IERC721Metadata, WithdrawalQueue { } /// @notice Sets the Base URI for computing {tokenURI} - /// @dev If NFTDescriptor address isn't set the `baseURI` would be used for generating erc721 metadata. In case - /// NFTDescriptor address is set it would be used as a priority method. + /// @dev If NFTDescriptor address isn't set the `baseURI` would be used for generating erc721 tokenURI. In case + /// NFTDescriptor address is set it would be used as a first-priority method. function setBaseURI(string calldata _baseURI) external onlyRole(MANAGE_TOKEN_URI_ROLE) { _getBaseURI().value = _baseURI; emit BaseURISet(_baseURI); } - /// @notice Address of NFTDescriptor contract that is responsible for metadata generation. + /// @notice Address of NFTDescriptor contract that is responsible for tokenURI generation. function getNFTDescriptorAddress() external view returns (address) { return NFT_DESCRIPTOR_ADDRESS_POSITION.getStorageAddress(); } - /// @notice Sets the address of NFTDescriptor contract that is responsible for metadata generation. - /// @dev If NFTDescriptor address isn't set the `baseURI` would be used for generating erc721 metadata. In case - /// NFTDescriptor address is set it would be used as a priority method. + /// @notice Sets the address of NFTDescriptor contract that is responsible for tokenURI generation. + /// @dev If NFTDescriptor address isn't set the `baseURI` would be used for generating erc721 tokenURI. In case + /// NFTDescriptor address is set it would be used as a first-priority method. function setNFTDescriptorAddress(address _nftDescriptorAddress) external onlyRole(MANAGE_TOKEN_URI_ROLE) { NFT_DESCRIPTOR_ADDRESS_POSITION.setStorageAddress(_nftDescriptorAddress); emit NftDescriptorAddressSet(_nftDescriptorAddress);