Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
To
|
Amount
|
||
|---|---|---|---|---|---|---|---|
| On Validators Co... | 1498589 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1498581 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1498581 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1498581 | 83 days ago | 0 ETH | ||||
| Get Staking Rewa... | 1498581 | 83 days ago | 0 ETH | ||||
| Get Staking Rewa... | 1498581 | 83 days ago | 0 ETH | ||||
| On Validators Co... | 1498245 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1498240 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1498240 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1498240 | 83 days ago | 0 ETH | ||||
| Get Staking Rewa... | 1498240 | 83 days ago | 0 ETH | ||||
| Get Staking Rewa... | 1498240 | 83 days ago | 0 ETH | ||||
| On Validators Co... | 1497902 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1497895 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1497895 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1497895 | 83 days ago | 0 ETH | ||||
| Get Staking Rewa... | 1497895 | 83 days ago | 0 ETH | ||||
| Get Staking Rewa... | 1497895 | 83 days ago | 0 ETH | ||||
| On Validators Co... | 1497568 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1497561 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1497561 | 83 days ago | 0 ETH | ||||
| Get Staking Modu... | 1497561 | 83 days ago | 0 ETH | ||||
| Get Staking Rewa... | 1497561 | 83 days ago | 0 ETH | ||||
| Get Staking Rewa... | 1497561 | 83 days ago | 0 ETH | ||||
| On Validators Co... | 1497229 | 83 days ago | 0 ETH |
Loading...
Loading
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
StakingRouter
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 200 runs
Other Settings:
istanbul EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-FileCopyrightText: 2025 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 /* See contracts/COMPILERS.md */ pragma solidity 0.8.9; import {AccessControlEnumerable} from "./utils/access/AccessControlEnumerable.sol"; import {IStakingModule} from "./interfaces/IStakingModule.sol"; import {Math256} from "../common/lib/Math256.sol"; import {UnstructuredStorage} from "./lib/UnstructuredStorage.sol"; import {MinFirstAllocationStrategy} from "../common/lib/MinFirstAllocationStrategy.sol"; import {BeaconChainDepositor} from "./BeaconChainDepositor.sol"; import {Versioned} from "./utils/Versioned.sol"; contract StakingRouter is AccessControlEnumerable, BeaconChainDepositor, Versioned { using UnstructuredStorage for bytes32; /// @dev Events event StakingModuleAdded(uint256 indexed stakingModuleId, address stakingModule, string name, address createdBy); event StakingModuleShareLimitSet(uint256 indexed stakingModuleId, uint256 stakeShareLimit, uint256 priorityExitShareThreshold, address setBy); event StakingModuleFeesSet(uint256 indexed stakingModuleId, uint256 stakingModuleFee, uint256 treasuryFee, address setBy); event StakingModuleStatusSet(uint256 indexed stakingModuleId, StakingModuleStatus status, address setBy); event StakingModuleExitedValidatorsIncompleteReporting(uint256 indexed stakingModuleId, uint256 unreportedExitedValidatorsCount); event StakingModuleMaxDepositsPerBlockSet( uint256 indexed stakingModuleId, uint256 maxDepositsPerBlock, address setBy ); event StakingModuleMinDepositBlockDistanceSet( uint256 indexed stakingModuleId, uint256 minDepositBlockDistance, address setBy ); event WithdrawalCredentialsSet(bytes32 withdrawalCredentials, address setBy); event WithdrawalsCredentialsChangeFailed(uint256 indexed stakingModuleId, bytes lowLevelRevertData); event ExitedAndStuckValidatorsCountsUpdateFailed(uint256 indexed stakingModuleId, bytes lowLevelRevertData); event RewardsMintedReportFailed(uint256 indexed stakingModuleId, bytes lowLevelRevertData); /// Emitted when the StakingRouter received ETH event StakingRouterETHDeposited(uint256 indexed stakingModuleId, uint256 amount); event StakingModuleExitNotificationFailed( uint256 indexed stakingModuleId, uint256 indexed nodeOperatorId, bytes _publicKey ); /// @dev Errors error ZeroAddressLido(); error ZeroAddressAdmin(); error ZeroAddressStakingModule(); error InvalidStakeShareLimit(); error InvalidFeeSum(); error StakingModuleNotActive(); error EmptyWithdrawalsCredentials(); error DirectETHTransfer(); error InvalidReportData(uint256 code); error ExitedValidatorsCountCannotDecrease(); error ReportedExitedValidatorsExceedDeposited( uint256 reportedExitedValidatorsCount, uint256 depositedValidatorsCount ); error StakingModulesLimitExceeded(); error StakingModuleUnregistered(); error AppAuthLidoFailed(); error StakingModuleStatusTheSame(); error StakingModuleWrongName(); error UnexpectedCurrentValidatorsCount( uint256 currentModuleExitedValidatorsCount, uint256 currentNodeOpExitedValidatorsCount ); error UnexpectedFinalExitedValidatorsCount ( uint256 newModuleTotalExitedValidatorsCount, uint256 newModuleTotalExitedValidatorsCountInStakingRouter ); error InvalidDepositsValue(uint256 etherValue, uint256 depositsCount); error StakingModuleAddressExists(); error ArraysLengthMismatch(uint256 firstArrayLength, uint256 secondArrayLength); error UnrecoverableModuleError(); error InvalidPriorityExitShareThreshold(); error InvalidMinDepositBlockDistance(); error InvalidMaxDepositPerBlockValue(); enum StakingModuleStatus { Active, // deposits and rewards allowed DepositsPaused, // deposits NOT allowed, rewards allowed Stopped // deposits and rewards NOT allowed } struct StakingModule { /// @notice Unique id of the staking module. uint24 id; /// @notice Address of the staking module. address stakingModuleAddress; /// @notice Part of the fee taken from staking rewards that goes to the staking module. uint16 stakingModuleFee; /// @notice Part of the fee taken from staking rewards that goes to the treasury. uint16 treasuryFee; /// @notice Maximum stake share that can be allocated to a module, in BP. /// @dev Formerly known as `targetShare`. uint16 stakeShareLimit; /// @notice Staking module status if staking module can not accept the deposits or can /// participate in further reward distribution. uint8 status; /// @notice Name of the staking module. string name; /// @notice block.timestamp of the last deposit of the staking module. /// @dev NB: lastDepositAt gets updated even if the deposit value was 0 and no actual deposit happened. uint64 lastDepositAt; /// @notice block.number of the last deposit of the staking module. /// @dev NB: lastDepositBlock gets updated even if the deposit value was 0 and no actual deposit happened. uint256 lastDepositBlock; /// @notice Number of exited validators. uint256 exitedValidatorsCount; /// @notice Module's share threshold, upon crossing which, exits of validators from the module will be prioritized, in BP. uint16 priorityExitShareThreshold; /// @notice The maximum number of validators that can be deposited in a single block. /// @dev Must be harmonized with `OracleReportSanityChecker.appearedValidatorsPerDayLimit`. /// See docs for the `OracleReportSanityChecker.setAppearedValidatorsPerDayLimit` function. uint64 maxDepositsPerBlock; /// @notice The minimum distance between deposits in blocks. /// @dev Must be harmonized with `OracleReportSanityChecker.appearedValidatorsPerDayLimit`. /// See docs for the `OracleReportSanityChecker.setAppearedValidatorsPerDayLimit` function). uint64 minDepositBlockDistance; } struct StakingModuleCache { address stakingModuleAddress; uint24 stakingModuleId; uint16 stakingModuleFee; uint16 treasuryFee; uint16 stakeShareLimit; StakingModuleStatus status; uint256 activeValidatorsCount; uint256 availableValidatorsCount; } struct ValidatorExitData { uint256 stakingModuleId; uint256 nodeOperatorId; bytes pubkey; } bytes32 public constant MANAGE_WITHDRAWAL_CREDENTIALS_ROLE = keccak256("MANAGE_WITHDRAWAL_CREDENTIALS_ROLE"); bytes32 public constant STAKING_MODULE_MANAGE_ROLE = keccak256("STAKING_MODULE_MANAGE_ROLE"); bytes32 public constant STAKING_MODULE_UNVETTING_ROLE = keccak256("STAKING_MODULE_UNVETTING_ROLE"); bytes32 public constant REPORT_EXITED_VALIDATORS_ROLE = keccak256("REPORT_EXITED_VALIDATORS_ROLE"); bytes32 public constant REPORT_VALIDATOR_EXITING_STATUS_ROLE = keccak256("REPORT_VALIDATOR_EXITING_STATUS_ROLE"); bytes32 public constant REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE = keccak256("REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE"); bytes32 public constant UNSAFE_SET_EXITED_VALIDATORS_ROLE = keccak256("UNSAFE_SET_EXITED_VALIDATORS_ROLE"); bytes32 public constant REPORT_REWARDS_MINTED_ROLE = keccak256("REPORT_REWARDS_MINTED_ROLE"); bytes32 internal constant LIDO_POSITION = keccak256("lido.StakingRouter.lido"); /// @dev Credentials to withdraw ETH on Consensus Layer side. bytes32 internal constant WITHDRAWAL_CREDENTIALS_POSITION = keccak256("lido.StakingRouter.withdrawalCredentials"); /// @dev Total count of staking modules. bytes32 internal constant STAKING_MODULES_COUNT_POSITION = keccak256("lido.StakingRouter.stakingModulesCount"); /// @dev Id of the last added staking module. This counter grow on staking modules adding. bytes32 internal constant LAST_STAKING_MODULE_ID_POSITION = keccak256("lido.StakingRouter.lastStakingModuleId"); /// @dev Mapping is used instead of array to allow to extend the StakingModule. bytes32 internal constant STAKING_MODULES_MAPPING_POSITION = keccak256("lido.StakingRouter.stakingModules"); /// @dev Position of the staking modules in the `_stakingModules` map, plus 1 because /// index 0 means a value is not in the set. bytes32 internal constant STAKING_MODULE_INDICES_MAPPING_POSITION = keccak256("lido.StakingRouter.stakingModuleIndicesOneBased"); uint256 public constant FEE_PRECISION_POINTS = 10 ** 20; // 100 * 10 ** 18 uint256 public constant TOTAL_BASIS_POINTS = 10000; uint256 public constant MAX_STAKING_MODULES_COUNT = 32; /// @dev Restrict the name size with 31 bytes to storage in a single slot. uint256 public constant MAX_STAKING_MODULE_NAME_LENGTH = 31; constructor(address _depositContract) BeaconChainDepositor(_depositContract) {} /// @notice Initializes the contract. /// @param _admin Lido DAO Aragon agent contract address. /// @param _lido Lido address. /// @param _withdrawalCredentials Credentials to withdraw ETH on Consensus Layer side. /// @dev Proxy initialization method. function initialize(address _admin, address _lido, bytes32 _withdrawalCredentials) external { if (_admin == address(0)) revert ZeroAddressAdmin(); if (_lido == address(0)) revert ZeroAddressLido(); _initializeContractVersionTo(3); _setupRole(DEFAULT_ADMIN_ROLE, _admin); LIDO_POSITION.setStorageAddress(_lido); WITHDRAWAL_CREDENTIALS_POSITION.setStorageBytes32(_withdrawalCredentials); emit WithdrawalCredentialsSet(_withdrawalCredentials, msg.sender); } /// @dev Prohibit direct transfer to contract. receive() external payable { revert DirectETHTransfer(); } /// @notice A function to finalize upgrade to v2 (from v1). Removed and no longer used. /// @dev https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-10.md /// See historical usage in commit: https://github.com/lidofinance/core/blob/c19480aa3366b26aa6eac17f85a6efae8b9f4f72/contracts/0.8.9/StakingRouter.sol#L190 // function finalizeUpgrade_v2( // uint256[] memory _priorityExitShareThresholds, // uint256[] memory _maxDepositsPerBlock, // uint256[] memory _minDepositBlockDistances // ) external /// @notice Finalizes upgrade to v3 (from v2). Can be called only once. function finalizeUpgrade_v3() external { _checkContractVersion(2); _updateContractVersion(3); } /// @notice Returns Lido contract address. /// @return Lido contract address. function getLido() public view returns (address) { return LIDO_POSITION.getStorageAddress(); } /// @notice Registers a new staking module. /// @param _name Name of staking module. /// @param _stakingModuleAddress Address of staking module. /// @param _stakeShareLimit Maximum share that can be allocated to a module. /// @param _priorityExitShareThreshold Module's priority exit share threshold. /// @param _stakingModuleFee Fee of the staking module taken from the staking rewards. /// @param _treasuryFee Treasury fee. /// @param _maxDepositsPerBlock The maximum number of validators that can be deposited in a single block. /// @param _minDepositBlockDistance The minimum distance between deposits in blocks. /// @dev The function is restricted to the `STAKING_MODULE_MANAGE_ROLE` role. function addStakingModule( string calldata _name, address _stakingModuleAddress, uint256 _stakeShareLimit, uint256 _priorityExitShareThreshold, uint256 _stakingModuleFee, uint256 _treasuryFee, uint256 _maxDepositsPerBlock, uint256 _minDepositBlockDistance ) external onlyRole(STAKING_MODULE_MANAGE_ROLE) { if (_stakingModuleAddress == address(0)) revert ZeroAddressStakingModule(); if (bytes(_name).length == 0 || bytes(_name).length > MAX_STAKING_MODULE_NAME_LENGTH) revert StakingModuleWrongName(); uint256 newStakingModuleIndex = getStakingModulesCount(); if (newStakingModuleIndex >= MAX_STAKING_MODULES_COUNT) 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; newStakingModule.id = newStakingModuleId; newStakingModule.name = _name; newStakingModule.stakingModuleAddress = _stakingModuleAddress; /// @dev Since `enum` is `uint8` by nature, so the `status` is stored as `uint8` to avoid /// possible problems when upgrading. But for human readability, we use `enum` as /// function parameter type. More about conversion in the docs: /// https://docs.soliditylang.org/en/v0.8.17/types.html#enums newStakingModule.status = uint8(StakingModuleStatus.Active); /// @dev Simulate zero value deposit to prevent real deposits into the new StakingModule via /// DepositSecurityModule just after the addition. _updateModuleLastDepositState(newStakingModule, newStakingModuleId, 0); _setStakingModuleIndexById(newStakingModuleId, newStakingModuleIndex); LAST_STAKING_MODULE_ID_POSITION.setStorageUint256(newStakingModuleId); STAKING_MODULES_COUNT_POSITION.setStorageUint256(newStakingModuleIndex + 1); emit StakingModuleAdded(newStakingModuleId, _stakingModuleAddress, _name, msg.sender); _updateStakingModule( newStakingModule, newStakingModuleId, _stakeShareLimit, _priorityExitShareThreshold, _stakingModuleFee, _treasuryFee, _maxDepositsPerBlock, _minDepositBlockDistance ); } /// @notice Updates staking module params. /// @param _stakingModuleId Staking module id. /// @param _stakeShareLimit Target total stake share. /// @param _priorityExitShareThreshold Module's priority exit share threshold. /// @param _stakingModuleFee Fee of the staking module taken from the staking rewards. /// @param _treasuryFee Treasury fee. /// @param _maxDepositsPerBlock The maximum number of validators that can be deposited in a single block. /// @param _minDepositBlockDistance The minimum distance between deposits in blocks. /// @dev The function is restricted to the `STAKING_MODULE_MANAGE_ROLE` role. function updateStakingModule( uint256 _stakingModuleId, uint256 _stakeShareLimit, uint256 _priorityExitShareThreshold, uint256 _stakingModuleFee, uint256 _treasuryFee, uint256 _maxDepositsPerBlock, uint256 _minDepositBlockDistance ) external onlyRole(STAKING_MODULE_MANAGE_ROLE) { StakingModule storage stakingModule = _getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)); _updateStakingModule( stakingModule, _stakingModuleId, _stakeShareLimit, _priorityExitShareThreshold, _stakingModuleFee, _treasuryFee, _maxDepositsPerBlock, _minDepositBlockDistance ); } function _updateStakingModule( StakingModule storage stakingModule, uint256 _stakingModuleId, uint256 _stakeShareLimit, uint256 _priorityExitShareThreshold, uint256 _stakingModuleFee, uint256 _treasuryFee, uint256 _maxDepositsPerBlock, uint256 _minDepositBlockDistance ) internal { if (_stakeShareLimit > TOTAL_BASIS_POINTS) revert InvalidStakeShareLimit(); if (_priorityExitShareThreshold > TOTAL_BASIS_POINTS) revert InvalidPriorityExitShareThreshold(); if (_stakeShareLimit > _priorityExitShareThreshold) revert InvalidPriorityExitShareThreshold(); if (_stakingModuleFee + _treasuryFee > TOTAL_BASIS_POINTS) revert InvalidFeeSum(); if (_minDepositBlockDistance == 0 || _minDepositBlockDistance > type(uint64).max) revert InvalidMinDepositBlockDistance(); if (_maxDepositsPerBlock > type(uint64).max) revert InvalidMaxDepositPerBlockValue(); stakingModule.stakeShareLimit = uint16(_stakeShareLimit); stakingModule.priorityExitShareThreshold = uint16(_priorityExitShareThreshold); stakingModule.treasuryFee = uint16(_treasuryFee); stakingModule.stakingModuleFee = uint16(_stakingModuleFee); stakingModule.maxDepositsPerBlock = uint64(_maxDepositsPerBlock); stakingModule.minDepositBlockDistance = uint64(_minDepositBlockDistance); emit StakingModuleShareLimitSet(_stakingModuleId, _stakeShareLimit, _priorityExitShareThreshold, msg.sender); emit StakingModuleFeesSet(_stakingModuleId, _stakingModuleFee, _treasuryFee, msg.sender); emit StakingModuleMaxDepositsPerBlockSet(_stakingModuleId, _maxDepositsPerBlock, msg.sender); emit StakingModuleMinDepositBlockDistanceSet(_stakingModuleId, _minDepositBlockDistance, msg.sender); } /// @notice Updates the limit of the validators that can be used for deposit. /// @param _stakingModuleId Id of the staking module. /// @param _nodeOperatorId Id of the node operator. /// @param _targetLimitMode Target limit mode. /// @param _targetLimit Target limit of the node operator. /// @dev The function is restricted to the `STAKING_MODULE_MANAGE_ROLE` role. function updateTargetValidatorsLimits( uint256 _stakingModuleId, uint256 _nodeOperatorId, uint256 _targetLimitMode, uint256 _targetLimit ) external onlyRole(STAKING_MODULE_MANAGE_ROLE) { _getIStakingModuleById(_stakingModuleId).updateTargetValidatorsLimits( _nodeOperatorId, _targetLimitMode, _targetLimit ); } /// @notice Updates the number of the refunded validators in the staking module with the given /// node operator id. /// @param _stakingModuleId Id of the staking module. /// @param _nodeOperatorId Id of the node operator. /// @param _refundedValidatorsCount New number of refunded validators of the node operator. /// @dev The function is restricted to the `STAKING_MODULE_MANAGE_ROLE` role. function updateRefundedValidatorsCount( uint256 _stakingModuleId, uint256 _nodeOperatorId, uint256 _refundedValidatorsCount ) external onlyRole(STAKING_MODULE_MANAGE_ROLE) { _getIStakingModuleById(_stakingModuleId).updateRefundedValidatorsCount( _nodeOperatorId, _refundedValidatorsCount ); } /// @notice Reports the minted rewards to the staking modules with the specified ids. /// @param _stakingModuleIds Ids of the staking modules. /// @param _totalShares Total shares minted for the staking modules. /// @dev The function is restricted to the `REPORT_REWARDS_MINTED_ROLE` role. function reportRewardsMinted(uint256[] calldata _stakingModuleIds, uint256[] calldata _totalShares) external onlyRole(REPORT_REWARDS_MINTED_ROLE) { _validateEqualArrayLengths(_stakingModuleIds.length, _totalShares.length); for (uint256 i = 0; i < _stakingModuleIds.length; ) { if (_totalShares[i] > 0) { try _getIStakingModuleById(_stakingModuleIds[i]).onRewardsMinted(_totalShares[i]) {} catch (bytes memory lowLevelRevertData) { /// @dev This check is required to prevent incorrect gas estimation of the method. /// Without it, Ethereum nodes that use binary search for gas estimation may /// return an invalid value when the onRewardsMinted() reverts because of the /// "out of gas" error. Here we assume that the onRewardsMinted() method doesn't /// have reverts with empty error data except "out of gas". if (lowLevelRevertData.length == 0) revert UnrecoverableModuleError(); emit RewardsMintedReportFailed( _stakingModuleIds[i], lowLevelRevertData ); } } unchecked { ++i; } } } /// @notice Updates total numbers of exited validators for staking modules with the specified module ids. /// @param _stakingModuleIds Ids of the staking modules to be updated. /// @param _exitedValidatorsCounts New counts of exited validators for the specified staking modules. /// @return The total increase in the aggregate number of exited validators across all updated modules. /// /// @dev The total numbers are stored in the staking router and can differ from the totals obtained by calling /// `IStakingModule.getStakingModuleSummary()`. The overall process of updating validator counts is the following: /// /// 1. In the first data submission phase, the oracle calls `updateExitedValidatorsCountByStakingModule` on the /// staking router, passing the totals by module. The staking router stores these totals and uses them to /// distribute new stake and staking fees between the modules. There can only be single call of this function /// per oracle reporting frame. /// /// 2. In the second part of the second data submission phase, the oracle calls /// `StakingRouter.reportStakingModuleExitedValidatorsCountByNodeOperator` on the staking router which passes /// the counts by node operator to the staking module by calling `IStakingModule.updateExitedValidatorsCount`. /// This can be done multiple times for the same module, passing data for different subsets of node /// operators. /// /// 3. At the end of the second data submission phase, it's expected for the aggregate exited validators count /// across all module's node operators (stored in the module) to match the total count for this module /// (stored in the staking router). However, it might happen that the second phase of data submission doesn't /// finish until the new oracle reporting frame is started, in which case staking router will emit a warning /// event `StakingModuleExitedValidatorsIncompleteReporting` when the first data submission phase is performed /// for a new reporting frame. This condition will result in the staking module having an incomplete data about /// the exited validator counts during the whole reporting frame. Handling this condition is /// the responsibility of each staking module. /// /// 4. When the second reporting phase is finished, i.e. when the oracle submitted the complete data on the exited /// validator counts per node operator for the current reporting frame, the oracle calls /// `StakingRouter.onValidatorsCountsByNodeOperatorReportingFinished` which, in turn, calls /// `IStakingModule.onExitedAndStuckValidatorsCountsUpdated` on all modules. /// /// @dev The function is restricted to the `REPORT_EXITED_VALIDATORS_ROLE` role. function updateExitedValidatorsCountByStakingModule( uint256[] calldata _stakingModuleIds, uint256[] calldata _exitedValidatorsCounts ) external onlyRole(REPORT_EXITED_VALIDATORS_ROLE) returns (uint256) { _validateEqualArrayLengths(_stakingModuleIds.length, _exitedValidatorsCounts.length); uint256 newlyExitedValidatorsCount; for (uint256 i = 0; i < _stakingModuleIds.length; ) { uint256 stakingModuleId = _stakingModuleIds[i]; StakingModule storage stakingModule = _getStakingModuleByIndex(_getStakingModuleIndexById(stakingModuleId)); uint256 prevReportedExitedValidatorsCount = stakingModule.exitedValidatorsCount; if (_exitedValidatorsCounts[i] < prevReportedExitedValidatorsCount) { revert ExitedValidatorsCountCannotDecrease(); } ( uint256 totalExitedValidators, uint256 totalDepositedValidators, /* uint256 depositableValidatorsCount */ ) = _getStakingModuleSummary(IStakingModule(stakingModule.stakingModuleAddress)); if (_exitedValidatorsCounts[i] > totalDepositedValidators) { revert ReportedExitedValidatorsExceedDeposited( _exitedValidatorsCounts[i], totalDepositedValidators ); } newlyExitedValidatorsCount += _exitedValidatorsCounts[i] - prevReportedExitedValidatorsCount; if (totalExitedValidators < prevReportedExitedValidatorsCount) { // not all of the exited validators were async reported to the module emit StakingModuleExitedValidatorsIncompleteReporting( stakingModuleId, prevReportedExitedValidatorsCount - totalExitedValidators ); } stakingModule.exitedValidatorsCount = _exitedValidatorsCounts[i]; unchecked { ++i; } } return newlyExitedValidatorsCount; } /// @notice Updates exited validators counts per node operator for the staking module with /// the specified id. See the docs for `updateExitedValidatorsCountByStakingModule` for the /// description of the overall update process. /// /// @param _stakingModuleId The id of the staking modules to be updated. /// @param _nodeOperatorIds Ids of the node operators to be updated. /// @param _exitedValidatorsCounts New counts of exited validators for the specified node operators. /// /// @dev The function is restricted to the `REPORT_EXITED_VALIDATORS_ROLE` role. function reportStakingModuleExitedValidatorsCountByNodeOperator( uint256 _stakingModuleId, bytes calldata _nodeOperatorIds, bytes calldata _exitedValidatorsCounts ) external onlyRole(REPORT_EXITED_VALIDATORS_ROLE) { _checkValidatorsByNodeOperatorReportData(_nodeOperatorIds, _exitedValidatorsCounts); _getIStakingModuleById(_stakingModuleId).updateExitedValidatorsCount(_nodeOperatorIds, _exitedValidatorsCounts); } 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 corrected number of exited validators of the module. uint256 newModuleExitedValidatorsCount; /// @notice The corrected number of exited validators of the node operator. uint256 newNodeOperatorExitedValidatorsCount; } /// @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. /// /// @param _stakingModuleId Id of the staking module. /// @param _nodeOperatorId Id of the node operator. /// @param _triggerUpdateFinish Whether to call `onExitedAndStuckValidatorsCountsUpdated` on the module /// after applying the corrections. /// @param _correction See the docs for the `ValidatorsCountsCorrection` struct. /// /// @dev Reverts if the current numbers of exited validators of the module and node operator /// don't match the supplied expected current values. /// /// @dev The function is restricted to the `UNSAFE_SET_EXITED_VALIDATORS_ROLE` role. function unsafeSetExitedValidatorsCount( uint256 _stakingModuleId, uint256 _nodeOperatorId, bool _triggerUpdateFinish, ValidatorsCountsCorrection memory _correction ) external onlyRole(UNSAFE_SET_EXITED_VALIDATORS_ROLE) { StakingModule storage stakingModuleState = _getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)); IStakingModule stakingModule = IStakingModule(stakingModuleState.stakingModuleAddress); ( /* uint256 targetLimitMode */, /* uint256 targetValidatorsCount */, /* uint256 stuckValidatorsCount, */, /* uint256 refundedValidatorsCount */, /* uint256 stuckPenaltyEndTimestamp */, uint256 totalExitedValidators, /* uint256 totalDepositedValidators */, /* uint256 depositableValidatorsCount */ ) = stakingModule.getNodeOperatorSummary(_nodeOperatorId); if (_correction.currentModuleExitedValidatorsCount != stakingModuleState.exitedValidatorsCount || _correction.currentNodeOperatorExitedValidatorsCount != totalExitedValidators ) { revert UnexpectedCurrentValidatorsCount( stakingModuleState.exitedValidatorsCount, totalExitedValidators ); } stakingModuleState.exitedValidatorsCount = _correction.newModuleExitedValidatorsCount; stakingModule.unsafeUpdateValidatorsCount( _nodeOperatorId, _correction.newNodeOperatorExitedValidatorsCount ); ( uint256 moduleTotalExitedValidators, uint256 moduleTotalDepositedValidators, ) = _getStakingModuleSummary(stakingModule); if (_correction.newModuleExitedValidatorsCount > moduleTotalDepositedValidators) { revert ReportedExitedValidatorsExceedDeposited( _correction.newModuleExitedValidatorsCount, moduleTotalDepositedValidators ); } if (_triggerUpdateFinish) { if (moduleTotalExitedValidators != _correction.newModuleExitedValidatorsCount) { revert UnexpectedFinalExitedValidatorsCount( moduleTotalExitedValidators, _correction.newModuleExitedValidatorsCount ); } stakingModule.onExitedAndStuckValidatorsCountsUpdated(); } } /// @notice Finalizes the reporting of the exited validators counts for the current /// reporting frame. /// /// @dev Called by the oracle when the second phase of data reporting finishes, i.e. when the /// oracle submitted the complete data on the exited validator counts per node operator /// for the current reporting frame. See the docs for `updateExitedValidatorsCountByStakingModule` /// for the description of the overall update process. /// /// @dev The function is restricted to the `REPORT_EXITED_VALIDATORS_ROLE` role. function onValidatorsCountsByNodeOperatorReportingFinished() external onlyRole(REPORT_EXITED_VALIDATORS_ROLE) { uint256 stakingModulesCount = getStakingModulesCount(); StakingModule storage stakingModule; IStakingModule moduleContract; for (uint256 i; i < stakingModulesCount; ) { stakingModule = _getStakingModuleByIndex(i); moduleContract = IStakingModule(stakingModule.stakingModuleAddress); (uint256 exitedValidatorsCount, , ) = _getStakingModuleSummary(moduleContract); if (exitedValidatorsCount == stakingModule.exitedValidatorsCount) { // oracle finished updating exited validators for all node ops try moduleContract.onExitedAndStuckValidatorsCountsUpdated() {} catch (bytes memory lowLevelRevertData) { /// @dev This check is required to prevent incorrect gas estimation of the method. /// Without it, Ethereum nodes that use binary search for gas estimation may /// return an invalid value when the onExitedAndStuckValidatorsCountsUpdated() /// reverts because of the "out of gas" error. Here we assume that the /// onExitedAndStuckValidatorsCountsUpdated() method doesn't have reverts with /// empty error data except "out of gas". if (lowLevelRevertData.length == 0) revert UnrecoverableModuleError(); emit ExitedAndStuckValidatorsCountsUpdateFailed( stakingModule.id, lowLevelRevertData ); } } unchecked { ++i; } } } /// @notice Decreases vetted signing keys counts per node operator for the staking module with /// the specified id. /// @param _stakingModuleId The id of the staking module to be updated. /// @param _nodeOperatorIds Ids of the node operators to be updated. /// @param _vettedSigningKeysCounts New counts of vetted signing keys for the specified node operators. /// @dev The function is restricted to the `STAKING_MODULE_UNVETTING_ROLE` role. function decreaseStakingModuleVettedKeysCountByNodeOperator( uint256 _stakingModuleId, bytes calldata _nodeOperatorIds, bytes calldata _vettedSigningKeysCounts ) external onlyRole(STAKING_MODULE_UNVETTING_ROLE) { _checkValidatorsByNodeOperatorReportData(_nodeOperatorIds, _vettedSigningKeysCounts); _getIStakingModuleById(_stakingModuleId).decreaseVettedSigningKeysCount(_nodeOperatorIds, _vettedSigningKeysCounts); } /// @notice Returns all registered staking modules. /// @return res Array of staking modules. function getStakingModules() external view returns (StakingModule[] memory res) { uint256 stakingModulesCount = getStakingModulesCount(); res = new StakingModule[](stakingModulesCount); for (uint256 i; i < stakingModulesCount; ) { res[i] = _getStakingModuleByIndex(i); unchecked { ++i; } } } /// @notice Returns the ids of all registered staking modules. /// @return stakingModuleIds Array of staking module ids. function getStakingModuleIds() public view returns (uint256[] memory stakingModuleIds) { uint256 stakingModulesCount = getStakingModulesCount(); stakingModuleIds = new uint256[](stakingModulesCount); for (uint256 i; i < stakingModulesCount; ) { stakingModuleIds[i] = _getStakingModuleByIndex(i).id; unchecked { ++i; } } } /// @notice Returns the staking module by its id. /// @param _stakingModuleId Id of the staking module. /// @return Staking module data. function getStakingModule(uint256 _stakingModuleId) public view returns (StakingModule memory) { return _getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)); } /// @notice Returns total number of staking modules. /// @return Total number of staking modules. function getStakingModulesCount() public view returns (uint256) { return STAKING_MODULES_COUNT_POSITION.getStorageUint256(); } /// @notice Returns true if staking module with the given id was registered via `addStakingModule`, false otherwise. /// @param _stakingModuleId Id of the staking module. /// @return True if staking module with the given id was registered, false otherwise. function hasStakingModule(uint256 _stakingModuleId) external view returns (bool) { return _getStorageStakingIndicesMapping()[_stakingModuleId] != 0; } /// @notice Returns status of staking module. /// @param _stakingModuleId Id of the staking module. /// @return Status of the staking module. function getStakingModuleStatus(uint256 _stakingModuleId) public view returns (StakingModuleStatus) { return StakingModuleStatus(_getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)).status); } /// @notice A summary of the staking module's validators. struct StakingModuleSummary { /// @notice The total number of validators in the EXITED state on the Consensus Layer. /// @dev This value can't decrease in normal conditions. uint256 totalExitedValidators; /// @notice The total number of validators deposited via the official Deposit Contract. /// @dev This value is a cumulative counter: even when the validator goes into EXITED state this /// counter is not decreasing. uint256 totalDepositedValidators; /// @notice The number of validators in the set available for deposit uint256 depositableValidatorsCount; } /// @notice A summary of node operator and its validators. struct NodeOperatorSummary { /// @notice Shows whether the current target limit applied to the node operator. uint256 targetLimitMode; /// @notice Relative target active validators limit for operator. uint256 targetValidatorsCount; /// @notice The number of validators with an expired request to exit time. /// @dev [deprecated] Stuck key processing has been removed, this field is no longer used. uint256 stuckValidatorsCount; /// @notice The number of validators that can't be withdrawn, but deposit costs were /// compensated to the Lido by the node operator. uint256 refundedValidatorsCount; /// @notice A time when the penalty for stuck validators stops applying to node operator rewards. /// @dev [deprecated] Stuck key processing has been removed, this field is no longer used. uint256 stuckPenaltyEndTimestamp; /// @notice The total number of validators in the EXITED state on the Consensus Layer. /// @dev This value can't decrease in normal conditions. uint256 totalExitedValidators; /// @notice The total number of validators deposited via the official Deposit Contract. /// @dev This value is a cumulative counter: even when the validator goes into EXITED state this /// counter is not decreasing. uint256 totalDepositedValidators; /// @notice The number of validators in the set available for deposit. uint256 depositableValidatorsCount; } /// @notice Returns all-validators summary in the staking module. /// @param _stakingModuleId Id of the staking module to return summary for. /// @return summary Staking module summary. function getStakingModuleSummary(uint256 _stakingModuleId) public view returns (StakingModuleSummary memory summary) { IStakingModule stakingModule = IStakingModule(getStakingModule(_stakingModuleId).stakingModuleAddress); ( summary.totalExitedValidators, summary.totalDepositedValidators, summary.depositableValidatorsCount ) = _getStakingModuleSummary(stakingModule); } /// @notice Returns node operator summary from the staking module. /// @param _stakingModuleId Id of the staking module where node operator is onboarded. /// @param _nodeOperatorId Id of the node operator to return summary for. /// @return summary Node operator summary. function getNodeOperatorSummary(uint256 _stakingModuleId, uint256 _nodeOperatorId) public view returns (NodeOperatorSummary memory summary) { IStakingModule stakingModule = IStakingModule(getStakingModule(_stakingModuleId).stakingModuleAddress); /// @dev using intermediate variables below due to "Stack too deep" error in case of /// assigning directly into the NodeOperatorSummary struct ( uint256 targetLimitMode, uint256 targetValidatorsCount, /* uint256 stuckValidatorsCount */, uint256 refundedValidatorsCount, /* uint256 stuckPenaltyEndTimestamp */, uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount ) = stakingModule.getNodeOperatorSummary(_nodeOperatorId); summary.targetLimitMode = targetLimitMode; summary.targetValidatorsCount = targetValidatorsCount; summary.refundedValidatorsCount = refundedValidatorsCount; summary.totalExitedValidators = totalExitedValidators; summary.totalDepositedValidators = totalDepositedValidators; summary.depositableValidatorsCount = depositableValidatorsCount; } /// @notice A collection of the staking module data stored across the StakingRouter and the /// staking module contract. /// /// @dev This data, first of all, is designed for off-chain usage and might be redundant for /// on-chain calls. Give preference for dedicated methods for gas-efficient on-chain calls. struct StakingModuleDigest { /// @notice The number of node operators registered in the staking module. uint256 nodeOperatorsCount; /// @notice The number of node operators registered in the staking module in active state. uint256 activeNodeOperatorsCount; /// @notice The current state of the staking module taken from the StakingRouter. StakingModule state; /// @notice A summary of the staking module's validators. StakingModuleSummary summary; } /// @notice A collection of the node operator data stored in the staking module. /// @dev This data, first of all, is designed for off-chain usage and might be redundant for /// on-chain calls. Give preference for dedicated methods for gas-efficient on-chain calls. struct NodeOperatorDigest { /// @notice Id of the node operator. uint256 id; /// @notice Shows whether the node operator is active or not. bool isActive; /// @notice A summary of node operator and its validators. NodeOperatorSummary summary; } /// @notice Returns staking module digest for each staking module registered in the staking router. /// @return Array of staking module digests. /// @dev WARNING: This method is not supposed to be used for onchain calls due to high gas costs /// for data aggregation. function getAllStakingModuleDigests() external view returns (StakingModuleDigest[] memory) { return getStakingModuleDigests(getStakingModuleIds()); } /// @notice Returns staking module digest for passed staking module ids. /// @param _stakingModuleIds Ids of the staking modules to return data for. /// @return digests Array of staking module digests. /// @dev WARNING: This method is not supposed to be used for onchain calls due to high gas costs /// for data aggregation. function getStakingModuleDigests(uint256[] memory _stakingModuleIds) public view returns (StakingModuleDigest[] memory digests) { digests = new StakingModuleDigest[](_stakingModuleIds.length); for (uint256 i = 0; i < _stakingModuleIds.length; ) { StakingModule memory stakingModuleState = getStakingModule(_stakingModuleIds[i]); IStakingModule stakingModule = IStakingModule(stakingModuleState.stakingModuleAddress); digests[i] = StakingModuleDigest({ nodeOperatorsCount: stakingModule.getNodeOperatorsCount(), activeNodeOperatorsCount: stakingModule.getActiveNodeOperatorsCount(), state: stakingModuleState, summary: getStakingModuleSummary(_stakingModuleIds[i]) }); unchecked { ++i; } } } /// @notice Returns node operator digest for each node operator registered in the given staking module. /// @param _stakingModuleId Id of the staking module to return data for. /// @return Array of node operator digests. /// @dev WARNING: This method is not supposed to be used for onchain calls due to high gas costs /// for data aggregation. function getAllNodeOperatorDigests(uint256 _stakingModuleId) external view returns (NodeOperatorDigest[] memory) { return getNodeOperatorDigests( _stakingModuleId, 0, _getIStakingModuleById(_stakingModuleId).getNodeOperatorsCount() ); } /// @notice Returns node operator digest for passed node operator ids in the given staking module. /// @param _stakingModuleId Id of the staking module where node operators registered. /// @param _offset Node operators offset starting with 0. /// @param _limit The max number of node operators to return. /// @return Array of node operator digests. /// @dev WARNING: This method is not supposed to be used for onchain calls due to high gas costs /// for data aggregation. function getNodeOperatorDigests( uint256 _stakingModuleId, uint256 _offset, uint256 _limit ) public view returns (NodeOperatorDigest[] memory) { return getNodeOperatorDigests( _stakingModuleId, _getIStakingModuleById(_stakingModuleId).getNodeOperatorIds(_offset, _limit) ); } /// @notice Returns node operator digest for a slice of node operators registered in the given /// staking module. /// @param _stakingModuleId Id of the staking module where node operators registered. /// @param _nodeOperatorIds Ids of the node operators to return data for. /// @return digests Array of node operator digests. /// @dev WARNING: This method is not supposed to be used for onchain calls due to high gas costs /// for data aggregation. function getNodeOperatorDigests(uint256 _stakingModuleId, uint256[] memory _nodeOperatorIds) public view returns (NodeOperatorDigest[] memory digests) { IStakingModule stakingModule = _getIStakingModuleById(_stakingModuleId); digests = new NodeOperatorDigest[](_nodeOperatorIds.length); for (uint256 i = 0; i < _nodeOperatorIds.length; ) { digests[i] = NodeOperatorDigest({ id: _nodeOperatorIds[i], isActive: stakingModule.getNodeOperatorIsActive(_nodeOperatorIds[i]), summary: getNodeOperatorSummary(_stakingModuleId, _nodeOperatorIds[i]) }); unchecked { ++i; } } } /// @notice Sets the staking module status flag for participation in further deposits and/or reward distribution. /// @param _stakingModuleId Id of the staking module to be updated. /// @param _status New status of the staking module. /// @dev The function is restricted to the `STAKING_MODULE_MANAGE_ROLE` role. function setStakingModuleStatus( uint256 _stakingModuleId, StakingModuleStatus _status ) external onlyRole(STAKING_MODULE_MANAGE_ROLE) { StakingModule storage stakingModule = _getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)); if (StakingModuleStatus(stakingModule.status) == _status) revert StakingModuleStatusTheSame(); _setStakingModuleStatus(stakingModule, _status); } /// @notice Returns whether the staking module is stopped. /// @param _stakingModuleId Id of the staking module. /// @return True if the staking module is stopped, false otherwise. function getStakingModuleIsStopped(uint256 _stakingModuleId) external view returns (bool) { return getStakingModuleStatus(_stakingModuleId) == StakingModuleStatus.Stopped; } /// @notice Returns whether the deposits are paused for the staking module. /// @param _stakingModuleId Id of the staking module. /// @return True if the deposits are paused, false otherwise. function getStakingModuleIsDepositsPaused(uint256 _stakingModuleId) external view returns (bool) { return getStakingModuleStatus(_stakingModuleId) == StakingModuleStatus.DepositsPaused; } /// @notice Returns whether the staking module is active. /// @param _stakingModuleId Id of the staking module. /// @return True if the staking module is active, false otherwise. function getStakingModuleIsActive(uint256 _stakingModuleId) external view returns (bool) { return getStakingModuleStatus(_stakingModuleId) == StakingModuleStatus.Active; } /// @notice Returns staking module nonce. /// @param _stakingModuleId Id of the staking module. /// @return Staking module nonce. function getStakingModuleNonce(uint256 _stakingModuleId) external view returns (uint256) { return _getIStakingModuleById(_stakingModuleId).getNonce(); } /// @notice Returns the last deposit block for the staking module. /// @param _stakingModuleId Id of the staking module. /// @return Last deposit block for the staking module. function getStakingModuleLastDepositBlock(uint256 _stakingModuleId) external view returns (uint256) { return _getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)).lastDepositBlock; } /// @notice Returns the min deposit block distance for the staking module. /// @param _stakingModuleId Id of the staking module. /// @return Min deposit block distance for the staking module. function getStakingModuleMinDepositBlockDistance(uint256 _stakingModuleId) external view returns (uint256) { return _getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)).minDepositBlockDistance; } /// @notice Returns the max deposits count per block for the staking module. /// @param _stakingModuleId Id of the staking module. /// @return Max deposits count per block for the staking module. function getStakingModuleMaxDepositsPerBlock(uint256 _stakingModuleId) external view returns (uint256) { return _getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)).maxDepositsPerBlock; } /// @notice Returns active validators count for the staking module. /// @param _stakingModuleId Id of the staking module. /// @return activeValidatorsCount Active validators count for the staking module. function getStakingModuleActiveValidatorsCount(uint256 _stakingModuleId) external view returns (uint256 activeValidatorsCount) { StakingModule storage stakingModule = _getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)); ( uint256 totalExitedValidators, uint256 totalDepositedValidators, /* uint256 depositableValidatorsCount */ ) = _getStakingModuleSummary(IStakingModule(stakingModule.stakingModuleAddress)); activeValidatorsCount = totalDepositedValidators - Math256.max( stakingModule.exitedValidatorsCount, totalExitedValidators ); } /// @notice Returns 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 returns (uint256) { ( /* uint256 allocated */, uint256[] memory newDepositsAllocation, StakingModuleCache[] memory stakingModulesCache ) = _getDepositsAllocation(_maxDepositsValue / DEPOSIT_SIZE); uint256 stakingModuleIndex = _getStakingModuleIndexById(_stakingModuleId); return newDepositsAllocation[stakingModuleIndex] - stakingModulesCache[stakingModuleIndex].activeValidatorsCount; } /// @notice Returns the aggregate fee distribution proportion. /// @return modulesFee Modules aggregate fee in base precision. /// @return treasuryFee Treasury fee in base precision. /// @return basePrecision Base precision: a value corresponding to the full fee. function getStakingFeeAggregateDistribution() public view returns ( uint96 modulesFee, uint96 treasuryFee, uint256 basePrecision ) { uint96[] memory moduleFees; uint96 totalFee; (, , moduleFees, totalFee, basePrecision) = getStakingRewardsDistribution(); for (uint256 i; i < moduleFees.length; ) { modulesFee += moduleFees[i]; unchecked { ++i; } } treasuryFee = totalFee - modulesFee; } /// @notice Return shares table. /// @return recipients Rewards recipient addresses corresponding to each module. /// @return stakingModuleIds Module IDs. /// @return stakingModuleFees Fee of each recipient. /// @return totalFee Total fee to mint for each staking module and treasury. /// @return precisionPoints Base precision number, which constitutes 100% fee. function getStakingRewardsDistribution() public view returns ( address[] memory recipients, uint256[] memory stakingModuleIds, uint96[] memory stakingModuleFees, uint96 totalFee, uint256 precisionPoints ) { (uint256 totalActiveValidators, StakingModuleCache[] memory stakingModulesCache) = _loadStakingModulesCache(); uint256 stakingModulesCount = stakingModulesCache.length; /// @dev Return empty response if there are no staking modules or active validators yet. if (stakingModulesCount == 0 || totalActiveValidators == 0) { return (new address[](0), new uint256[](0), new uint96[](0), 0, FEE_PRECISION_POINTS); } precisionPoints = FEE_PRECISION_POINTS; stakingModuleIds = new uint256[](stakingModulesCount); recipients = new address[](stakingModulesCount); stakingModuleFees = new uint96[](stakingModulesCount); uint256 rewardedStakingModulesCount = 0; uint256 stakingModuleValidatorsShare; uint96 stakingModuleFee; for (uint256 i; i < stakingModulesCount; ) { /// @dev Skip staking modules which have no active validators. if (stakingModulesCache[i].activeValidatorsCount > 0) { stakingModuleIds[rewardedStakingModulesCount] = stakingModulesCache[i].stakingModuleId; stakingModuleValidatorsShare = ((stakingModulesCache[i].activeValidatorsCount * precisionPoints) / totalActiveValidators); recipients[rewardedStakingModulesCount] = address(stakingModulesCache[i].stakingModuleAddress); stakingModuleFee = uint96((stakingModuleValidatorsShare * stakingModulesCache[i].stakingModuleFee) / TOTAL_BASIS_POINTS); /// @dev If the staking module has the `Stopped` status for some reason, then /// the staking module's rewards go to the treasury, so that the DAO has ability /// to manage them (e.g. to compensate the staking module in case of an error, etc.) if (stakingModulesCache[i].status != StakingModuleStatus.Stopped) { stakingModuleFees[rewardedStakingModulesCount] = stakingModuleFee; } // Else keep stakingModuleFees[rewardedStakingModulesCount] = 0, but increase totalFee. totalFee += (uint96((stakingModuleValidatorsShare * stakingModulesCache[i].treasuryFee) / TOTAL_BASIS_POINTS) + stakingModuleFee); unchecked { rewardedStakingModulesCount++; } } unchecked { ++i; } } // Total fee never exceeds 100%. assert(totalFee <= precisionPoints); /// @dev Shrink arrays. if (rewardedStakingModulesCount < stakingModulesCount) { assembly { mstore(stakingModuleIds, rewardedStakingModulesCount) mstore(recipients, rewardedStakingModulesCount) mstore(stakingModuleFees, rewardedStakingModulesCount) } } } /// @notice Returns the same as getStakingRewardsDistribution() but in reduced, 1e4 precision (DEPRECATED). /// @dev Helper only for Lido contract. Use getStakingRewardsDistribution() instead. /// @return totalFee Total fee to mint for each staking module and treasury in reduced, 1e4 precision. function getTotalFeeE4Precision() external view returns (uint16 totalFee) { /// @dev The logic is placed here but in Lido contract to save Lido bytecode. (, , , uint96 totalFeeInHighPrecision, uint256 precision) = getStakingRewardsDistribution(); // Here we rely on (totalFeeInHighPrecision <= precision). totalFee = _toE4Precision(totalFeeInHighPrecision, precision); } /// @notice Returns the same as getStakingFeeAggregateDistribution() but in reduced, 1e4 precision (DEPRECATED). /// @dev Helper only for Lido contract. Use getStakingFeeAggregateDistribution() instead. /// @return modulesFee Modules aggregate fee in reduced, 1e4 precision. /// @return treasuryFee Treasury fee in reduced, 1e4 precision. function getStakingFeeAggregateDistributionE4Precision() external view returns (uint16 modulesFee, uint16 treasuryFee) { /// @dev The logic is placed here but in Lido contract to save Lido bytecode. ( uint256 modulesFeeHighPrecision, uint256 treasuryFeeHighPrecision, uint256 precision ) = getStakingFeeAggregateDistribution(); // Here we rely on ({modules,treasury}FeeHighPrecision <= precision). modulesFee = _toE4Precision(modulesFeeHighPrecision, precision); treasuryFee = _toE4Precision(treasuryFeeHighPrecision, precision); } /// @notice Returns new deposits allocation after the distribution of the `_depositsCount` deposits. /// @param _depositsCount The maximum number of deposits to be allocated. /// @return allocated Number of deposits allocated to the staking modules. /// @return allocations Array of new deposits allocation to the staking modules. function getDepositsAllocation(uint256 _depositsCount) external view returns (uint256 allocated, uint256[] memory allocations) { (allocated, allocations, ) = _getDepositsAllocation(_depositsCount); } /// @notice Invokes a deposit call to the official Deposit contract. /// @param _depositsCount Number of deposits to make. /// @param _stakingModuleId Id of the staking module to be deposited. /// @param _depositCalldata Staking module calldata. /// @dev Only the Lido contract is allowed to call this method. function deposit( uint256 _depositsCount, uint256 _stakingModuleId, bytes calldata _depositCalldata ) external payable { if (msg.sender != LIDO_POSITION.getStorageAddress()) revert AppAuthLidoFailed(); bytes32 withdrawalCredentials = getWithdrawalCredentials(); if (withdrawalCredentials == 0) revert EmptyWithdrawalsCredentials(); StakingModule storage stakingModule = _getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)); if (StakingModuleStatus(stakingModule.status) != StakingModuleStatus.Active) revert StakingModuleNotActive(); /// @dev Firstly update the local state of the contract to prevent a reentrancy attack /// even though the staking modules are trusted contracts. uint256 depositsValue = msg.value; if (depositsValue != _depositsCount * DEPOSIT_SIZE) revert InvalidDepositsValue(depositsValue, _depositsCount); _updateModuleLastDepositState(stakingModule, _stakingModuleId, depositsValue); if (_depositsCount > 0) { (bytes memory publicKeysBatch, bytes memory signaturesBatch) = IStakingModule(stakingModule.stakingModuleAddress) .obtainDepositData(_depositsCount, _depositCalldata); uint256 etherBalanceBeforeDeposits = address(this).balance; _makeBeaconChainDeposits32ETH( _depositsCount, abi.encodePacked(withdrawalCredentials), publicKeysBatch, signaturesBatch ); uint256 etherBalanceAfterDeposits = address(this).balance; /// @dev All sent ETH must be deposited and self balance stay the same. assert(etherBalanceBeforeDeposits - etherBalanceAfterDeposits == depositsValue); } } /// @notice Set credentials to withdraw ETH on Consensus Layer side. /// @param _withdrawalCredentials withdrawal credentials field as defined in the Consensus Layer specs. /// @dev Note that setWithdrawalCredentials discards all unused deposits data as the signatures are invalidated. /// @dev The function is restricted to the `MANAGE_WITHDRAWAL_CREDENTIALS_ROLE` role. function setWithdrawalCredentials(bytes32 _withdrawalCredentials) external onlyRole(MANAGE_WITHDRAWAL_CREDENTIALS_ROLE) { WITHDRAWAL_CREDENTIALS_POSITION.setStorageBytes32(_withdrawalCredentials); uint256 stakingModulesCount = getStakingModulesCount(); for (uint256 i; i < stakingModulesCount; ) { StakingModule storage stakingModule = _getStakingModuleByIndex(i); unchecked { ++i; } try IStakingModule(stakingModule.stakingModuleAddress) .onWithdrawalCredentialsChanged() {} catch (bytes memory lowLevelRevertData) { /// @dev This check is required to prevent incorrect gas estimation of the method. /// Without it, Ethereum nodes that use binary search for gas estimation may /// return an invalid value when the onWithdrawalCredentialsChanged() /// reverts because of the "out of gas" error. Here we assume that the /// onWithdrawalCredentialsChanged() method doesn't have reverts with /// empty error data except "out of gas". if (lowLevelRevertData.length == 0) revert UnrecoverableModuleError(); _setStakingModuleStatus(stakingModule, StakingModuleStatus.DepositsPaused); emit WithdrawalsCredentialsChangeFailed(stakingModule.id, lowLevelRevertData); } } emit WithdrawalCredentialsSet(_withdrawalCredentials, msg.sender); } /// @notice Returns current credentials to withdraw ETH on Consensus Layer side. /// @return Withdrawal credentials. function getWithdrawalCredentials() public view returns (bytes32) { return WITHDRAWAL_CREDENTIALS_POSITION.getStorageBytes32(); } function _checkValidatorsByNodeOperatorReportData( bytes calldata _nodeOperatorIds, bytes calldata _validatorsCounts ) internal pure { 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 Save the last deposit state for the staking module and emit the event /// @param stakingModule staking module storage ref /// @param stakingModuleId id of the staking module to be deposited /// @param depositsValue value to deposit function _updateModuleLastDepositState( StakingModule storage stakingModule, uint256 stakingModuleId, uint256 depositsValue ) internal { stakingModule.lastDepositAt = uint64(block.timestamp); stakingModule.lastDepositBlock = block.number; emit StakingRouterETHDeposited(stakingModuleId, depositsValue); } /// @dev Loads modules into a memory cache. /// @return totalActiveValidators Total active validators across all modules. /// @return stakingModulesCache Array of StakingModuleCache structs. function _loadStakingModulesCache() internal view returns ( uint256 totalActiveValidators, StakingModuleCache[] memory stakingModulesCache ) { uint256 stakingModulesCount = getStakingModulesCount(); stakingModulesCache = new StakingModuleCache[](stakingModulesCount); for (uint256 i; i < stakingModulesCount; ) { stakingModulesCache[i] = _loadStakingModulesCacheItem(i); totalActiveValidators += stakingModulesCache[i].activeValidatorsCount; unchecked { ++i; } } } function _loadStakingModulesCacheItem(uint256 _stakingModuleIndex) internal view returns (StakingModuleCache memory cacheItem) { StakingModule storage stakingModuleData = _getStakingModuleByIndex(_stakingModuleIndex); cacheItem.stakingModuleAddress = stakingModuleData.stakingModuleAddress; cacheItem.stakingModuleId = stakingModuleData.id; cacheItem.stakingModuleFee = stakingModuleData.stakingModuleFee; cacheItem.treasuryFee = stakingModuleData.treasuryFee; cacheItem.stakeShareLimit = stakingModuleData.stakeShareLimit; cacheItem.status = StakingModuleStatus(stakingModuleData.status); ( uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount ) = _getStakingModuleSummary(IStakingModule(cacheItem.stakingModuleAddress)); cacheItem.availableValidatorsCount = cacheItem.status == StakingModuleStatus.Active ? depositableValidatorsCount : 0; // The module might not receive all exited validators data yet => we need to replacing // the exitedValidatorsCount with the one that the staking router is aware of. cacheItem.activeValidatorsCount = totalDepositedValidators - Math256.max(totalExitedValidators, stakingModuleData.exitedValidatorsCount); } function _setStakingModuleStatus(StakingModule storage _stakingModule, StakingModuleStatus _status) internal { StakingModuleStatus prevStatus = StakingModuleStatus(_stakingModule.status); if (prevStatus != _status) { _stakingModule.status = uint8(_status); emit StakingModuleStatusSet(_stakingModule.id, _status, msg.sender); } } function _getDepositsAllocation( uint256 _depositsToAllocate ) internal view returns (uint256 allocated, uint256[] memory allocations, StakingModuleCache[] memory stakingModulesCache) { // Calculate total used validators for operators. uint256 totalActiveValidators; (totalActiveValidators, stakingModulesCache) = _loadStakingModulesCache(); uint256 stakingModulesCount = stakingModulesCache.length; allocations = new uint256[](stakingModulesCount); if (stakingModulesCount > 0) { /// @dev New estimated active validators count. totalActiveValidators += _depositsToAllocate; uint256[] memory capacities = new uint256[](stakingModulesCount); uint256 targetValidators; for (uint256 i; i < stakingModulesCount; ) { allocations[i] = stakingModulesCache[i].activeValidatorsCount; targetValidators = (stakingModulesCache[i].stakeShareLimit * totalActiveValidators) / TOTAL_BASIS_POINTS; capacities[i] = Math256.min(targetValidators, stakingModulesCache[i].activeValidatorsCount + stakingModulesCache[i].availableValidatorsCount); unchecked { ++i; } } (allocated, allocations) = MinFirstAllocationStrategy.allocate(allocations, capacities, _depositsToAllocate); } } function _getStakingModuleIndexById(uint256 _stakingModuleId) internal view returns (uint256) { mapping(uint256 => uint256) storage _stakingModuleIndicesOneBased = _getStorageStakingIndicesMapping(); uint256 indexOneBased = _stakingModuleIndicesOneBased[_stakingModuleId]; if (indexOneBased == 0) revert StakingModuleUnregistered(); return indexOneBased - 1; } function _setStakingModuleIndexById(uint256 _stakingModuleId, uint256 _stakingModuleIndex) internal { mapping(uint256 => uint256) storage _stakingModuleIndicesOneBased = _getStorageStakingIndicesMapping(); _stakingModuleIndicesOneBased[_stakingModuleId] = _stakingModuleIndex + 1; } function _getIStakingModuleById(uint256 _stakingModuleId) internal view returns (IStakingModule) { return IStakingModule(_getStakingModuleAddressById(_stakingModuleId)); } function _getStakingModuleByIndex(uint256 _stakingModuleIndex) internal view returns (StakingModule storage) { mapping(uint256 => StakingModule) storage _stakingModules = _getStorageStakingModulesMapping(); return _stakingModules[_stakingModuleIndex]; } function _getStakingModuleAddressById(uint256 _stakingModuleId) internal view returns (address) { return _getStakingModuleByIndex(_getStakingModuleIndexById(_stakingModuleId)).stakingModuleAddress; } function _getStorageStakingModulesMapping() internal pure returns (mapping(uint256 => StakingModule) storage result) { bytes32 position = STAKING_MODULES_MAPPING_POSITION; assembly { result.slot := position } } function _getStorageStakingIndicesMapping() internal pure returns (mapping(uint256 => uint256) storage result) { bytes32 position = STAKING_MODULE_INDICES_MAPPING_POSITION; assembly { result.slot := position } } function _toE4Precision(uint256 _value, uint256 _precision) internal pure returns (uint16) { return uint16((_value * TOTAL_BASIS_POINTS) / _precision); } function _validateEqualArrayLengths(uint256 firstArrayLength, uint256 secondArrayLength) internal pure { if (firstArrayLength != secondArrayLength) { revert ArraysLengthMismatch(firstArrayLength, secondArrayLength); } } /// @dev Optimizes contract deployment size by wrapping the 'stakingModule.getStakingModuleSummary' function. function _getStakingModuleSummary(IStakingModule stakingModule) internal view returns (uint256, uint256, uint256) { return stakingModule.getStakingModuleSummary(); } /// @notice Handles tracking and penalization logic for a node operator who failed to exit their validator within the defined exit window. /// @dev This function is called to report the current exit-related status of a validator belonging to a specific node operator. /// It accepts a validator's public key, associated with the duration (in seconds) it was eligible to exit but has not exited. /// This data could be used to trigger penalties for the node operator if the validator has been non-exiting for too long. /// @param _stakingModuleId The ID of the staking module. /// @param _nodeOperatorId The ID of the node operator whose validator status is being delivered. /// @param _proofSlotTimestamp The timestamp (slot time) when the validator was last known to be in an active ongoing state. /// @param _publicKey The public key of the validator being reported. /// @param _eligibleToExitInSec The duration (in seconds) indicating how long the validator has been eligible to exit after request but has not exited. function reportValidatorExitDelay( uint256 _stakingModuleId, uint256 _nodeOperatorId, uint256 _proofSlotTimestamp, bytes calldata _publicKey, uint256 _eligibleToExitInSec ) external onlyRole(REPORT_VALIDATOR_EXITING_STATUS_ROLE) { _getIStakingModuleById(_stakingModuleId).reportValidatorExitDelay( _nodeOperatorId, _proofSlotTimestamp, _publicKey, _eligibleToExitInSec ); } /// @notice Handles the triggerable exit event for a set of validators. /// @dev This function is called when validators are exited using triggerable exit requests on the Execution Layer. /// @param validatorExitData An array of `ValidatorExitData` structs, each representing a validator /// for which a triggerable exit was requested. Each entry includes: /// - `stakingModuleId`: ID of the staking module. /// - `nodeOperatorId`: ID of the node operator. /// - `pubkey`: Validator public key, 48 bytes length. /// @param _withdrawalRequestPaidFee Fee amount paid to send a withdrawal request on the Execution Layer (EL). /// @param _exitType The type of exit being performed. /// This parameter may be interpreted differently across various staking modules depending on their specific implementation. function onValidatorExitTriggered( ValidatorExitData[] calldata validatorExitData, uint256 _withdrawalRequestPaidFee, uint256 _exitType ) external onlyRole(REPORT_VALIDATOR_EXIT_TRIGGERED_ROLE) { ValidatorExitData calldata data; for (uint256 i = 0; i < validatorExitData.length; ++i) { data = validatorExitData[i]; try _getIStakingModuleById(data.stakingModuleId).onValidatorExitTriggered( data.nodeOperatorId, data.pubkey, _withdrawalRequestPaidFee, _exitType ) {} catch (bytes memory lowLevelRevertData) { /// @dev This check is required to prevent incorrect gas estimation of the method. /// Without it, Ethereum nodes that use binary search for gas estimation may /// return an invalid value when the onValidatorExitTriggered() /// reverts because of the "out of gas" error. Here we assume that the /// onValidatorExitTriggered() method doesn't have reverts with /// empty error data except "out of gas". if (lowLevelRevertData.length == 0) revert UnrecoverableModuleError(); emit StakingModuleExitNotificationFailed(data.stakingModuleId, data.nodeOperatorId, data.pubkey); } } } }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* 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 _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* 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 values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* 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 values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* 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 values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 // See contracts/COMPILERS.md pragma solidity 0.8.9; import {MemUtils} from "../common/lib/MemUtils.sol"; interface IDepositContract { function get_deposit_root() external view returns (bytes32 rootHash); function deposit( bytes calldata pubkey, // 48 bytes bytes calldata withdrawal_credentials, // 32 bytes bytes calldata signature, // 96 bytes bytes32 deposit_data_root ) external payable; } contract BeaconChainDepositor { uint256 internal constant PUBLIC_KEY_LENGTH = 48; uint256 internal constant SIGNATURE_LENGTH = 96; uint256 internal constant DEPOSIT_SIZE = 32 ether; /// @dev deposit amount 32eth in gweis converted to little endian uint64 /// DEPOSIT_SIZE_IN_GWEI_LE64 = toLittleEndian64(32 ether / 1 gwei) uint64 internal constant DEPOSIT_SIZE_IN_GWEI_LE64 = 0x0040597307000000; IDepositContract public immutable DEPOSIT_CONTRACT; constructor(address _depositContract) { if (_depositContract == address(0)) revert DepositContractZeroAddress(); DEPOSIT_CONTRACT = IDepositContract(_depositContract); } /// @dev Invokes a deposit call to the official Beacon Deposit contract /// @param _keysCount amount of keys to deposit /// @param _withdrawalCredentials Commitment to a public key for withdrawals /// @param _publicKeysBatch A BLS12-381 public keys batch /// @param _signaturesBatch A BLS12-381 signatures batch function _makeBeaconChainDeposits32ETH( uint256 _keysCount, bytes memory _withdrawalCredentials, bytes memory _publicKeysBatch, bytes memory _signaturesBatch ) internal { 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); for (uint256 i; i < _keysCount;) { MemUtils.copyBytes(_publicKeysBatch, publicKey, i * PUBLIC_KEY_LENGTH, 0, PUBLIC_KEY_LENGTH); MemUtils.copyBytes(_signaturesBatch, signature, i * SIGNATURE_LENGTH, 0, SIGNATURE_LENGTH); DEPOSIT_CONTRACT.deposit{value: DEPOSIT_SIZE}( publicKey, _withdrawalCredentials, signature, _computeDepositDataRoot(_withdrawalCredentials, publicKey, signature) ); unchecked { ++i; } } } /// @dev computes the deposit_root_hash required by official Beacon Deposit contract /// @param _publicKey A BLS12-381 public key. /// @param _signature A BLS12-381 signature function _computeDepositDataRoot(bytes memory _withdrawalCredentials, bytes memory _publicKey, bytes memory _signature) private pure returns (bytes32) { // Compute deposit data root (`DepositData` hash tree root) according to deposit_contract.sol 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); 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)) ) ); } error DepositContractZeroAddress(); error InvalidPublicKeysBatchLength(uint256 actual, uint256 expected); error InvalidSignaturesBatchLength(uint256 actual, uint256 expected); }
// SPDX-FileCopyrightText: 2025 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.9; /// @title Lido's Staking Module interface interface IStakingModule { /// @dev Event to be emitted on StakingModule's nonce change event NonceChanged(uint256 nonce); /// @dev Event to be emitted when a signing key is added to the StakingModule event SigningKeyAdded(uint256 indexed nodeOperatorId, bytes pubkey); /// @dev Event to be emitted when a signing key is removed from the StakingModule event SigningKeyRemoved(uint256 indexed nodeOperatorId, bytes pubkey); /// @notice Handles tracking and penalization logic for a node operator who failed to exit their validator within the defined exit window. /// @dev This function is called by the StakingRouter to report the current exit-related status of a validator /// belonging to a specific node operator. It accepts a validator's public key, associated /// with the duration (in seconds) it was eligible to exit but has not exited. /// This data could be used to trigger penalties for the node operator if the validator has exceeded the allowed exit window. /// @param _nodeOperatorId The ID of the node operator whose validator's status is being delivered. /// @param _proofSlotTimestamp The timestamp (slot time) when the validator was last known to be in an active ongoing state. /// @param _publicKey The public key of the validator being reported. /// @param _eligibleToExitInSec The duration (in seconds) indicating how long the validator has been eligible to exit after request but has not exited. function reportValidatorExitDelay( uint256 _nodeOperatorId, uint256 _proofSlotTimestamp, bytes calldata _publicKey, uint256 _eligibleToExitInSec ) external; /// @notice Handles the triggerable exit event for a validator belonging to a specific node operator. /// @dev This function is called by the StakingRouter when a validator is triggered to exit using the triggerable /// exit request on the Execution Layer (EL). /// @param _nodeOperatorId The ID of the node operator. /// @param _publicKey The public key of the validator being reported. /// @param _withdrawalRequestPaidFee Fee amount paid to send a withdrawal request on the Execution Layer (EL). /// @param _exitType The type of exit being performed. /// This parameter may be interpreted differently across various staking modules, depending on their specific implementation. function onValidatorExitTriggered( uint256 _nodeOperatorId, bytes calldata _publicKey, uint256 _withdrawalRequestPaidFee, uint256 _exitType ) external; /// @notice Determines whether a validator's exit status should be updated and will have an effect on the Node Operator. /// @param _nodeOperatorId The ID of the node operator. /// @param _proofSlotTimestamp The timestamp (slot time) when the validator was last known to be in an active ongoing state. /// @param _publicKey The public key of the validator. /// @param _eligibleToExitInSec The number of seconds the validator was eligible to exit but did not. /// @return bool Returns true if the contract should receive the updated status of the validator. function isValidatorExitDelayPenaltyApplicable( uint256 _nodeOperatorId, uint256 _proofSlotTimestamp, bytes calldata _publicKey, uint256 _eligibleToExitInSec ) external view returns (bool); /// @notice Returns the number of seconds after which a validator is considered late for specified node operator. /// @param _nodeOperatorId The ID of the node operator. /// @return The exit deadline threshold in seconds. function exitDeadlineThreshold(uint256 _nodeOperatorId) external view returns (uint256); /// @notice Returns the type of the staking module function getType() external view returns (bytes32); /// @notice Returns all-validators summary in the staking module /// @return totalExitedValidators total number of validators in the EXITED state /// on the Consensus Layer. This value can't decrease in normal conditions /// @return totalDepositedValidators total number of validators deposited via the /// official Deposit Contract. This value is a cumulative counter: even when the validator /// goes into EXITED state this counter is not decreasing /// @return depositableValidatorsCount number of validators in the set available for deposit function getStakingModuleSummary() external view returns ( uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount ); /// @notice Returns all-validators summary belonging to the node operator with the given id /// @param _nodeOperatorId id of the operator to return report for /// @return targetLimitMode shows whether the current target limit applied to the node operator (0 = disabled, 1 = soft mode, 2 = boosted mode) /// @return targetValidatorsCount relative target active validators limit for operator /// @return stuckValidatorsCount number of validators with an expired request to exit time /// @return refundedValidatorsCount number of validators that can't be withdrawn, but deposit /// costs were compensated to the Lido by the node operator /// @return stuckPenaltyEndTimestamp time when the penalty for stuck validators stops applying /// to node operator rewards /// @return totalExitedValidators total number of validators in the EXITED state /// on the Consensus Layer. This value can't decrease in normal conditions /// @return totalDepositedValidators total number of validators deposited via the official /// Deposit Contract. This value is a cumulative counter: even when the validator goes into /// EXITED state this counter is not decreasing /// @return depositableValidatorsCount number of validators in the set available for deposit function getNodeOperatorSummary(uint256 _nodeOperatorId) external view returns ( uint256 targetLimitMode, uint256 targetValidatorsCount, uint256 stuckValidatorsCount, uint256 refundedValidatorsCount, uint256 stuckPenaltyEndTimestamp, uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount ); /// @notice Returns a counter that MUST change its value whenever the deposit data set changes. /// Below is the typical list of actions that requires an update of the nonce: /// 1. a node operator's deposit data is added /// 2. a node operator's deposit data is removed /// 3. a node operator's ready-to-deposit data size is changed /// 4. a node operator was activated/deactivated /// 5. a node operator's deposit data is used for the deposit /// Note: Depending on the StakingModule implementation above list might be extended /// @dev In some scenarios, it's allowed to update nonce without actual change of the deposit /// data subset, but it MUST NOT lead to the DOS of the staking module via continuous /// update of the nonce by the malicious actor function getNonce() external view returns (uint256); /// @notice Returns total number of node operators function getNodeOperatorsCount() external view returns (uint256); /// @notice Returns number of active node operators function getActiveNodeOperatorsCount() external view returns (uint256); /// @notice Returns if the node operator with given id is active /// @param _nodeOperatorId Id of the node operator function getNodeOperatorIsActive(uint256 _nodeOperatorId) external view returns (bool); /// @notice Returns up to `_limit` node operator ids starting from the `_offset`. The order of /// the returned ids is not defined and might change between calls. /// @dev This view must not revert in case of invalid data passed. When `_offset` exceeds the /// total node operators count or when `_limit` is equal to 0 MUST be returned empty array. function getNodeOperatorIds(uint256 _offset, uint256 _limit) external view returns (uint256[] memory nodeOperatorIds); /// @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. /// @dev IMPORTANT: this method SHOULD revert with empty error data ONLY because of "out of gas". /// Details about error data: https://docs.soliditylang.org/en/v0.8.9/control-structures.html#error-handling-assert-require-revert-and-exceptions function onRewardsMinted(uint256 _totalShares) external; /// @notice Called by StakingRouter to decrease the number of vetted keys for node operator with given id /// @param _nodeOperatorIds bytes packed array of the node operators id /// @param _vettedSigningKeysCounts bytes packed array of the new number of vetted keys for the node operators function decreaseVettedSigningKeysCount( bytes calldata _nodeOperatorIds, bytes calldata _vettedSigningKeysCounts ) external; /// @notice Updates the number of the validators in the EXITED state for node operator with given id /// @param _nodeOperatorIds bytes packed array of the node operators id /// @param _exitedValidatorsCounts bytes packed array of the new number of EXITED validators for the node operators function updateExitedValidatorsCount( bytes calldata _nodeOperatorIds, bytes calldata _exitedValidatorsCounts ) external; /// @notice Updates the number of the refunded validators for node operator with the given id /// @param _nodeOperatorId Id of the node operator /// @param _refundedValidatorsCount New number of refunded validators of the node operator function updateRefundedValidatorsCount(uint256 _nodeOperatorId, uint256 _refundedValidatorsCount) external; /// @notice Updates the limit of the validators that can be used for deposit /// @param _nodeOperatorId Id of the node operator /// @param _targetLimitMode target limit mode /// @param _targetLimit Target limit of the node operator function updateTargetValidatorsLimits( uint256 _nodeOperatorId, uint256 _targetLimitMode, uint256 _targetLimit ) external; /// @notice Unsafely updates the number of validators in the EXITED/STUCK states for node operator with given id /// 'unsafely' means that this method can both increase and decrease exited and stuck counters /// @param _nodeOperatorId Id of the node operator /// @param _exitedValidatorsCount New number of EXITED validators for the node operator function unsafeUpdateValidatorsCount( uint256 _nodeOperatorId, uint256 _exitedValidatorsCount ) external; /// @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 _depositCalldata Staking module defined data encoded as bytes. /// IMPORTANT: _depositCalldata MUST NOT modify the deposit data set of the staking module /// @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 _depositCalldata) external returns (bytes memory publicKeys, bytes memory signatures); /// @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. /// /// @dev IMPORTANT: this method SHOULD revert with empty error data ONLY because of "out of gas". /// Details about error data: https://docs.soliditylang.org/en/v0.8.9/control-structures.html#error-handling-assert-require-revert-and-exceptions 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 /// invalid after the withdrawal credentials are changed /// /// @dev IMPORTANT: this method SHOULD revert with empty error data ONLY because of "out of gas". /// Details about error data: https://docs.soliditylang.org/en/v0.8.9/control-structures.html#error-handling-assert-require-revert-and-exceptions function onWithdrawalCredentialsChanged() external; }
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity 0.8.9;
/**
* @notice Aragon Unstructured Storage library
*/
library UnstructuredStorage {
function getStorageBool(bytes32 position) internal view returns (bool data) {
assembly { data := sload(position) }
}
function getStorageAddress(bytes32 position) internal view returns (address data) {
assembly { data := sload(position) }
}
function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
assembly { data := sload(position) }
}
function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
assembly { data := sload(position) }
}
function setStorageBool(bytes32 position, bool data) internal {
assembly { sstore(position, data) }
}
function setStorageAddress(bytes32 position, address data) internal {
assembly { sstore(position, data) }
}
function setStorageBytes32(bytes32 position, bytes32 data) internal {
assembly { sstore(position, data) }
}
function setStorageUint256(bytes32 position, uint256 data) internal {
assembly { sstore(position, data) }
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)
//
// A modified AccessControl contract using unstructured storage. Copied from tree:
// https://github.com/OpenZeppelin/openzeppelin-contracts/tree/6bd6b76/contracts/access
//
/* See contracts/COMPILERS.md */
pragma solidity 0.8.9;
import "@openzeppelin/contracts-v4.4/access/IAccessControl.sol";
import "@openzeppelin/contracts-v4.4/utils/Context.sol";
import "@openzeppelin/contracts-v4.4/utils/Strings.sol";
import "@openzeppelin/contracts-v4.4/utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
/// @dev Storage slot: mapping(bytes32 => RoleData) _roles
bytes32 private constant ROLES_POSITION = keccak256("openzeppelin.AccessControl._roles");
function _storageRoles() private pure returns (mapping(bytes32 => RoleData) storage _roles) {
bytes32 position = ROLES_POSITION;
assembly { _roles.slot := position }
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
return _storageRoles()[role].members[account];
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
return _storageRoles()[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_storageRoles()[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_storageRoles()[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_storageRoles()[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/AccessControlEnumerable.sol)
//
// A modified AccessControlEnumerable contract using unstructured storage. Copied from tree:
// https://github.com/OpenZeppelin/openzeppelin-contracts/tree/6bd6b76/contracts/access
//
/* See contracts/COMPILERS.md */
pragma solidity 0.8.9;
import "@openzeppelin/contracts-v4.4/access/IAccessControlEnumerable.sol";
import "@openzeppelin/contracts-v4.4/utils/structs/EnumerableSet.sol";
import "./AccessControl.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
/// @dev Storage slot: mapping(bytes32 => EnumerableSet.AddressSet) _roleMembers
bytes32 private constant ROLE_MEMBERS_POSITION = keccak256("openzeppelin.AccessControlEnumerable._roleMembers");
function _storageRoleMembers() private pure returns (
mapping(bytes32 => EnumerableSet.AddressSet) storage _roleMembers
) {
bytes32 position = ROLE_MEMBERS_POSITION;
assembly { _roleMembers.slot := position }
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {
return _storageRoleMembers()[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view override returns (uint256) {
return _storageRoleMembers()[role].length();
}
/**
* @dev Overload {_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override {
super._grantRole(role, account);
_storageRoleMembers()[role].add(account);
}
/**
* @dev Overload {_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override {
super._revokeRole(role, account);
_storageRoleMembers()[role].remove(account);
}
}// SPDX-FileCopyrightText: 2022 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.9; import "../lib/UnstructuredStorage.sol"; contract Versioned { using UnstructuredStorage for bytes32; event ContractVersionSet(uint256 version); error NonZeroContractVersionOnInit(); error InvalidContractVersionIncrement(); error UnexpectedContractVersion(uint256 expected, uint256 received); /// @dev Storage slot: uint256 version /// Version of the initialized contract storage. /// The version stored in CONTRACT_VERSION_POSITION equals to: /// - 0 right after the deployment, before an initializer is invoked (and only at that moment); /// - N after calling initialize(), where N is the initially deployed contract version; /// - N after upgrading contract by calling finalizeUpgrade_vN(). bytes32 internal constant CONTRACT_VERSION_POSITION = keccak256("lido.Versioned.contractVersion"); uint256 internal constant PETRIFIED_VERSION_MARK = type(uint256).max; constructor() { // lock version in the implementation's storage to prevent initialization CONTRACT_VERSION_POSITION.setStorageUint256(PETRIFIED_VERSION_MARK); } /// @notice Returns the current contract version. function getContractVersion() public view returns (uint256) { return CONTRACT_VERSION_POSITION.getStorageUint256(); } function _checkContractVersion(uint256 version) internal view { uint256 expectedVersion = getContractVersion(); if (version != expectedVersion) { revert UnexpectedContractVersion(expectedVersion, version); } } /// @dev Sets the contract version to N. Should be called from the initialize() function. function _initializeContractVersionTo(uint256 version) internal { if (getContractVersion() != 0) revert NonZeroContractVersionOnInit(); _setContractVersion(version); } /// @dev Updates the contract version. Should be called from a finalizeUpgrade_vN() function. function _updateContractVersion(uint256 newVersion) internal { if (newVersion != getContractVersion() + 1) revert InvalidContractVersionIncrement(); _setContractVersion(newVersion); } function _setContractVersion(uint256 version) private { CONTRACT_VERSION_POSITION.setStorageUint256(version); emit ContractVersionSet(version); } }
// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: MIT // Copied from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/0457042d93d9dfd760dbaa06a4d2f1216fdbe297/contracts/utils/math/Math.sol // See contracts/COMPILERS.md // solhint-disable-next-line pragma solidity >=0.4.24 <0.9.0; library Math256 { /// @dev Returns the largest of two numbers. function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /// @dev Returns the smallest of two numbers. function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /// @dev Returns the largest of two numbers. function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /// @dev Returns the smallest of two numbers. function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /// @dev Returns the ceiling of the division of two numbers. /// /// This differs from standard division with `/` in that it rounds up instead /// of rounding down. function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /// @dev Returns absolute difference of two numbers. function absDiff(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a - b : b - a; } }
// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 /* See contracts/COMPILERS.md */ // solhint-disable-next-line lido/fixed-compiler-version pragma solidity >=0.4.24 <0.9.0; library MemUtils { /** * @dev Allocates a memory byte array of `_len` bytes without zeroing it out. */ function unsafeAllocateBytes(uint256 _len) internal pure returns (bytes memory result) { assembly { result := mload(0x40) mstore(result, _len) let freeMemPtr := add(add(result, 32), _len) // align free mem ptr to 32 bytes as the compiler does now mstore(0x40, and(add(freeMemPtr, 31), not(31))) } } /** * Performs a memory copy of `_len` bytes from position `_src` to position `_dst`. */ function memcpy(uint256 _src, uint256 _dst, uint256 _len) internal pure { assembly { // while al least 32 bytes left, copy in 32-byte chunks for { } gt(_len, 31) { } { mstore(_dst, mload(_src)) _src := add(_src, 32) _dst := add(_dst, 32) _len := sub(_len, 32) } if gt(_len, 0) { // read the next 32-byte chunk from _dst, replace the first N bytes // with those left in the _src, and write the transformed chunk back let mask := sub(shl(mul(8, sub(32, _len)), 1), 1) // 2 ** (8 * (32 - _len)) - 1 let srcMasked := and(mload(_src), not(mask)) let dstMasked := and(mload(_dst), mask) mstore(_dst, or(dstMasked, srcMasked)) } } } /** * Copies `_len` bytes from `_src`, starting at position `_srcStart`, into `_dst`, starting at position `_dstStart` into `_dst`. */ function copyBytes(bytes memory _src, bytes memory _dst, uint256 _srcStart, uint256 _dstStart, uint256 _len) internal pure { require(_srcStart + _len <= _src.length && _dstStart + _len <= _dst.length, "BYTES_ARRAY_OUT_OF_BOUNDS"); uint256 srcStartPos; uint256 dstStartPos; assembly { srcStartPos := add(add(_src, 32), _srcStart) dstStartPos := add(add(_dst, 32), _dstStart) } memcpy(srcStartPos, dstStartPos, _len); } /** * Copies bytes from `_src` to `_dst`, starting at position `_dstStart` into `_dst`. */ function copyBytes(bytes memory _src, bytes memory _dst, uint256 _dstStart) internal pure { copyBytes(_src, _dst, 0, _dstStart, _src.length); } }
// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 /* See contracts/COMPILERS.md */ // solhint-disable-next-line pragma solidity >=0.4.24 <0.9.0; import {Math256} from "./Math256.sol"; /// @notice Library with methods to calculate "proportional" allocations among buckets with different /// capacity and level of filling. /// @dev The current implementation favors buckets with the least fill factor library MinFirstAllocationStrategy { uint256 private constant MAX_UINT256 = 2**256 - 1; /// @notice Allocates passed maxAllocationSize among the buckets. The resulting allocation doesn't exceed the /// capacities of the buckets. An algorithm starts filling from the least populated buckets to equalize the fill factor. /// For example, for buckets: [9998, 70, 0], capacities: [10000, 101, 100], and maxAllocationSize: 101, the allocation happens /// following way: /// 1. top up the bucket with index 2 on 70. Intermediate state of the buckets: [9998, 70, 70]. According to the definition, /// the rest allocation must be proportionally split among the buckets with the same values. /// 2. top up the bucket with index 1 on 15. Intermediate state of the buckets: [9998, 85, 70]. /// 3. top up the bucket with index 2 on 15. Intermediate state of the buckets: [9998, 85, 85]. /// 4. top up the bucket with index 1 on 1. Nothing to distribute. The final state of the buckets: [9998, 86, 85] /// @dev Method modifies the passed buckets array to reduce the gas costs on memory allocation. /// @param buckets The array of current allocations in the buckets /// @param capacities The array of capacities of the buckets /// @param allocationSize The desired value to allocate among the buckets /// @return allocated The total value allocated among the buckets. Can't exceed the allocationSize value function allocate( uint256[] memory buckets, uint256[] memory capacities, uint256 allocationSize ) public pure returns (uint256 allocated, uint256[] memory) { uint256 allocatedToBestCandidate = 0; while (allocated < allocationSize) { allocatedToBestCandidate = allocateToBestCandidate(buckets, capacities, allocationSize - allocated); if (allocatedToBestCandidate == 0) { break; } allocated += allocatedToBestCandidate; } return (allocated, buckets); } /// @notice Allocates the max allowed value not exceeding allocationSize to the bucket with the least value. /// The candidate search happens according to the following algorithm: /// 1. Find the first least filled bucket which has free space. Count the number of such buckets. /// 2. If no buckets are found terminate the search - no free buckets /// 3. Find the first bucket with free space, which has the least value greater /// than the bucket found in step 1. To preserve proportional allocation the resulting allocation can't exceed this value. /// 4. Calculate the allocation size as: /// min( /// (count of least filling buckets > 1 ? ceilDiv(allocationSize, count of least filling buckets) : allocationSize), /// fill factor of the bucket found in step 3, /// free space of the least filled bucket /// ) /// @dev Method modifies the passed buckets array to reduce the gas costs on memory allocation. /// @param buckets The array of current allocations in the buckets /// @param capacities The array of capacities of the buckets /// @param allocationSize The desired value to allocate to the bucket /// @return allocated The total value allocated to the bucket. Can't exceed the allocationSize value function allocateToBestCandidate( uint256[] memory buckets, uint256[] memory capacities, uint256 allocationSize ) internal pure returns (uint256 allocated) { uint256 bestCandidateIndex = buckets.length; uint256 bestCandidateAllocation = MAX_UINT256; uint256 bestCandidatesCount = 0; if (allocationSize == 0) { return 0; } for (uint256 i = 0; i < buckets.length; ++i) { if (buckets[i] >= capacities[i]) { continue; } else if (bestCandidateAllocation > buckets[i]) { bestCandidateIndex = i; bestCandidatesCount = 1; bestCandidateAllocation = buckets[i]; } else if (bestCandidateAllocation == buckets[i]) { bestCandidatesCount += 1; } } if (bestCandidatesCount == 0) { return 0; } // cap the allocation by the smallest larger allocation than the found best one uint256 allocationSizeUpperBound = MAX_UINT256; for (uint256 j = 0; j < buckets.length; ++j) { if (buckets[j] >= capacities[j]) { continue; } else if (buckets[j] > bestCandidateAllocation && buckets[j] < allocationSizeUpperBound) { allocationSizeUpperBound = buckets[j]; } } allocated = Math256.min( bestCandidatesCount > 1 ? Math256.ceilDiv(allocationSize, bestCandidatesCount) : allocationSize, Math256.min(allocationSizeUpperBound, capacities[bestCandidateIndex]) - bestCandidateAllocation ); buckets[bestCandidateIndex] += allocated; } }
{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "istanbul",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/common/lib/MinFirstAllocationStrategy.sol": {
"MinFirstAllocationStrategy": "0x4a08c1501a886861c17341317ff7885a5a1e5db6"
}
}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"_depositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AppAuthLidoFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"firstArrayLength","type":"uint256"},{"internalType":"uint256","name":"secondArrayLength","type":"uint256"}],"name":"ArraysLengthMismatch","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"},{"internalType":"uint256","name":"depositsCount","type":"uint256"}],"name":"InvalidDepositsValue","type":"error"},{"inputs":[],"name":"InvalidFeeSum","type":"error"},{"inputs":[],"name":"InvalidMaxDepositPerBlockValue","type":"error"},{"inputs":[],"name":"InvalidMinDepositBlockDistance","type":"error"},{"inputs":[],"name":"InvalidPriorityExitShareThreshold","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":"InvalidStakeShareLimit","type":"error"},{"inputs":[],"name":"NonZeroContractVersionOnInit","type":"error"},{"inputs":[{"internalType":"uint256","name":"reportedExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"depositedValidatorsCount","type":"uint256"}],"name":"ReportedExitedValidatorsExceedDeposited","type":"error"},{"inputs":[],"name":"StakingModuleAddressExists","type":"error"},{"inputs":[],"name":"StakingModuleNotActive","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"}],"name":"UnexpectedCurrentValidatorsCount","type":"error"},{"inputs":[{"internalType":"uint256","name":"newModuleTotalExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newModuleTotalExitedValidatorsCountInStakingRouter","type":"uint256"}],"name":"UnexpectedFinalExitedValidatorsCount","type":"error"},{"inputs":[],"name":"UnrecoverableModuleError","type":"error"},{"inputs":[],"name":"ZeroAddressAdmin","type":"error"},{"inputs":[],"name":"ZeroAddressLido","type":"error"},{"inputs":[],"name":"ZeroAddressStakingModule","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"lowLevelRevertData","type":"bytes"}],"name":"ExitedAndStuckValidatorsCountsUpdateFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"lowLevelRevertData","type":"bytes"}],"name":"RewardsMintedReportFailed","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":true,"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_publicKey","type":"bytes"}],"name":"StakingModuleExitNotificationFailed","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":"uint256","name":"maxDepositsPerBlock","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleMaxDepositsPerBlockSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minDepositBlockDistance","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleMinDepositBlockDistanceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakeShareLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priorityExitShareThreshold","type":"uint256"},{"indexed":false,"internalType":"address","name":"setBy","type":"address"}],"name":"StakingModuleShareLimitSet","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":"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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"lowLevelRevertData","type":"bytes"}],"name":"WithdrawalsCredentialsChangeFailed","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":"MAX_STAKING_MODULES_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STAKING_MODULE_NAME_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"REPORT_VALIDATOR_EXITING_STATUS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPORT_VALIDATOR_EXIT_TRIGGERED_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_UNVETTING_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":"_stakeShareLimit","type":"uint256"},{"internalType":"uint256","name":"_priorityExitShareThreshold","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"},{"internalType":"uint256","name":"_maxDepositsPerBlock","type":"uint256"},{"internalType":"uint256","name":"_minDepositBlockDistance","type":"uint256"}],"name":"addStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"bytes","name":"_nodeOperatorIds","type":"bytes"},{"internalType":"bytes","name":"_vettedSigningKeysCounts","type":"bytes"}],"name":"decreaseStakingModuleVettedKeysCountByNodeOperator","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":[],"name":"finalizeUpgrade_v3","outputs":[],"stateMutability":"nonpayable","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":"uint256","name":"targetLimitMode","type":"uint256"},{"internalType":"uint256","name":"targetValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"stuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"refundedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"stuckPenaltyEndTimestamp","type":"uint256"},{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"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":"stakeShareLimit","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":"uint16","name":"priorityExitShareThreshold","type":"uint16"},{"internalType":"uint64","name":"maxDepositsPerBlock","type":"uint64"},{"internalType":"uint64","name":"minDepositBlockDistance","type":"uint64"}],"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":"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":"uint256","name":"targetLimitMode","type":"uint256"},{"internalType":"uint256","name":"targetValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"stuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"refundedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"stuckPenaltyEndTimestamp","type":"uint256"},{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"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":"uint256","name":"targetLimitMode","type":"uint256"},{"internalType":"uint256","name":"targetValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"stuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"refundedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"stuckPenaltyEndTimestamp","type":"uint256"},{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"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":"uint256","name":"targetLimitMode","type":"uint256"},{"internalType":"uint256","name":"targetValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"stuckValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"refundedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"stuckPenaltyEndTimestamp","type":"uint256"},{"internalType":"uint256","name":"totalExitedValidators","type":"uint256"},{"internalType":"uint256","name":"totalDepositedValidators","type":"uint256"},{"internalType":"uint256","name":"depositableValidatorsCount","type":"uint256"}],"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":"stakeShareLimit","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":"uint16","name":"priorityExitShareThreshold","type":"uint16"},{"internalType":"uint64","name":"maxDepositsPerBlock","type":"uint64"},{"internalType":"uint64","name":"minDepositBlockDistance","type":"uint64"}],"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":"stakeShareLimit","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":"uint16","name":"priorityExitShareThreshold","type":"uint16"},{"internalType":"uint64","name":"maxDepositsPerBlock","type":"uint64"},{"internalType":"uint64","name":"minDepositBlockDistance","type":"uint64"}],"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":"getStakingModuleMaxDepositsPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"getStakingModuleMinDepositBlockDistance","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":"stakeShareLimit","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":"uint16","name":"priorityExitShareThreshold","type":"uint16"},{"internalType":"uint64","name":"maxDepositsPerBlock","type":"uint64"},{"internalType":"uint64","name":"minDepositBlockDistance","type":"uint64"}],"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":"uint256","name":"_stakingModuleId","type":"uint256"}],"name":"hasStakingModule","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":[{"components":[{"internalType":"uint256","name":"stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"nodeOperatorId","type":"uint256"},{"internalType":"bytes","name":"pubkey","type":"bytes"}],"internalType":"struct StakingRouter.ValidatorExitData[]","name":"validatorExitData","type":"tuple[]"},{"internalType":"uint256","name":"_withdrawalRequestPaidFee","type":"uint256"},{"internalType":"uint256","name":"_exitType","type":"uint256"}],"name":"onValidatorExitTriggered","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"onValidatorsCountsByNodeOperatorReportingFinished","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":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_proofSlotTimestamp","type":"uint256"},{"internalType":"bytes","name":"_publicKey","type":"bytes"},{"internalType":"uint256","name":"_eligibleToExitInSec","type":"uint256"}],"name":"reportValidatorExitDelay","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":"newModuleExitedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"newNodeOperatorExitedValidatorsCount","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":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"_stakeShareLimit","type":"uint256"},{"internalType":"uint256","name":"_priorityExitShareThreshold","type":"uint256"},{"internalType":"uint256","name":"_stakingModuleFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"},{"internalType":"uint256","name":"_maxDepositsPerBlock","type":"uint256"},{"internalType":"uint256","name":"_minDepositBlockDistance","type":"uint256"}],"name":"updateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingModuleId","type":"uint256"},{"internalType":"uint256","name":"_nodeOperatorId","type":"uint256"},{"internalType":"uint256","name":"_targetLimitMode","type":"uint256"},{"internalType":"uint256","name":"_targetLimit","type":"uint256"}],"name":"updateTargetValidatorsLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a06040523480156200001157600080fd5b50604051620060e9380380620060e98339810160408190526200003491620000ae565b806001600160a01b0381166200005d57604051637c5f8bcf60e11b815260040160405180910390fd5b6001600160a01b0316608052620000a37f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6600019620000aa602090811b6200340c17901c565b50620000e0565b9055565b600060208284031215620000c157600080fd5b81516001600160a01b0381168114620000d957600080fd5b9392505050565b608051615fe662000103600039600081816107b40152613dee0152615fe66000f3fe6080604052600436106103fe5760003560e01c80639010d07c11610213578063c445ea7511610123578063e1b92a5c116100ab578063efcdcc0e1161007a578063efcdcc0e14610d00578063f07ff28a14610d30578063f2aebb6514610d50578063f8bb6d4214610d72578063fa5093eb14610d9257600080fd5b8063e1b92a5c14610c6c578063e24ce9f114610c8c578063e39fdbe914610cac578063e97ee8cc14610ce057600080fd5b8063cb8fd4da116100f2578063cb8fd4da14610bd5578063d0a2b1b814610bf5578063d547741f14610c15578063db3c7ba714610c35578063e016e6f714610c4a57600080fd5b8063c445ea7514610b45578063c82b1bb114610b67578063c8ac498014610b95578063ca15c87314610bb557600080fd5b8063a217fddf116101a6578063aa5a1b9d11610175578063aa5a1b9d14610a85578063abd44a2414610ab2578063af12409714610ad2578063ba21ccae14610af2578063bc1bb19014610b1857600080fd5b8063a217fddf146109ef578063a4258a8d14610a04578063a734329c14610a24578063aa0b7db714610a7257600080fd5b80639b75b4ef116101e25780639b75b4ef146109655780639dd068481461097a5780639fbb7bae1461099a5780639fc5a6ed146109c257600080fd5b80639010d07c146108d1578063909c01de146108f157806391d148541461092557806396b5d81c1461094557600080fd5b80634b3a1cb71161030e5780636b96736b116102a15780637a74884d116102705780637a74884d1461082b5780637b2740311461085f5780637c8da51c1461087f5780638525e3a11461089c5780638aa10435146108bc57600080fd5b80636b96736b146107a25780636d395b7e146107d657806371416583146107eb578063771895831461080b57600080fd5b80636183214d116102dd5780636183214d146107135780636608b11b146107355780636a516b47146107555780636ada55b91461078257600080fd5b80634b3a1cb7146106a757806356396715146106bc57806357993b85146106d15780636133f985146106f357600080fd5b8063248a9ca3116103915780633240a322116103605780633240a3221461060557806332c4962c1461063257806336568abe14610652578063473e0433146106725780634a7583b61461069257600080fd5b8063248a9ca31461058d578063271662ec146105ad5780632c201d31146105c35780632f2ff15d146105e557600080fd5b80631565d2f2116103cd5780631565d2f2146104e557806319c64b79146105195780631d1b9d3c1461053957806320e948c81461056d57600080fd5b806301ffc9a7146104215780630519fbbf1461045657806307e203ac146104845780630fb31c84146104b157600080fd5b3661041c576040516309fb455960e41b815260040160405180910390fd5b600080fd5b34801561042d57600080fd5b5061044161043c366004614c6e565b610dcd565b60405190151581526020015b60405180910390f35b34801561046257600080fd5b50610476610471366004614c98565b610df8565b60405190815260200161044d565b34801561049057600080fd5b506104a461049f366004614c98565b610e73565b60405161044d9190614cb1565b3480156104bd57600080fd5b506104767fbe1bd143a0dde8a867d58aab054bfdb25250951665c4570e39abc3b3de3c2d6c81565b3480156104f157600080fd5b506104767f55180e25fcacf9af017d35d497765476319b23896daa1f9bc2b38fa80b36a16381565b34801561052557600080fd5b50610476610534366004614cd2565b610ec3565b34801561054557600080fd5b506104767f779e5c23cb7a5bcb9bfe1e9a5165a00057f12bcdfd13e374540fdf1a1cd9113781565b34801561057957600080fd5b50610476610588366004614c98565b610f40565b34801561059957600080fd5b506104766105a8366004614c98565b610f6c565b3480156105b957600080fd5b5061047661271081565b3480156105cf57600080fd5b506105e36105de366004614d3c565b610f8e565b005b3480156105f157600080fd5b506105e3610600366004614dd1565b611039565b34801561061157600080fd5b50610625610620366004614c98565b61105b565b60405161044d9190614e4b565b34801561063e57600080fd5b506105e361064d366004614eb1565b6110dc565b34801561065e57600080fd5b506105e361066d366004614dd1565b61117e565b34801561067e57600080fd5b5061047661068d366004614c98565b611201565b34801561069e57600080fd5b50610476611219565b3480156106b357600080fd5b50610476602081565b3480156106c857600080fd5b50610476611248565b3480156106dd57600080fd5b506106e6611272565b60405161044d9190615078565b3480156106ff57600080fd5b506105e361070e36600461511d565b61127f565b34801561071f57600080fd5b50610728611372565b60405161044d9190615159565b34801561074157600080fd5b50610441610750366004614c98565b61156e565b34801561076157600080fd5b5061076a611593565b6040516001600160a01b03909116815260200161044d565b34801561078e57600080fd5b5061044161079d366004614c98565b6115bd565b3480156107ae57600080fd5b5061076a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156107e257600080fd5b506105e36115c6565b3480156107f757600080fd5b506105e36108063660046151ff565b6115dc565b34801561081757600080fd5b506105e361082636600461524f565b611769565b34801561083757600080fd5b506104767fe7c742a54cd11fc9749a47ab34bdcd7327820908e8d0d48b4a5c7f17b029409881565b34801561086b57600080fd5b506105e361087a3660046152ef565b6117ad565b34801561088b57600080fd5b5061047668056bc75e2d6310000081565b3480156108a857600080fd5b506106e66108b7366004615410565b611a18565b3480156108c857600080fd5b50610476611bf9565b3480156108dd57600080fd5b5061076a6108ec366004614cd2565b611c23565b3480156108fd57600080fd5b506104767f240525496a9dc32284b17ce03b43e539e4bd81414634ee54395030d793463b5781565b34801561093157600080fd5b50610441610940366004614dd1565b611c4f565b34801561095157600080fd5b50610476610960366004614c98565b611c87565b34801561097157600080fd5b50610476601f81565b34801561098657600080fd5b506105e3610995366004615444565b611cdf565b3480156109a657600080fd5b506109af611d67565b60405161ffff909116815260200161044d565b3480156109ce57600080fd5b506109e26109dd366004614c98565b611d95565b60405161044d91906154ae565b3480156109fb57600080fd5b50610476600081565b348015610a1057600080fd5b506105e3610a1f3660046154bc565b611dbf565b348015610a3057600080fd5b50610441610a3f366004614c98565b60009081527f9b48f5b32acb95b982effe269feac267eead113c4b5af14ffeb9aadac18a6e9c6020526040902054151590565b6105e3610a80366004615546565b61202b565b348015610a9157600080fd5b50610aa5610aa0366004614cd2565b612237565b60405161044d9190615598565b348015610abe57600080fd5b50610476610acd3660046155a7565b61230a565b348015610ade57600080fd5b506105e3610aed3660046155a7565b6124dc565b348015610afe57600080fd5b50610b07612683565b60405161044d959493929190615641565b348015610b2457600080fd5b50610b38610b33366004614c98565b6129fe565b60405161044d9190615700565b348015610b5157600080fd5b50610476600080516020615f7183398151915281565b348015610b7357600080fd5b50610b87610b82366004614c98565b612b72565b60405161044d929190615713565b348015610ba157600080fd5b506105e3610bb0366004614d3c565b612b8a565b348015610bc157600080fd5b50610476610bd0366004614c98565b612be9565b348015610be157600080fd5b50610476610bf0366004614c98565b612c0d565b348015610c0157600080fd5b506105e3610c1036600461572c565b612c35565b348015610c2157600080fd5b506105e3610c30366004614dd1565b612ccd565b348015610c4157600080fd5b506105e3612cea565b348015610c5657600080fd5b50610476600080516020615f9183398151915281565b348015610c7857600080fd5b506105e3610c87366004615760565b612e4b565b348015610c9857600080fd5b50610441610ca7366004614c98565b612ed6565b348015610cb857600080fd5b506104767f0766e72e5c008b3df8129fb356d9176eef8544f6241e078b7d61aff604f8812b81565b348015610cec57600080fd5b506105e3610cfb366004614c98565b612edf565b348015610d0c57600080fd5b50610d1561309e565b6040805161ffff93841681529290911660208301520161044d565b348015610d3c57600080fd5b50610625610d4b36600461578c565b6130e5565b348015610d5c57600080fd5b50610d65613270565b60405161044d91906157d2565b348015610d7e57600080fd5b50610625610d8d366004615760565b613306565b348015610d9e57600080fd5b50610da76133a2565b604080516001600160601b0394851681529390921660208401529082015260600161044d565b60006001600160e01b03198216635a05180f60e01b1480610df25750610df282613410565b92915050565b6000610e0382613445565b6001600160a01b031663d087d2886040518163ffffffff1660e01b815260040160206040518083038186803b158015610e3b57600080fd5b505afa158015610e4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df291906157e5565b610e9760405180606001604052806000815260200160008152602001600081525090565b6000610ea2836129fe565b602001519050610eb181613450565b60408501526020840152825250919050565b60008080610ee2610edd6801bc16d674ec8000008661582a565b6134d3565b92509250506000610ef28661371f565b9050818181518110610f0657610f0661583e565b602002602001015160c00151838281518110610f2457610f2461583e565b6020026020010151610f369190615854565b9695505050505050565b6000610f53610f4e8361371f565b613778565b600501546201000090046001600160401b031692915050565b6000908152600080516020615f51833981519152602052604090206001015490565b7f240525496a9dc32284b17ce03b43e539e4bd81414634ee54395030d793463b57610fb981336137a8565b610fc58585858561380c565b610fce86613445565b6001600160a01b031663b643189b868686866040518563ffffffff1660e01b8152600401610fff9493929190615894565b600060405180830381600087803b15801561101957600080fd5b505af115801561102d573d6000803e3d6000fd5b50505050505050505050565b61104282610f6c565b61104c81336137a8565b61105683836138ab565b505050565b6060610df282600061106c85613445565b6001600160a01b031663a70c70e46040518163ffffffff1660e01b815260040160206040518083038186803b1580156110a457600080fd5b505afa1580156110b8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8d91906157e5565b7fbe1bd143a0dde8a867d58aab054bfdb25250951665c4570e39abc3b3de3c2d6c61110781336137a8565b61111087613445565b6001600160a01b03166357f9c34187878787876040518663ffffffff1660e01b81526004016111439594939291906158c6565b600060405180830381600087803b15801561115d57600080fd5b505af1158015611171573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b03811633146111f35760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6111fd82826138da565b5050565b600061120f610f4e8361371f565b6003015492915050565b60006112437f1b3ef9db2d6f0727a31622833b45264c21051726d23ddb6f73b3b65628cafcc35490565b905090565b60006112437fabeb05279af36da5d476d7f950157cd2ea98a4166fa68a6bc97ce3a22fbb93c05490565b60606112436108b7613270565b6001600160a01b0383166112a65760405163371262eb60e11b815260040160405180910390fd5b6001600160a01b0382166112cd57604051630c75384960e01b815260040160405180910390fd5b6112d76003613909565b6112e260008461393b565b61130b7f706b9ed9846c161ad535be9b6345c3a7b2cb929e8d4a7254dee9ba6e6f8e5531839055565b6113347fabeb05279af36da5d476d7f950157cd2ea98a4166fa68a6bc97ce3a22fbb93c0829055565b604080518281523360208201527f82e72df77173eab89b00556d791a407a78f4605c5c2f0694967c8c429dd43c7c91015b60405180910390a1505050565b6060600061137e611219565b9050806001600160401b03811115611398576113986152a9565b6040519080825280602002602001820160405280156113d157816020015b6113be614a72565b8152602001906001900390816113b65790505b50915060005b81811015611569576113e881613778565b604080516101a081018252825462ffffff81168252630100000081046001600160a01b03166020830152600160b81b810461ffff90811693830193909352600160c81b810483166060830152600160d81b81049092166080820152600160e81b90910460ff1660a082015260018201805491929160c08401919061146b906158f8565b80601f0160208091040260200160405190810160405280929190818152602001828054611497906158f8565b80156114e45780601f106114b9576101008083540402835291602001916114e4565b820191906000526020600020905b8154815290600101906020018083116114c757829003601f168201915b505050918352505060028201546001600160401b039081166020830152600383015460408301526004830154606083015260059092015461ffff81166080830152620100008104831660a0830152600160501b900490911660c09091015283518490839081106115565761155661583e565b60209081029190910101526001016113d7565b505090565b6000805b61157b83611d95565b600281111561158c5761158c615476565b1492915050565b60006112437f706b9ed9846c161ad535be9b6345c3a7b2cb929e8d4a7254dee9ba6e6f8e55315490565b60006002611572565b6115d06002613945565b6115da600361397b565b565b7f0766e72e5c008b3df8129fb356d9176eef8544f6241e078b7d61aff604f8812b61160781336137a8565b3660005b85811015611760578686828181106116255761162561583e565b9050602002810190611637919061592d565b91506116438235613445565b6001600160a01b031663693cc6006020840135611663604086018661594d565b89896040518663ffffffff1660e01b8152600401611685959493929190615993565b600060405180830381600087803b15801561169f57600080fd5b505af19250505080156116b0575060015b611750573d8080156116de576040519150601f19603f3d011682016040523d82523d6000602084013e6116e3565b606091505b50805161170357604051638fd297d960e01b815260040160405180910390fd5b602083013583357fb639213d4cc5d7a615491fb0505dd448dee5074f322660125b7171993bf9bb1d611738604087018761594d565b6040516117469291906159c1565b60405180910390a3505b611759816159d5565b905061160b565b50505050505050565b600080516020615f9183398151915261178281336137a8565b6000611790610f4e8a61371f565b90506117a2818a8a8a8a8a8a8a6139ad565b505050505050505050565b7f55180e25fcacf9af017d35d497765476319b23896daa1f9bc2b38fa80b36a1636117d881336137a8565b60006117e6610f4e8761371f565b8054604051632cc1db0f60e21b815260048101889052919250630100000090046001600160a01b031690600090829063b3076c3c906024016101006040518083038186803b15801561183757600080fd5b505afa15801561184b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186f91906159f0565b50509550505050505082600401548560000151141580611893575080856020015114155b156118be5760048381015460405163c7c450d560e01b815291820152602481018290526044016111ea565b60408086015160048086019190915560608701519151631282406d60e31b81526001600160a01b03851692639412036892611905928c929101918252602082015260400190565b600060405180830381600087803b15801561191f57600080fd5b505af1158015611933573d6000803e3d6000fd5b5050505060008061194384613450565b5091509150808760400151111561197e57866040015181604051630b72c59d60e21b81526004016111ea929190918252602082015260400190565b871561102d57866040015182146119b95781876040015160405163dcab2a8960e01b81526004016111ea929190918252602082015260400190565b836001600160a01b031663e864299e6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156119f457600080fd5b505af1158015611a08573d6000803e3d6000fd5b5050505050505050505050505050565b606081516001600160401b03811115611a3357611a336152a9565b604051908082528060200260200182016040528015611a6c57816020015b611a59614add565b815260200190600190039081611a515790505b50905060005b8251811015611bf3576000611a9f848381518110611a9257611a9261583e565b60200260200101516129fe565b90506000816020015190506040518060800160405280826001600160a01b031663a70c70e46040518163ffffffff1660e01b815260040160206040518083038186803b158015611aee57600080fd5b505afa158015611b02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2691906157e5565b8152602001826001600160a01b0316638469cbd36040518163ffffffff1660e01b815260040160206040518083038186803b158015611b6457600080fd5b505afa158015611b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9c91906157e5565b8152602001838152602001611bc9878681518110611bbc57611bbc61583e565b6020026020010151610e73565b815250848481518110611bde57611bde61583e565b60209081029190910101525050600101611a72565b50919050565b60006112437f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a65490565b6000828152600080516020615f3183398151915260205260408120611c489083613c34565b9392505050565b6000918252600080516020615f51833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b600080611c96610f4e8461371f565b80549091506000908190611cb990630100000090046001600160a01b0316613450565b5091509150611ccc836004015483613c40565b611cd69082615854565b95945050505050565b600080516020615f91833981519152611cf881336137a8565b611d0185613445565b6040516308a679ad60e01b81526004810186905260248101859052604481018490526001600160a01b0391909116906308a679ad90606401600060405180830381600087803b158015611d5357600080fd5b505af11580156117a2573d6000803e3d6000fd5b6000806000611d74612683565b94509450505050611d8e826001600160601b031682613c56565b9250505090565b6000611da3610f4e8361371f565b54600160e81b900460ff166002811115610df257610df2615476565b600080516020615f91833981519152611dd881336137a8565b6001600160a01b038816611dff57604051632ec8c66160e01b815260040160405180910390fd5b881580611e0c5750601f89115b15611e2a5760405163ac18716960e01b815260040160405180910390fd5b6000611e34611219565b905060208110611e575760405163309eed9960e01b815260040160405180910390fd5b60005b81811015611ea757611e6b81613778565b546001600160a01b038b81166301000000909204161415611e9f5760405163050f969d60e41b815260040160405180910390fd5b600101611e5a565b506000611eb382613778565b90506000611edf7ff9a85ae945d8134f58bd2ee028636634dcb9e812798acb5c806bf1951232a2255490565b611eea906001615a4d565b825462ffffff191662ffffff82161783559050611f0b600183018e8e614b2c565b5081547fffff00ffffffffffff0000000000000000000000000000000000000000ffffff1663010000006001600160a01b038d160260ff60e81b1916178255611f5b8262ffffff83166000613c6f565b611f6a8162ffffff1684613cce565b62ffffff81167ff9a85ae945d8134f58bd2ee028636634dcb9e812798acb5c806bf1951232a22555611fc4611fa0846001615a74565b7f1b3ef9db2d6f0727a31622833b45264c21051726d23ddb6f73b3b65628cafcc355565b8062ffffff167f43b5213f0e1666cd0b8692a73686164c94deb955a59c65e10dee8bb958e7ce3e8c8f8f33604051611fff9493929190615a8c565b60405180910390a261201c828262ffffff168c8c8c8c8c8c6139ad565b50505050505050505050505050565b7f706b9ed9846c161ad535be9b6345c3a7b2cb929e8d4a7254dee9ba6e6f8e5531546001600160a01b0316336001600160a01b03161461207e57604051637e71782360e01b815260040160405180910390fd5b6000612088611248565b9050806120a85760405163180a97cd60e21b815260040160405180910390fd5b60006120b6610f4e8661371f565b905060008154600160e81b900460ff1660028111156120d7576120d7615476565b60028111156120e8576120e8615476565b146121065760405163322e64fb60e11b815260040160405180910390fd5b3461211a6801bc16d674ec80000088615ac3565b81146121435760405163023db95b60e21b815260048101829052602481018890526044016111ea565b61214e828783613c6f565b86156117605781546040516317dc836b60e31b8152600091829163010000009091046001600160a01b03169063bee41b5890612192908c908b908b90600401615ae2565b600060405180830381600087803b1580156121ac57600080fd5b505af11580156121c0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121e89190810190615b5f565b91509150600047905061221e8a8760405160200161220891815260200190565b6040516020818303038152906040528585613d11565b478461222a8284615854565b1461117157611171615bb8565b61223f614bb0565b600061224a846129fe565b602001519050600080600080600080866001600160a01b031663b3076c3c8a6040518263ffffffff1660e01b815260040161228791815260200190565b6101006040518083038186803b1580156122a057600080fd5b505afa1580156122b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122d891906159f0565b968f5260208f019590955260608e01929092525060a08c01525060c08a015260e0890152509598975050505050505050565b6000600080516020615f7183398151915261232581336137a8565b61232f8584613e8f565b6000805b868110156124d157600088888381811061234f5761234f61583e565b9050602002013590506000612366610f4e8361371f565b6004810154909150808989868181106123815761238161583e565b9050602002013510156123a757604051632f789f4960e21b815260040160405180910390fd5b815460009081906123c790630100000090046001600160a01b0316613450565b5091509150808b8b888181106123df576123df61583e565b90506020020135111561242a578a8a878181106123fe576123fe61583e565b9050602002013581604051630b72c59d60e21b81526004016111ea929190918252602082015260400190565b828b8b8881811061243d5761243d61583e565b9050602002013561244e9190615854565b6124589088615a74565b9650828210156124a057847fdd2523ca96a639ba7e17420698937f71eddd8af012ccb36ff5c8fe96141acae961248e8486615854565b60405190815260200160405180910390a25b8a8a878181106124b2576124b261583e565b9050602002013584600401819055508560010195505050505050612333565b509695505050505050565b7f779e5c23cb7a5bcb9bfe1e9a5165a00057f12bcdfd13e374540fdf1a1cd9113761250781336137a8565b6125118483613e8f565b60005b8481101561267b5760008484838181106125305761253061583e565b9050602002013511156126735761255e8686838181106125525761255261583e565b90506020020135613445565b6001600160a01b0316638d7e401785858481811061257e5761257e61583e565b905060200201356040518263ffffffff1660e01b81526004016125a391815260200190565b600060405180830381600087803b1580156125bd57600080fd5b505af19250505080156125ce575060015b612673573d8080156125fc576040519150601f19603f3d011682016040523d82523d6000602084013e612601565b606091505b50805161262157604051638fd297d960e01b815260040160405180910390fd5b8686838181106126335761263361583e565b905060200201357ff74208fedac7280fd11f8de0be14e00423dc5076da8e8ec8ca90e09257fff1b3826040516126699190615bce565b60405180910390a2505b600101612514565b505050505050565b6060806060600080600080612696613eb9565b805191935091508015806126a8575082155b156126ea5750506040805160008082526020820181815282840182815260608401909452919850909650909450925068056bc75e2d6310000091506129f79050565b68056bc75e2d631000009350806001600160401b0381111561270e5761270e6152a9565b604051908082528060200260200182016040528015612737578160200160208202803683370190505b509650806001600160401b03811115612752576127526152a9565b60405190808252806020026020018201604052801561277b578160200160208202803683370190505b509750806001600160401b03811115612796576127966152a9565b6040519080825280602002602001820160405280156127bf578160200160208202803683370190505b5095506000808060005b848110156129c45760008682815181106127e5576127e561583e565b602002602001015160c0015111156129bc578581815181106128095761280961583e565b60200260200101516020015162ffffff168b858151811061282c5761282c61583e565b602002602001018181525050868887838151811061284c5761284c61583e565b602002602001015160c001516128629190615ac3565b61286c919061582a565b92508581815181106128805761288061583e565b6020026020010151600001518c858151811061289e5761289e61583e565b60200260200101906001600160a01b031690816001600160a01b0316815250506127108682815181106128d3576128d361583e565b60200260200101516040015161ffff16846128ee9190615ac3565b6128f8919061582a565b9150600286828151811061290e5761290e61583e565b602002602001015160a00151600281111561292b5761292b615476565b1461296457818a85815181106129435761294361583e565b60200260200101906001600160601b031690816001600160601b0316815250505b8161271087838151811061297a5761297a61583e565b60200260200101516060015161ffff16856129959190615ac3565b61299f919061582a565b6129a99190615be1565b6129b3908a615be1565b98506001909301925b6001016127c9565b5086886001600160601b031611156129de576129de615bb8565b838310156129f057828a52828b528289525b5050505050505b9091929394565b612a06614a72565b612a12610f4e8361371f565b604080516101a081018252825462ffffff81168252630100000081046001600160a01b03166020830152600160b81b810461ffff90811693830193909352600160c81b810483166060830152600160d81b81049092166080820152600160e81b90910460ff1660a082015260018201805491929160c084019190612a95906158f8565b80601f0160208091040260200160405190810160405280929190818152602001828054612ac1906158f8565b8015612b0e5780601f10612ae357610100808354040283529160200191612b0e565b820191906000526020600020905b815481529060010190602001808311612af157829003601f168201915b505050918352505060028201546001600160401b039081166020830152600383015460408301526004830154606083015260059092015461ffff81166080830152620100008104831660a0830152600160501b900490911660c09091015292915050565b60006060612b7f836134d3565b509094909350915050565b600080516020615f71833981519152612ba381336137a8565b612baf8585858561380c565b612bb886613445565b6001600160a01b0316639b00c146868686866040518563ffffffff1660e01b8152600401610fff9493929190615894565b6000818152600080516020615f3183398151915260205260408120610df290613f87565b6000612c1b610f4e8361371f565b60050154600160501b90046001600160401b031692915050565b600080516020615f91833981519152612c4e81336137a8565b6000612c5c610f4e8561371f565b9050826002811115612c7057612c70615476565b8154600160e81b900460ff166002811115612c8d57612c8d615476565b6002811115612c9e57612c9e615476565b1415612cbd57604051635ca16fa760e11b815260040160405180910390fd5b612cc78184613f91565b50505050565b612cd682610f6c565b612ce081336137a8565b61105683836138da565b600080516020615f71833981519152612d0381336137a8565b6000612d0d611219565b905060008060005b83811015612e4457612d2681613778565b8054909350630100000090046001600160a01b031691506000612d4883613450565b505090508360040154811415612e3b57826001600160a01b031663e864299e6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612d9357600080fd5b505af1925050508015612da4575060015b612e3b573d808015612dd2576040519150601f19603f3d011682016040523d82523d6000602084013e612dd7565b606091505b508051612df757604051638fd297d960e01b815260040160405180910390fd5b845460405162ffffff909116907fe74bf895f0c3a2d6c74c40cbb362fdd9640035fc4226c72e3843809ad2a9d2b590612e31908490615bce565b60405180910390a2505b50600101612d15565b5050505050565b600080516020615f91833981519152612e6481336137a8565b612e6d84613445565b60405163a2e080f160e01b815260048101859052602481018490526001600160a01b03919091169063a2e080f190604401600060405180830381600087803b158015612eb857600080fd5b505af1158015612ecc573d6000803e3d6000fd5b5050505050505050565b60006001611572565b7fe7c742a54cd11fc9749a47ab34bdcd7327820908e8d0d48b4a5c7f17b0294098612f0a81336137a8565b612f337fabeb05279af36da5d476d7f950157cd2ea98a4166fa68a6bc97ce3a22fbb93c0839055565b6000612f3d611219565b905060005b81811015613068576000612f5582613778565b90508160010191508060000160039054906101000a90046001600160a01b03166001600160a01b03166390c09bdb6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612faf57600080fd5b505af1925050508015612fc0575060015b613062573d808015612fee576040519150601f19603f3d011682016040523d82523d6000602084013e612ff3565b606091505b50805161301357604051638fd297d960e01b815260040160405180910390fd5b61301e826001613f91565b815460405162ffffff909116907f0d64b11929aa111ca874dd00b5b0cc2d82b741be924ec9e3691e67c71552f62390613058908490615bce565b60405180910390a2505b50612f42565b50604080518481523360208201527f82e72df77173eab89b00556d791a407a78f4605c5c2f0694967c8c429dd43c7c9101611365565b60008060008060006130ae6133a2565b92506001600160601b031692506001600160601b031692506130d08382613c56565b94506130dc8282613c56565b93505050509091565b606060006130f284613445565b905082516001600160401b0381111561310d5761310d6152a9565b60405190808252806020026020018201604052801561314657816020015b613133614bf5565b81526020019060019003908161312b5790505b50915060005b83518110156132685760405180606001604052808583815181106131725761317261583e565b60200260200101518152602001836001600160a01b0316635e2fb9088785815181106131a0576131a061583e565b60200260200101516040518263ffffffff1660e01b81526004016131c691815260200190565b60206040518083038186803b1580156131de57600080fd5b505afa1580156131f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132169190615c03565b15158152602001613240878785815181106132335761323361583e565b6020026020010151612237565b8152508382815181106132555761325561583e565b602090810291909101015260010161314c565b505092915050565b6060600061327c611219565b9050806001600160401b03811115613296576132966152a9565b6040519080825280602002602001820160405280156132bf578160200160208202803683370190505b50915060005b81811015611569576132d681613778565b54835162ffffff909116908490839081106132f3576132f361583e565b60209081029190910101526001016132c5565b606061339a8461331586613445565b604051634febc81b60e01b815260048101879052602481018690526001600160a01b039190911690634febc81b9060440160006040518083038186803b15801561335e57600080fd5b505afa158015613372573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d4b9190810190615c7b565b949350505050565b6000806000606060006133b3612683565b9650909450925060009150505b82518110156133f8578281815181106133db576133db61583e565b6020026020010151866133ee9190615be1565b95506001016133c0565b506134038582615caf565b93505050909192565b9055565b60006001600160e01b03198216637965db0b60e01b1480610df257506301ffc9a760e01b6001600160e01b0319831614610df2565b6000610df282614047565b6000806000836001600160a01b0316639abddf096040518163ffffffff1660e01b815260040160606040518083038186803b15801561348e57600080fd5b505afa1580156134a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134c69190615cd7565b9250925092509193909250565b600060608060006134e2613eb9565b8051909350909150806001600160401b03811115613502576135026152a9565b60405190808252806020026020018201604052801561352b578160200160208202803683370190505b50935080156137165761353e8683615a74565b91506000816001600160401b0381111561355a5761355a6152a9565b604051908082528060200260200182016040528015613583578160200160208202803683370190505b5090506000805b8381101561367e578581815181106135a4576135a461583e565b602002602001015160c001518782815181106135c2576135c261583e565b602002602001018181525050612710858783815181106135e4576135e461583e565b60200260200101516080015161ffff166135fe9190615ac3565b613608919061582a565b9150613659828783815181106136205761362061583e565b602002602001015160e0015188848151811061363e5761363e61583e565b602002602001015160c001516136549190615a74565b61406c565b83828151811061366b5761366b61583e565b602090810291909101015260010161358a565b50604051632529fbc960e01b8152734a08c1501a886861c17341317ff7885a5a1e5db690632529fbc9906136ba90899086908d90600401615d05565b60006040518083038186803b1580156136d257600080fd5b505af41580156136e6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261370e9190810190615d3b565b909750955050505b50509193909250565b60008181527f9b48f5b32acb95b982effe269feac267eead113c4b5af14ffeb9aadac18a6e9c602081905260408220548061376d57604051636a0eb14160e11b815260040160405180910390fd5b61339a600182615854565b60009081527f1d2f69fc9b5fe89d7414bf039e8d897c4c487c7603d80de6bcdd2868466f94766020526040902090565b6137b28282611c4f565b6111fd576137ca816001600160a01b0316601461407b565b6137d583602061407b565b6040516020016137e6929190615d77565b60408051601f198184030181529082905262461bcd60e51b82526111ea91600401615bce565b613817600884615dec565b15158061382d575061382a601082615dec565b15155b1561384e576040516363209a7d60e11b8152600360048201526024016111ea565b600061385b60088561582a565b90508061386960108461582a565b1461388a576040516363209a7d60e11b8152600260048201526024016111ea565b80612e44576040516363209a7d60e11b8152600160048201526024016111ea565b6138b58282614216565b6000828152600080516020615f3183398151915260205260409020611056908261428c565b6138e482826142a1565b6000828152600080516020615f31833981519152602052604090206110569082614315565b613911611bf9565b1561392f5760405163184e52a160e21b815260040160405180910390fd5b6139388161432a565b50565b6111fd82826138ab565b600061394f611bf9565b90508082146111fd576040516303abe78360e21b815260048101829052602481018390526044016111ea565b613983611bf9565b61398e906001615a74565b811461392f5760405163167679d560e01b815260040160405180910390fd5b6127108611156139d057604051636f004ebd60e11b815260040160405180910390fd5b6127108511156139f357604051630285aacf60e31b815260040160405180910390fd5b84861115613a1457604051630285aacf60e31b815260040160405180910390fd5b612710613a218486615a74565b1115613a405760405163b65e4c5960e01b815260040160405180910390fd5b801580613a5357506001600160401b0381115b15613a71576040516309e7727560e31b815260040160405180910390fd5b6001600160401b03821115613a995760405163e747a27f60e01b815260040160405180910390fd5b875460058901805463ffffffff60c81b19909216600160d81b61ffff8a81169190910261ffff60c81b191691909117600160c81b878316021761ffff60b81b1916600160b81b88831602178b55871669ffffffffffffffffffff1990921691909117620100006001600160401b03858116919091029190911767ffffffffffffffff60501b1916600160501b918416919091021790556040805187815260208101879052339181019190915287907f1730859048adcce16559e75a58fd609e9dbf7d34f39bcb7a45ad388dfbba0e4e9060600160405180910390a260408051858152602081018590523381830152905188917f303c8ac43d1b1f9b898ddd2915a294efa01e9b07c322d7deeb7db332b66f0410919081900360600190a26040805183815233602082015288917f72766c50f14fe492bd1281ceef0a57ad49a02b7e1042fb58723647bf38040f83910160405180910390a26040805182815233602082015288917f4d106b4a7aff347abccca2dd6855d8d59d6cf792f1fdbb272c9858433d94b328910160405180910390a25050505050505050565b6000611c488383614389565b6000818311613c4f5781611c48565b5090919050565b600081613c6561271085615ac3565b611c48919061582a565b60028301805467ffffffffffffffff1916426001600160401b031617905543600384015560405181815282907f9151b7f88aca05d432bb395647ef52b2ffc454e3c6afb69c95345af6b5a778c0906020015b60405180910390a2505050565b7f9b48f5b32acb95b982effe269feac267eead113c4b5af14ffeb9aadac18a6e9c613cfa826001615a74565b600093845260209190915260409092209190915550565b613d1c846030615ac3565b825114613d52578151613d30856030615ac3565b6040516346b38e7960e11b8152600481019290925260248201526044016111ea565b613d5d846060615ac3565b815114613d93578051613d71856060615ac3565b604051633c11c1f760e21b8152600481019290925260248201526044016111ea565b6000613d9f60306143b3565b90506000613dad60606143b3565b905060005b8681101561176057613dd38584613dca603085615ac3565b600060306143cc565b613dec8483613de3606085615ac3565b600060606143cc565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec800000858986613e338c8a8a614453565b6040518663ffffffff1660e01b8152600401613e529493929190615e00565b6000604051808303818588803b158015613e6b57600080fd5b505af1158015613e7f573d6000803e3d6000fd5b5050505050806001019050613db2565b8082146111fd5760405163098b37e560e31b815260048101839052602481018290526044016111ea565b600060606000613ec7611219565b9050806001600160401b03811115613ee157613ee16152a9565b604051908082528060200260200182016040528015613f1a57816020015b613f07614c14565b815260200190600190039081613eff5790505b50915060005b81811015613f8157613f31816147ce565b838281518110613f4357613f4361583e565b6020026020010181905250828181518110613f6057613f6061583e565b602002602001015160c0015184613f779190615a74565b9350600101613f20565b50509091565b6000610df2825490565b8154600090600160e81b900460ff166002811115613fb157613fb1615476565b9050816002811115613fc557613fc5615476565b816002811115613fd757613fd7615476565b1461105657816002811115613fee57613fee615476565b835460ff91909116600160e81b0260ff60e81b1982168117855560405162ffffff9182169190921617907ffd6f15fb2b48a21a60fe3d44d3c3a0433ca01e121b5124a63ec45c30ad925a1790613cc19085903390615e4b565b6000614055610f4e8361371f565b54630100000090046001600160a01b031692915050565b6000818310613c4f5781611c48565b6060600061408a836002615ac3565b614095906002615a74565b6001600160401b038111156140ac576140ac6152a9565b6040519080825280601f01601f1916602001820160405280156140d6576020820181803683370190505b509050600360fc1b816000815181106140f1576140f161583e565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106141205761412061583e565b60200101906001600160f81b031916908160001a9053506000614144846002615ac3565b61414f906001615a74565b90505b60018111156141c7576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106141835761418361583e565b1a60f81b8282815181106141995761419961583e565b60200101906001600160f81b031916908160001a90535060049490941c936141c081615e71565b9050614152565b508315611c485760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016111ea565b6142208282611c4f565b6111fd576000828152600080516020615f51833981519152602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6000611c48836001600160a01b0384166148e5565b6142ab8282611c4f565b156111fd576000828152600080516020615f51833981519152602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611c48836001600160a01b038416614934565b6143537f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6829055565b6040518181527ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9060200160405180910390a150565b60008260000182815481106143a0576143a061583e565b9060005260206000200154905092915050565b60408051828152603f92810192909201601f1916905290565b84516143d88285615a74565b111580156143f0575083516143ed8284615a74565b11155b61443c5760405162461bcd60e51b815260206004820152601960248201527f42595445535f41525241595f4f55545f4f465f424f554e44530000000000000060448201526064016111ea565b602083860181019083860101611760828285614a27565b60008061446060406143b3565b9050600061447861447360406060615854565b6143b3565b9050614489848360008060406143cc565b6144a284826040600061449d826060615854565b6143cc565b6000600286600060801b6040516020016144bd929190615e88565b60408051601f19818403018152908290526144d791615ec0565b602060405180830381855afa1580156144f4573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061451791906157e5565b905060006002808560405160200161452f9190615ec0565b60408051601f198184030181529082905261454991615ec0565b602060405180830381855afa158015614566573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061458991906157e5565b6040516002906145a0908790600090602001615ed2565b60408051601f19818403018152908290526145ba91615ec0565b602060405180830381855afa1580156145d7573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906145fa91906157e5565b60408051602081019390935282015260600160408051601f198184030181529082905261462691615ec0565b602060405180830381855afa158015614643573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061466691906157e5565b9050600280838a60405160200161467e929190615ef4565b60408051601f198184030181529082905261469891615ec0565b602060405180830381855afa1580156146b5573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906146d891906157e5565b60408051634059730760d81b60208201526000602882015290810184905260029060600160408051601f198184030181529082905261471691615ec0565b602060405180830381855afa158015614733573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061475691906157e5565b60408051602081019390935282015260600160408051601f198184030181529082905261478291615ec0565b602060405180830381855afa15801561479f573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906147c291906157e5565b98975050505050505050565b6147d6614c14565b60006147e183613778565b80546001600160a01b036301000000820416845262ffffff8116602085015261ffff600160b81b820481166040860152600160c81b820481166060860152600160d81b820416608085015290915060ff600160e81b90910416600281111561484b5761484b615476565b8260a00190600281111561486157614861615476565b9081600281111561487457614874615476565b81525050600080600061488a8560000151613450565b9194509250905060008560a0015160028111156148a9576148a9615476565b146148b55760006148b7565b805b60e086015260048401546148cc908490613c40565b6148d69083615854565b60c08601525092949350505050565b600081815260018301602052604081205461492c57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610df2565b506000610df2565b60008181526001830160205260408120548015614a1d576000614958600183615854565b855490915060009061496c90600190615854565b90508181146149d157600086600001828154811061498c5761498c61583e565b90600052602060002001549050808760000184815481106149af576149af61583e565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806149e2576149e2615f1a565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610df2565b6000915050610df2565b5b601f811115614a48578251825260209283019290910190601f1901614a28565b80156110565782518251600019600160086020869003021b01908116901991909116178252505050565b604080516101a08101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082015260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081019190915290565b60405180608001604052806000815260200160008152602001614afe614a72565b8152602001614b2760405180606001604052806000815260200160008152602001600081525090565b905290565b828054614b38906158f8565b90600052602060002090601f016020900481019282614b5a5760008555614ba0565b82601f10614b735782800160ff19823516178555614ba0565b82800160010185558215614ba0579182015b82811115614ba0578235825591602001919060010190614b85565b50614bac929150614c59565b5090565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160608101825260008082526020820152908101614b27614bb0565b604080516101008101825260008082526020820181905291810182905260608101829052608081018290529060a0820190815260200160008152602001600081525090565b5b80821115614bac5760008155600101614c5a565b600060208284031215614c8057600080fd5b81356001600160e01b031981168114611c4857600080fd5b600060208284031215614caa57600080fd5b5035919050565b81518152602080830151908201526040808301519082015260608101610df2565b60008060408385031215614ce557600080fd5b50508035926020909101359150565b60008083601f840112614d0657600080fd5b5081356001600160401b03811115614d1d57600080fd5b602083019150836020828501011115614d3557600080fd5b9250929050565b600080600080600060608688031215614d5457600080fd5b8535945060208601356001600160401b0380821115614d7257600080fd5b614d7e89838a01614cf4565b90965094506040880135915080821115614d9757600080fd5b50614da488828901614cf4565b969995985093965092949392505050565b80356001600160a01b0381168114614dcc57600080fd5b919050565b60008060408385031215614de457600080fd5b82359150614df460208401614db5565b90509250929050565b805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301525050565b602080825282518282018190526000919060409081850190868401855b82811015614ea45781518051855286810151151587860152850151614e8f86860182614dfd565b50610140939093019290850190600101614e68565b5091979650505050505050565b60008060008060008060a08789031215614eca57600080fd5b86359550602087013594506040870135935060608701356001600160401b03811115614ef557600080fd5b614f0189828a01614cf4565b979a9699509497949695608090950135949350505050565b60005b83811015614f34578181015183820152602001614f1c565b83811115612cc75750506000910152565b60008151808452614f5d816020860160208601614f19565b601f01601f19169290920160200192915050565b805162ffffff16825260006101a06020830151614f9960208601826001600160a01b03169052565b506040830151614faf604086018261ffff169052565b506060830151614fc5606086018261ffff169052565b506080830151614fdb608086018261ffff169052565b5060a0830151614ff060a086018260ff169052565b5060c08301518160c086015261500882860182614f45565b91505060e083015161502560e08601826001600160401b03169052565b50610100838101519085015261012080840151908501526101408084015161ffff1690850152610160808401516001600160401b0390811691860191909152610180938401511692909301919091525090565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561510f57603f19898403018552815160c08151855288820151898601528782015181898701526150d582870182614f71565b60609384015180518886015260208101516080890152604081015160a089015293909250905050958801959350509086019060010161509f565b509098975050505050505050565b60008060006060848603121561513257600080fd5b61513b84614db5565b925061514960208501614db5565b9150604084013590509250925092565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156151ae57603f1988860301845261519c858351614f71565b94509285019290850190600101615180565b5092979650505050505050565b60008083601f8401126151cd57600080fd5b5081356001600160401b038111156151e457600080fd5b6020830191508360208260051b8501011115614d3557600080fd5b6000806000806060858703121561521557600080fd5b84356001600160401b0381111561522b57600080fd5b615237878288016151bb565b90989097506020870135966040013595509350505050565b600080600080600080600060e0888a03121561526a57600080fd5b505085359760208701359750604087013596606081013596506080810135955060a0810135945060c0013592509050565b801515811461393857600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156152e7576152e76152a9565b604052919050565b60008060008084860360e081121561530657600080fd5b8535945060208601359350604086013561531f8161529b565b92506080605f198201121561533357600080fd5b50604051608081018181106001600160401b0382111715615356576153566152a9565b8060405250606086013581526080860135602082015260a0860135604082015260c086013560608201528091505092959194509250565b60006001600160401b038211156153a6576153a66152a9565b5060051b60200190565b600082601f8301126153c157600080fd5b813560206153d66153d18361538d565b6152bf565b82815260059290921b840181019181810190868411156153f557600080fd5b8286015b848110156124d157803583529183019183016153f9565b60006020828403121561542257600080fd5b81356001600160401b0381111561543857600080fd5b61339a848285016153b0565b6000806000806080858703121561545a57600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052602160045260246000fd5b600381106154aa57634e487b7160e01b600052602160045260246000fd5b9052565b60208101610df2828461548c565b60008060008060008060008060006101008a8c0312156154db57600080fd5b89356001600160401b038111156154f157600080fd5b6154fd8c828d01614cf4565b909a509850615510905060208b01614db5565b989b979a509798604081013598506060810135976080820135975060a0820135965060c0820135955060e0909101359350915050565b6000806000806060858703121561555c57600080fd5b843593506020850135925060408501356001600160401b0381111561558057600080fd5b61558c87828801614cf4565b95989497509550505050565b6101008101610df28284614dfd565b600080600080604085870312156155bd57600080fd5b84356001600160401b03808211156155d457600080fd5b6155e0888389016151bb565b909650945060208701359150808211156155f957600080fd5b5061558c878288016151bb565b600081518084526020808501945080840160005b838110156156365781518752958201959082019060010161561a565b509495945050505050565b60a0808252865190820181905260009060209060c0840190828a01845b828110156156835781516001600160a01b03168452928401929084019060010161565e565b505050838103828501526156978189615606565b8481036040860152875180825283890192509083019060005b818110156156d55783516001600160601b0316835292840192918401916001016156b0565b50506001600160601b038716606086015292506156f0915050565b8260808301529695505050505050565b602081526000611c486020830184614f71565b82815260406020820152600061339a6040830184615606565b6000806040838503121561573f57600080fd5b8235915060208301356003811061575557600080fd5b809150509250929050565b60008060006060848603121561577557600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561579f57600080fd5b8235915060208301356001600160401b038111156157bc57600080fd5b6157c8858286016153b0565b9150509250929050565b602081526000611c486020830184615606565b6000602082840312156157f757600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082615839576158396157fe565b500490565b634e487b7160e01b600052603260045260246000fd5b60008282101561586657615866615814565b500390565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6040815260006158a860408301868861586b565b82810360208401526158bb81858761586b565b979650505050505050565b8581528460208201526080604082015260006158e660808301858761586b565b90508260608301529695505050505050565b600181811c9082168061590c57607f821691505b60208210811415611bf357634e487b7160e01b600052602260045260246000fd5b60008235605e1983360301811261594357600080fd5b9190910192915050565b6000808335601e1984360301811261596457600080fd5b8301803591506001600160401b0382111561597e57600080fd5b602001915036819003821315614d3557600080fd5b8581526080602082015260006159ad60808301868861586b565b604083019490945250606001529392505050565b60208152600061339a60208301848661586b565b60006000198214156159e9576159e9615814565b5060010190565b600080600080600080600080610100898b031215615a0d57600080fd5b505086516020880151604089015160608a015160808b015160a08c015160c08d015160e0909d0151959e949d50929b919a50985090965094509092509050565b600062ffffff808316818516808303821115615a6b57615a6b615814565b01949350505050565b60008219821115615a8757615a87615814565b500190565b600060018060a01b03808716835260606020840152615aaf60608401868861586b565b915080841660408401525095945050505050565b6000816000190483118215151615615add57615add615814565b500290565b838152604060208201526000611cd660408301848661586b565b600082601f830112615b0d57600080fd5b81516001600160401b03811115615b2657615b266152a9565b615b39601f8201601f19166020016152bf565b818152846020838601011115615b4e57600080fd5b61339a826020830160208701614f19565b60008060408385031215615b7257600080fd5b82516001600160401b0380821115615b8957600080fd5b615b9586838701615afc565b93506020850151915080821115615bab57600080fd5b506157c885828601615afc565b634e487b7160e01b600052600160045260246000fd5b602081526000611c486020830184614f45565b60006001600160601b03808316818516808303821115615a6b57615a6b615814565b600060208284031215615c1557600080fd5b8151611c488161529b565b600082601f830112615c3157600080fd5b81516020615c416153d18361538d565b82815260059290921b84018101918181019086841115615c6057600080fd5b8286015b848110156124d15780518352918301918301615c64565b600060208284031215615c8d57600080fd5b81516001600160401b03811115615ca357600080fd5b61339a84828501615c20565b60006001600160601b0383811690831681811015615ccf57615ccf615814565b039392505050565b600080600060608486031215615cec57600080fd5b8351925060208401519150604084015190509250925092565b606081526000615d186060830186615606565b8281036020840152615d2a8186615606565b915050826040830152949350505050565b60008060408385031215615d4e57600080fd5b8251915060208301516001600160401b03811115615d6b57600080fd5b6157c885828601615c20565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615daf816017850160208801614f19565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615de0816028840160208801614f19565b01602801949350505050565b600082615dfb57615dfb6157fe565b500690565b608081526000615e136080830187614f45565b8281036020840152615e258187614f45565b90508281036040840152615e398186614f45565b91505082606083015295945050505050565b60408101615e59828561548c565b6001600160a01b039290921660209190910152919050565b600081615e8057615e80615814565b506000190190565b60008351615e9a818460208801614f19565b6fffffffffffffffffffffffffffffffff19939093169190920190815260100192915050565b60008251615943818460208701614f19565b60008351615ee4818460208801614f19565b9190910191825250602001919050565b82815260008251615f0c816020850160208701614f19565b919091016020019392505050565b634e487b7160e01b600052603160045260246000fdfe8f8c450dae5029cd48cd91dd9db65da48fb742893edfc7941250f6721d93cbbe9a627a5d4aa7c17f87ff26e3fe9a42c2b6c559e8b41a42282d0ecebb17c0e4d3c23292b191d95d2a7dd94fc6436eb44338fda9e1307d9394fd27c28157c1b33c3105bcbf19d4417b73ae0e58d508a65ecf75665e46c2622d8521732de6080c48a264697066735822122075326e39f348a71e5550c61485363bae72b2ff45d197d8b5ee464d943f1ad6f464736f6c6343000809003300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa
Deployed Bytecode
0x6080604052600436106103fe5760003560e01c80639010d07c11610213578063c445ea7511610123578063e1b92a5c116100ab578063efcdcc0e1161007a578063efcdcc0e14610d00578063f07ff28a14610d30578063f2aebb6514610d50578063f8bb6d4214610d72578063fa5093eb14610d9257600080fd5b8063e1b92a5c14610c6c578063e24ce9f114610c8c578063e39fdbe914610cac578063e97ee8cc14610ce057600080fd5b8063cb8fd4da116100f2578063cb8fd4da14610bd5578063d0a2b1b814610bf5578063d547741f14610c15578063db3c7ba714610c35578063e016e6f714610c4a57600080fd5b8063c445ea7514610b45578063c82b1bb114610b67578063c8ac498014610b95578063ca15c87314610bb557600080fd5b8063a217fddf116101a6578063aa5a1b9d11610175578063aa5a1b9d14610a85578063abd44a2414610ab2578063af12409714610ad2578063ba21ccae14610af2578063bc1bb19014610b1857600080fd5b8063a217fddf146109ef578063a4258a8d14610a04578063a734329c14610a24578063aa0b7db714610a7257600080fd5b80639b75b4ef116101e25780639b75b4ef146109655780639dd068481461097a5780639fbb7bae1461099a5780639fc5a6ed146109c257600080fd5b80639010d07c146108d1578063909c01de146108f157806391d148541461092557806396b5d81c1461094557600080fd5b80634b3a1cb71161030e5780636b96736b116102a15780637a74884d116102705780637a74884d1461082b5780637b2740311461085f5780637c8da51c1461087f5780638525e3a11461089c5780638aa10435146108bc57600080fd5b80636b96736b146107a25780636d395b7e146107d657806371416583146107eb578063771895831461080b57600080fd5b80636183214d116102dd5780636183214d146107135780636608b11b146107355780636a516b47146107555780636ada55b91461078257600080fd5b80634b3a1cb7146106a757806356396715146106bc57806357993b85146106d15780636133f985146106f357600080fd5b8063248a9ca3116103915780633240a322116103605780633240a3221461060557806332c4962c1461063257806336568abe14610652578063473e0433146106725780634a7583b61461069257600080fd5b8063248a9ca31461058d578063271662ec146105ad5780632c201d31146105c35780632f2ff15d146105e557600080fd5b80631565d2f2116103cd5780631565d2f2146104e557806319c64b79146105195780631d1b9d3c1461053957806320e948c81461056d57600080fd5b806301ffc9a7146104215780630519fbbf1461045657806307e203ac146104845780630fb31c84146104b157600080fd5b3661041c576040516309fb455960e41b815260040160405180910390fd5b600080fd5b34801561042d57600080fd5b5061044161043c366004614c6e565b610dcd565b60405190151581526020015b60405180910390f35b34801561046257600080fd5b50610476610471366004614c98565b610df8565b60405190815260200161044d565b34801561049057600080fd5b506104a461049f366004614c98565b610e73565b60405161044d9190614cb1565b3480156104bd57600080fd5b506104767fbe1bd143a0dde8a867d58aab054bfdb25250951665c4570e39abc3b3de3c2d6c81565b3480156104f157600080fd5b506104767f55180e25fcacf9af017d35d497765476319b23896daa1f9bc2b38fa80b36a16381565b34801561052557600080fd5b50610476610534366004614cd2565b610ec3565b34801561054557600080fd5b506104767f779e5c23cb7a5bcb9bfe1e9a5165a00057f12bcdfd13e374540fdf1a1cd9113781565b34801561057957600080fd5b50610476610588366004614c98565b610f40565b34801561059957600080fd5b506104766105a8366004614c98565b610f6c565b3480156105b957600080fd5b5061047661271081565b3480156105cf57600080fd5b506105e36105de366004614d3c565b610f8e565b005b3480156105f157600080fd5b506105e3610600366004614dd1565b611039565b34801561061157600080fd5b50610625610620366004614c98565b61105b565b60405161044d9190614e4b565b34801561063e57600080fd5b506105e361064d366004614eb1565b6110dc565b34801561065e57600080fd5b506105e361066d366004614dd1565b61117e565b34801561067e57600080fd5b5061047661068d366004614c98565b611201565b34801561069e57600080fd5b50610476611219565b3480156106b357600080fd5b50610476602081565b3480156106c857600080fd5b50610476611248565b3480156106dd57600080fd5b506106e6611272565b60405161044d9190615078565b3480156106ff57600080fd5b506105e361070e36600461511d565b61127f565b34801561071f57600080fd5b50610728611372565b60405161044d9190615159565b34801561074157600080fd5b50610441610750366004614c98565b61156e565b34801561076157600080fd5b5061076a611593565b6040516001600160a01b03909116815260200161044d565b34801561078e57600080fd5b5061044161079d366004614c98565b6115bd565b3480156107ae57600080fd5b5061076a7f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa81565b3480156107e257600080fd5b506105e36115c6565b3480156107f757600080fd5b506105e36108063660046151ff565b6115dc565b34801561081757600080fd5b506105e361082636600461524f565b611769565b34801561083757600080fd5b506104767fe7c742a54cd11fc9749a47ab34bdcd7327820908e8d0d48b4a5c7f17b029409881565b34801561086b57600080fd5b506105e361087a3660046152ef565b6117ad565b34801561088b57600080fd5b5061047668056bc75e2d6310000081565b3480156108a857600080fd5b506106e66108b7366004615410565b611a18565b3480156108c857600080fd5b50610476611bf9565b3480156108dd57600080fd5b5061076a6108ec366004614cd2565b611c23565b3480156108fd57600080fd5b506104767f240525496a9dc32284b17ce03b43e539e4bd81414634ee54395030d793463b5781565b34801561093157600080fd5b50610441610940366004614dd1565b611c4f565b34801561095157600080fd5b50610476610960366004614c98565b611c87565b34801561097157600080fd5b50610476601f81565b34801561098657600080fd5b506105e3610995366004615444565b611cdf565b3480156109a657600080fd5b506109af611d67565b60405161ffff909116815260200161044d565b3480156109ce57600080fd5b506109e26109dd366004614c98565b611d95565b60405161044d91906154ae565b3480156109fb57600080fd5b50610476600081565b348015610a1057600080fd5b506105e3610a1f3660046154bc565b611dbf565b348015610a3057600080fd5b50610441610a3f366004614c98565b60009081527f9b48f5b32acb95b982effe269feac267eead113c4b5af14ffeb9aadac18a6e9c6020526040902054151590565b6105e3610a80366004615546565b61202b565b348015610a9157600080fd5b50610aa5610aa0366004614cd2565b612237565b60405161044d9190615598565b348015610abe57600080fd5b50610476610acd3660046155a7565b61230a565b348015610ade57600080fd5b506105e3610aed3660046155a7565b6124dc565b348015610afe57600080fd5b50610b07612683565b60405161044d959493929190615641565b348015610b2457600080fd5b50610b38610b33366004614c98565b6129fe565b60405161044d9190615700565b348015610b5157600080fd5b50610476600080516020615f7183398151915281565b348015610b7357600080fd5b50610b87610b82366004614c98565b612b72565b60405161044d929190615713565b348015610ba157600080fd5b506105e3610bb0366004614d3c565b612b8a565b348015610bc157600080fd5b50610476610bd0366004614c98565b612be9565b348015610be157600080fd5b50610476610bf0366004614c98565b612c0d565b348015610c0157600080fd5b506105e3610c1036600461572c565b612c35565b348015610c2157600080fd5b506105e3610c30366004614dd1565b612ccd565b348015610c4157600080fd5b506105e3612cea565b348015610c5657600080fd5b50610476600080516020615f9183398151915281565b348015610c7857600080fd5b506105e3610c87366004615760565b612e4b565b348015610c9857600080fd5b50610441610ca7366004614c98565b612ed6565b348015610cb857600080fd5b506104767f0766e72e5c008b3df8129fb356d9176eef8544f6241e078b7d61aff604f8812b81565b348015610cec57600080fd5b506105e3610cfb366004614c98565b612edf565b348015610d0c57600080fd5b50610d1561309e565b6040805161ffff93841681529290911660208301520161044d565b348015610d3c57600080fd5b50610625610d4b36600461578c565b6130e5565b348015610d5c57600080fd5b50610d65613270565b60405161044d91906157d2565b348015610d7e57600080fd5b50610625610d8d366004615760565b613306565b348015610d9e57600080fd5b50610da76133a2565b604080516001600160601b0394851681529390921660208401529082015260600161044d565b60006001600160e01b03198216635a05180f60e01b1480610df25750610df282613410565b92915050565b6000610e0382613445565b6001600160a01b031663d087d2886040518163ffffffff1660e01b815260040160206040518083038186803b158015610e3b57600080fd5b505afa158015610e4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df291906157e5565b610e9760405180606001604052806000815260200160008152602001600081525090565b6000610ea2836129fe565b602001519050610eb181613450565b60408501526020840152825250919050565b60008080610ee2610edd6801bc16d674ec8000008661582a565b6134d3565b92509250506000610ef28661371f565b9050818181518110610f0657610f0661583e565b602002602001015160c00151838281518110610f2457610f2461583e565b6020026020010151610f369190615854565b9695505050505050565b6000610f53610f4e8361371f565b613778565b600501546201000090046001600160401b031692915050565b6000908152600080516020615f51833981519152602052604090206001015490565b7f240525496a9dc32284b17ce03b43e539e4bd81414634ee54395030d793463b57610fb981336137a8565b610fc58585858561380c565b610fce86613445565b6001600160a01b031663b643189b868686866040518563ffffffff1660e01b8152600401610fff9493929190615894565b600060405180830381600087803b15801561101957600080fd5b505af115801561102d573d6000803e3d6000fd5b50505050505050505050565b61104282610f6c565b61104c81336137a8565b61105683836138ab565b505050565b6060610df282600061106c85613445565b6001600160a01b031663a70c70e46040518163ffffffff1660e01b815260040160206040518083038186803b1580156110a457600080fd5b505afa1580156110b8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8d91906157e5565b7fbe1bd143a0dde8a867d58aab054bfdb25250951665c4570e39abc3b3de3c2d6c61110781336137a8565b61111087613445565b6001600160a01b03166357f9c34187878787876040518663ffffffff1660e01b81526004016111439594939291906158c6565b600060405180830381600087803b15801561115d57600080fd5b505af1158015611171573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b03811633146111f35760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6111fd82826138da565b5050565b600061120f610f4e8361371f565b6003015492915050565b60006112437f1b3ef9db2d6f0727a31622833b45264c21051726d23ddb6f73b3b65628cafcc35490565b905090565b60006112437fabeb05279af36da5d476d7f950157cd2ea98a4166fa68a6bc97ce3a22fbb93c05490565b60606112436108b7613270565b6001600160a01b0383166112a65760405163371262eb60e11b815260040160405180910390fd5b6001600160a01b0382166112cd57604051630c75384960e01b815260040160405180910390fd5b6112d76003613909565b6112e260008461393b565b61130b7f706b9ed9846c161ad535be9b6345c3a7b2cb929e8d4a7254dee9ba6e6f8e5531839055565b6113347fabeb05279af36da5d476d7f950157cd2ea98a4166fa68a6bc97ce3a22fbb93c0829055565b604080518281523360208201527f82e72df77173eab89b00556d791a407a78f4605c5c2f0694967c8c429dd43c7c91015b60405180910390a1505050565b6060600061137e611219565b9050806001600160401b03811115611398576113986152a9565b6040519080825280602002602001820160405280156113d157816020015b6113be614a72565b8152602001906001900390816113b65790505b50915060005b81811015611569576113e881613778565b604080516101a081018252825462ffffff81168252630100000081046001600160a01b03166020830152600160b81b810461ffff90811693830193909352600160c81b810483166060830152600160d81b81049092166080820152600160e81b90910460ff1660a082015260018201805491929160c08401919061146b906158f8565b80601f0160208091040260200160405190810160405280929190818152602001828054611497906158f8565b80156114e45780601f106114b9576101008083540402835291602001916114e4565b820191906000526020600020905b8154815290600101906020018083116114c757829003601f168201915b505050918352505060028201546001600160401b039081166020830152600383015460408301526004830154606083015260059092015461ffff81166080830152620100008104831660a0830152600160501b900490911660c09091015283518490839081106115565761155661583e565b60209081029190910101526001016113d7565b505090565b6000805b61157b83611d95565b600281111561158c5761158c615476565b1492915050565b60006112437f706b9ed9846c161ad535be9b6345c3a7b2cb929e8d4a7254dee9ba6e6f8e55315490565b60006002611572565b6115d06002613945565b6115da600361397b565b565b7f0766e72e5c008b3df8129fb356d9176eef8544f6241e078b7d61aff604f8812b61160781336137a8565b3660005b85811015611760578686828181106116255761162561583e565b9050602002810190611637919061592d565b91506116438235613445565b6001600160a01b031663693cc6006020840135611663604086018661594d565b89896040518663ffffffff1660e01b8152600401611685959493929190615993565b600060405180830381600087803b15801561169f57600080fd5b505af19250505080156116b0575060015b611750573d8080156116de576040519150601f19603f3d011682016040523d82523d6000602084013e6116e3565b606091505b50805161170357604051638fd297d960e01b815260040160405180910390fd5b602083013583357fb639213d4cc5d7a615491fb0505dd448dee5074f322660125b7171993bf9bb1d611738604087018761594d565b6040516117469291906159c1565b60405180910390a3505b611759816159d5565b905061160b565b50505050505050565b600080516020615f9183398151915261178281336137a8565b6000611790610f4e8a61371f565b90506117a2818a8a8a8a8a8a8a6139ad565b505050505050505050565b7f55180e25fcacf9af017d35d497765476319b23896daa1f9bc2b38fa80b36a1636117d881336137a8565b60006117e6610f4e8761371f565b8054604051632cc1db0f60e21b815260048101889052919250630100000090046001600160a01b031690600090829063b3076c3c906024016101006040518083038186803b15801561183757600080fd5b505afa15801561184b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186f91906159f0565b50509550505050505082600401548560000151141580611893575080856020015114155b156118be5760048381015460405163c7c450d560e01b815291820152602481018290526044016111ea565b60408086015160048086019190915560608701519151631282406d60e31b81526001600160a01b03851692639412036892611905928c929101918252602082015260400190565b600060405180830381600087803b15801561191f57600080fd5b505af1158015611933573d6000803e3d6000fd5b5050505060008061194384613450565b5091509150808760400151111561197e57866040015181604051630b72c59d60e21b81526004016111ea929190918252602082015260400190565b871561102d57866040015182146119b95781876040015160405163dcab2a8960e01b81526004016111ea929190918252602082015260400190565b836001600160a01b031663e864299e6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156119f457600080fd5b505af1158015611a08573d6000803e3d6000fd5b5050505050505050505050505050565b606081516001600160401b03811115611a3357611a336152a9565b604051908082528060200260200182016040528015611a6c57816020015b611a59614add565b815260200190600190039081611a515790505b50905060005b8251811015611bf3576000611a9f848381518110611a9257611a9261583e565b60200260200101516129fe565b90506000816020015190506040518060800160405280826001600160a01b031663a70c70e46040518163ffffffff1660e01b815260040160206040518083038186803b158015611aee57600080fd5b505afa158015611b02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2691906157e5565b8152602001826001600160a01b0316638469cbd36040518163ffffffff1660e01b815260040160206040518083038186803b158015611b6457600080fd5b505afa158015611b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9c91906157e5565b8152602001838152602001611bc9878681518110611bbc57611bbc61583e565b6020026020010151610e73565b815250848481518110611bde57611bde61583e565b60209081029190910101525050600101611a72565b50919050565b60006112437f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a65490565b6000828152600080516020615f3183398151915260205260408120611c489083613c34565b9392505050565b6000918252600080516020615f51833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b600080611c96610f4e8461371f565b80549091506000908190611cb990630100000090046001600160a01b0316613450565b5091509150611ccc836004015483613c40565b611cd69082615854565b95945050505050565b600080516020615f91833981519152611cf881336137a8565b611d0185613445565b6040516308a679ad60e01b81526004810186905260248101859052604481018490526001600160a01b0391909116906308a679ad90606401600060405180830381600087803b158015611d5357600080fd5b505af11580156117a2573d6000803e3d6000fd5b6000806000611d74612683565b94509450505050611d8e826001600160601b031682613c56565b9250505090565b6000611da3610f4e8361371f565b54600160e81b900460ff166002811115610df257610df2615476565b600080516020615f91833981519152611dd881336137a8565b6001600160a01b038816611dff57604051632ec8c66160e01b815260040160405180910390fd5b881580611e0c5750601f89115b15611e2a5760405163ac18716960e01b815260040160405180910390fd5b6000611e34611219565b905060208110611e575760405163309eed9960e01b815260040160405180910390fd5b60005b81811015611ea757611e6b81613778565b546001600160a01b038b81166301000000909204161415611e9f5760405163050f969d60e41b815260040160405180910390fd5b600101611e5a565b506000611eb382613778565b90506000611edf7ff9a85ae945d8134f58bd2ee028636634dcb9e812798acb5c806bf1951232a2255490565b611eea906001615a4d565b825462ffffff191662ffffff82161783559050611f0b600183018e8e614b2c565b5081547fffff00ffffffffffff0000000000000000000000000000000000000000ffffff1663010000006001600160a01b038d160260ff60e81b1916178255611f5b8262ffffff83166000613c6f565b611f6a8162ffffff1684613cce565b62ffffff81167ff9a85ae945d8134f58bd2ee028636634dcb9e812798acb5c806bf1951232a22555611fc4611fa0846001615a74565b7f1b3ef9db2d6f0727a31622833b45264c21051726d23ddb6f73b3b65628cafcc355565b8062ffffff167f43b5213f0e1666cd0b8692a73686164c94deb955a59c65e10dee8bb958e7ce3e8c8f8f33604051611fff9493929190615a8c565b60405180910390a261201c828262ffffff168c8c8c8c8c8c6139ad565b50505050505050505050505050565b7f706b9ed9846c161ad535be9b6345c3a7b2cb929e8d4a7254dee9ba6e6f8e5531546001600160a01b0316336001600160a01b03161461207e57604051637e71782360e01b815260040160405180910390fd5b6000612088611248565b9050806120a85760405163180a97cd60e21b815260040160405180910390fd5b60006120b6610f4e8661371f565b905060008154600160e81b900460ff1660028111156120d7576120d7615476565b60028111156120e8576120e8615476565b146121065760405163322e64fb60e11b815260040160405180910390fd5b3461211a6801bc16d674ec80000088615ac3565b81146121435760405163023db95b60e21b815260048101829052602481018890526044016111ea565b61214e828783613c6f565b86156117605781546040516317dc836b60e31b8152600091829163010000009091046001600160a01b03169063bee41b5890612192908c908b908b90600401615ae2565b600060405180830381600087803b1580156121ac57600080fd5b505af11580156121c0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121e89190810190615b5f565b91509150600047905061221e8a8760405160200161220891815260200190565b6040516020818303038152906040528585613d11565b478461222a8284615854565b1461117157611171615bb8565b61223f614bb0565b600061224a846129fe565b602001519050600080600080600080866001600160a01b031663b3076c3c8a6040518263ffffffff1660e01b815260040161228791815260200190565b6101006040518083038186803b1580156122a057600080fd5b505afa1580156122b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122d891906159f0565b968f5260208f019590955260608e01929092525060a08c01525060c08a015260e0890152509598975050505050505050565b6000600080516020615f7183398151915261232581336137a8565b61232f8584613e8f565b6000805b868110156124d157600088888381811061234f5761234f61583e565b9050602002013590506000612366610f4e8361371f565b6004810154909150808989868181106123815761238161583e565b9050602002013510156123a757604051632f789f4960e21b815260040160405180910390fd5b815460009081906123c790630100000090046001600160a01b0316613450565b5091509150808b8b888181106123df576123df61583e565b90506020020135111561242a578a8a878181106123fe576123fe61583e565b9050602002013581604051630b72c59d60e21b81526004016111ea929190918252602082015260400190565b828b8b8881811061243d5761243d61583e565b9050602002013561244e9190615854565b6124589088615a74565b9650828210156124a057847fdd2523ca96a639ba7e17420698937f71eddd8af012ccb36ff5c8fe96141acae961248e8486615854565b60405190815260200160405180910390a25b8a8a878181106124b2576124b261583e565b9050602002013584600401819055508560010195505050505050612333565b509695505050505050565b7f779e5c23cb7a5bcb9bfe1e9a5165a00057f12bcdfd13e374540fdf1a1cd9113761250781336137a8565b6125118483613e8f565b60005b8481101561267b5760008484838181106125305761253061583e565b9050602002013511156126735761255e8686838181106125525761255261583e565b90506020020135613445565b6001600160a01b0316638d7e401785858481811061257e5761257e61583e565b905060200201356040518263ffffffff1660e01b81526004016125a391815260200190565b600060405180830381600087803b1580156125bd57600080fd5b505af19250505080156125ce575060015b612673573d8080156125fc576040519150601f19603f3d011682016040523d82523d6000602084013e612601565b606091505b50805161262157604051638fd297d960e01b815260040160405180910390fd5b8686838181106126335761263361583e565b905060200201357ff74208fedac7280fd11f8de0be14e00423dc5076da8e8ec8ca90e09257fff1b3826040516126699190615bce565b60405180910390a2505b600101612514565b505050505050565b6060806060600080600080612696613eb9565b805191935091508015806126a8575082155b156126ea5750506040805160008082526020820181815282840182815260608401909452919850909650909450925068056bc75e2d6310000091506129f79050565b68056bc75e2d631000009350806001600160401b0381111561270e5761270e6152a9565b604051908082528060200260200182016040528015612737578160200160208202803683370190505b509650806001600160401b03811115612752576127526152a9565b60405190808252806020026020018201604052801561277b578160200160208202803683370190505b509750806001600160401b03811115612796576127966152a9565b6040519080825280602002602001820160405280156127bf578160200160208202803683370190505b5095506000808060005b848110156129c45760008682815181106127e5576127e561583e565b602002602001015160c0015111156129bc578581815181106128095761280961583e565b60200260200101516020015162ffffff168b858151811061282c5761282c61583e565b602002602001018181525050868887838151811061284c5761284c61583e565b602002602001015160c001516128629190615ac3565b61286c919061582a565b92508581815181106128805761288061583e565b6020026020010151600001518c858151811061289e5761289e61583e565b60200260200101906001600160a01b031690816001600160a01b0316815250506127108682815181106128d3576128d361583e565b60200260200101516040015161ffff16846128ee9190615ac3565b6128f8919061582a565b9150600286828151811061290e5761290e61583e565b602002602001015160a00151600281111561292b5761292b615476565b1461296457818a85815181106129435761294361583e565b60200260200101906001600160601b031690816001600160601b0316815250505b8161271087838151811061297a5761297a61583e565b60200260200101516060015161ffff16856129959190615ac3565b61299f919061582a565b6129a99190615be1565b6129b3908a615be1565b98506001909301925b6001016127c9565b5086886001600160601b031611156129de576129de615bb8565b838310156129f057828a52828b528289525b5050505050505b9091929394565b612a06614a72565b612a12610f4e8361371f565b604080516101a081018252825462ffffff81168252630100000081046001600160a01b03166020830152600160b81b810461ffff90811693830193909352600160c81b810483166060830152600160d81b81049092166080820152600160e81b90910460ff1660a082015260018201805491929160c084019190612a95906158f8565b80601f0160208091040260200160405190810160405280929190818152602001828054612ac1906158f8565b8015612b0e5780601f10612ae357610100808354040283529160200191612b0e565b820191906000526020600020905b815481529060010190602001808311612af157829003601f168201915b505050918352505060028201546001600160401b039081166020830152600383015460408301526004830154606083015260059092015461ffff81166080830152620100008104831660a0830152600160501b900490911660c09091015292915050565b60006060612b7f836134d3565b509094909350915050565b600080516020615f71833981519152612ba381336137a8565b612baf8585858561380c565b612bb886613445565b6001600160a01b0316639b00c146868686866040518563ffffffff1660e01b8152600401610fff9493929190615894565b6000818152600080516020615f3183398151915260205260408120610df290613f87565b6000612c1b610f4e8361371f565b60050154600160501b90046001600160401b031692915050565b600080516020615f91833981519152612c4e81336137a8565b6000612c5c610f4e8561371f565b9050826002811115612c7057612c70615476565b8154600160e81b900460ff166002811115612c8d57612c8d615476565b6002811115612c9e57612c9e615476565b1415612cbd57604051635ca16fa760e11b815260040160405180910390fd5b612cc78184613f91565b50505050565b612cd682610f6c565b612ce081336137a8565b61105683836138da565b600080516020615f71833981519152612d0381336137a8565b6000612d0d611219565b905060008060005b83811015612e4457612d2681613778565b8054909350630100000090046001600160a01b031691506000612d4883613450565b505090508360040154811415612e3b57826001600160a01b031663e864299e6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612d9357600080fd5b505af1925050508015612da4575060015b612e3b573d808015612dd2576040519150601f19603f3d011682016040523d82523d6000602084013e612dd7565b606091505b508051612df757604051638fd297d960e01b815260040160405180910390fd5b845460405162ffffff909116907fe74bf895f0c3a2d6c74c40cbb362fdd9640035fc4226c72e3843809ad2a9d2b590612e31908490615bce565b60405180910390a2505b50600101612d15565b5050505050565b600080516020615f91833981519152612e6481336137a8565b612e6d84613445565b60405163a2e080f160e01b815260048101859052602481018490526001600160a01b03919091169063a2e080f190604401600060405180830381600087803b158015612eb857600080fd5b505af1158015612ecc573d6000803e3d6000fd5b5050505050505050565b60006001611572565b7fe7c742a54cd11fc9749a47ab34bdcd7327820908e8d0d48b4a5c7f17b0294098612f0a81336137a8565b612f337fabeb05279af36da5d476d7f950157cd2ea98a4166fa68a6bc97ce3a22fbb93c0839055565b6000612f3d611219565b905060005b81811015613068576000612f5582613778565b90508160010191508060000160039054906101000a90046001600160a01b03166001600160a01b03166390c09bdb6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612faf57600080fd5b505af1925050508015612fc0575060015b613062573d808015612fee576040519150601f19603f3d011682016040523d82523d6000602084013e612ff3565b606091505b50805161301357604051638fd297d960e01b815260040160405180910390fd5b61301e826001613f91565b815460405162ffffff909116907f0d64b11929aa111ca874dd00b5b0cc2d82b741be924ec9e3691e67c71552f62390613058908490615bce565b60405180910390a2505b50612f42565b50604080518481523360208201527f82e72df77173eab89b00556d791a407a78f4605c5c2f0694967c8c429dd43c7c9101611365565b60008060008060006130ae6133a2565b92506001600160601b031692506001600160601b031692506130d08382613c56565b94506130dc8282613c56565b93505050509091565b606060006130f284613445565b905082516001600160401b0381111561310d5761310d6152a9565b60405190808252806020026020018201604052801561314657816020015b613133614bf5565b81526020019060019003908161312b5790505b50915060005b83518110156132685760405180606001604052808583815181106131725761317261583e565b60200260200101518152602001836001600160a01b0316635e2fb9088785815181106131a0576131a061583e565b60200260200101516040518263ffffffff1660e01b81526004016131c691815260200190565b60206040518083038186803b1580156131de57600080fd5b505afa1580156131f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132169190615c03565b15158152602001613240878785815181106132335761323361583e565b6020026020010151612237565b8152508382815181106132555761325561583e565b602090810291909101015260010161314c565b505092915050565b6060600061327c611219565b9050806001600160401b03811115613296576132966152a9565b6040519080825280602002602001820160405280156132bf578160200160208202803683370190505b50915060005b81811015611569576132d681613778565b54835162ffffff909116908490839081106132f3576132f361583e565b60209081029190910101526001016132c5565b606061339a8461331586613445565b604051634febc81b60e01b815260048101879052602481018690526001600160a01b039190911690634febc81b9060440160006040518083038186803b15801561335e57600080fd5b505afa158015613372573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d4b9190810190615c7b565b949350505050565b6000806000606060006133b3612683565b9650909450925060009150505b82518110156133f8578281815181106133db576133db61583e565b6020026020010151866133ee9190615be1565b95506001016133c0565b506134038582615caf565b93505050909192565b9055565b60006001600160e01b03198216637965db0b60e01b1480610df257506301ffc9a760e01b6001600160e01b0319831614610df2565b6000610df282614047565b6000806000836001600160a01b0316639abddf096040518163ffffffff1660e01b815260040160606040518083038186803b15801561348e57600080fd5b505afa1580156134a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134c69190615cd7565b9250925092509193909250565b600060608060006134e2613eb9565b8051909350909150806001600160401b03811115613502576135026152a9565b60405190808252806020026020018201604052801561352b578160200160208202803683370190505b50935080156137165761353e8683615a74565b91506000816001600160401b0381111561355a5761355a6152a9565b604051908082528060200260200182016040528015613583578160200160208202803683370190505b5090506000805b8381101561367e578581815181106135a4576135a461583e565b602002602001015160c001518782815181106135c2576135c261583e565b602002602001018181525050612710858783815181106135e4576135e461583e565b60200260200101516080015161ffff166135fe9190615ac3565b613608919061582a565b9150613659828783815181106136205761362061583e565b602002602001015160e0015188848151811061363e5761363e61583e565b602002602001015160c001516136549190615a74565b61406c565b83828151811061366b5761366b61583e565b602090810291909101015260010161358a565b50604051632529fbc960e01b8152734a08c1501a886861c17341317ff7885a5a1e5db690632529fbc9906136ba90899086908d90600401615d05565b60006040518083038186803b1580156136d257600080fd5b505af41580156136e6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261370e9190810190615d3b565b909750955050505b50509193909250565b60008181527f9b48f5b32acb95b982effe269feac267eead113c4b5af14ffeb9aadac18a6e9c602081905260408220548061376d57604051636a0eb14160e11b815260040160405180910390fd5b61339a600182615854565b60009081527f1d2f69fc9b5fe89d7414bf039e8d897c4c487c7603d80de6bcdd2868466f94766020526040902090565b6137b28282611c4f565b6111fd576137ca816001600160a01b0316601461407b565b6137d583602061407b565b6040516020016137e6929190615d77565b60408051601f198184030181529082905262461bcd60e51b82526111ea91600401615bce565b613817600884615dec565b15158061382d575061382a601082615dec565b15155b1561384e576040516363209a7d60e11b8152600360048201526024016111ea565b600061385b60088561582a565b90508061386960108461582a565b1461388a576040516363209a7d60e11b8152600260048201526024016111ea565b80612e44576040516363209a7d60e11b8152600160048201526024016111ea565b6138b58282614216565b6000828152600080516020615f3183398151915260205260409020611056908261428c565b6138e482826142a1565b6000828152600080516020615f31833981519152602052604090206110569082614315565b613911611bf9565b1561392f5760405163184e52a160e21b815260040160405180910390fd5b6139388161432a565b50565b6111fd82826138ab565b600061394f611bf9565b90508082146111fd576040516303abe78360e21b815260048101829052602481018390526044016111ea565b613983611bf9565b61398e906001615a74565b811461392f5760405163167679d560e01b815260040160405180910390fd5b6127108611156139d057604051636f004ebd60e11b815260040160405180910390fd5b6127108511156139f357604051630285aacf60e31b815260040160405180910390fd5b84861115613a1457604051630285aacf60e31b815260040160405180910390fd5b612710613a218486615a74565b1115613a405760405163b65e4c5960e01b815260040160405180910390fd5b801580613a5357506001600160401b0381115b15613a71576040516309e7727560e31b815260040160405180910390fd5b6001600160401b03821115613a995760405163e747a27f60e01b815260040160405180910390fd5b875460058901805463ffffffff60c81b19909216600160d81b61ffff8a81169190910261ffff60c81b191691909117600160c81b878316021761ffff60b81b1916600160b81b88831602178b55871669ffffffffffffffffffff1990921691909117620100006001600160401b03858116919091029190911767ffffffffffffffff60501b1916600160501b918416919091021790556040805187815260208101879052339181019190915287907f1730859048adcce16559e75a58fd609e9dbf7d34f39bcb7a45ad388dfbba0e4e9060600160405180910390a260408051858152602081018590523381830152905188917f303c8ac43d1b1f9b898ddd2915a294efa01e9b07c322d7deeb7db332b66f0410919081900360600190a26040805183815233602082015288917f72766c50f14fe492bd1281ceef0a57ad49a02b7e1042fb58723647bf38040f83910160405180910390a26040805182815233602082015288917f4d106b4a7aff347abccca2dd6855d8d59d6cf792f1fdbb272c9858433d94b328910160405180910390a25050505050505050565b6000611c488383614389565b6000818311613c4f5781611c48565b5090919050565b600081613c6561271085615ac3565b611c48919061582a565b60028301805467ffffffffffffffff1916426001600160401b031617905543600384015560405181815282907f9151b7f88aca05d432bb395647ef52b2ffc454e3c6afb69c95345af6b5a778c0906020015b60405180910390a2505050565b7f9b48f5b32acb95b982effe269feac267eead113c4b5af14ffeb9aadac18a6e9c613cfa826001615a74565b600093845260209190915260409092209190915550565b613d1c846030615ac3565b825114613d52578151613d30856030615ac3565b6040516346b38e7960e11b8152600481019290925260248201526044016111ea565b613d5d846060615ac3565b815114613d93578051613d71856060615ac3565b604051633c11c1f760e21b8152600481019290925260248201526044016111ea565b6000613d9f60306143b3565b90506000613dad60606143b3565b905060005b8681101561176057613dd38584613dca603085615ac3565b600060306143cc565b613dec8483613de3606085615ac3565b600060606143cc565b7f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa6001600160a01b031663228951186801bc16d674ec800000858986613e338c8a8a614453565b6040518663ffffffff1660e01b8152600401613e529493929190615e00565b6000604051808303818588803b158015613e6b57600080fd5b505af1158015613e7f573d6000803e3d6000fd5b5050505050806001019050613db2565b8082146111fd5760405163098b37e560e31b815260048101839052602481018290526044016111ea565b600060606000613ec7611219565b9050806001600160401b03811115613ee157613ee16152a9565b604051908082528060200260200182016040528015613f1a57816020015b613f07614c14565b815260200190600190039081613eff5790505b50915060005b81811015613f8157613f31816147ce565b838281518110613f4357613f4361583e565b6020026020010181905250828181518110613f6057613f6061583e565b602002602001015160c0015184613f779190615a74565b9350600101613f20565b50509091565b6000610df2825490565b8154600090600160e81b900460ff166002811115613fb157613fb1615476565b9050816002811115613fc557613fc5615476565b816002811115613fd757613fd7615476565b1461105657816002811115613fee57613fee615476565b835460ff91909116600160e81b0260ff60e81b1982168117855560405162ffffff9182169190921617907ffd6f15fb2b48a21a60fe3d44d3c3a0433ca01e121b5124a63ec45c30ad925a1790613cc19085903390615e4b565b6000614055610f4e8361371f565b54630100000090046001600160a01b031692915050565b6000818310613c4f5781611c48565b6060600061408a836002615ac3565b614095906002615a74565b6001600160401b038111156140ac576140ac6152a9565b6040519080825280601f01601f1916602001820160405280156140d6576020820181803683370190505b509050600360fc1b816000815181106140f1576140f161583e565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106141205761412061583e565b60200101906001600160f81b031916908160001a9053506000614144846002615ac3565b61414f906001615a74565b90505b60018111156141c7576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106141835761418361583e565b1a60f81b8282815181106141995761419961583e565b60200101906001600160f81b031916908160001a90535060049490941c936141c081615e71565b9050614152565b508315611c485760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016111ea565b6142208282611c4f565b6111fd576000828152600080516020615f51833981519152602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6000611c48836001600160a01b0384166148e5565b6142ab8282611c4f565b156111fd576000828152600080516020615f51833981519152602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611c48836001600160a01b038416614934565b6143537f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6829055565b6040518181527ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9060200160405180910390a150565b60008260000182815481106143a0576143a061583e565b9060005260206000200154905092915050565b60408051828152603f92810192909201601f1916905290565b84516143d88285615a74565b111580156143f0575083516143ed8284615a74565b11155b61443c5760405162461bcd60e51b815260206004820152601960248201527f42595445535f41525241595f4f55545f4f465f424f554e44530000000000000060448201526064016111ea565b602083860181019083860101611760828285614a27565b60008061446060406143b3565b9050600061447861447360406060615854565b6143b3565b9050614489848360008060406143cc565b6144a284826040600061449d826060615854565b6143cc565b6000600286600060801b6040516020016144bd929190615e88565b60408051601f19818403018152908290526144d791615ec0565b602060405180830381855afa1580156144f4573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061451791906157e5565b905060006002808560405160200161452f9190615ec0565b60408051601f198184030181529082905261454991615ec0565b602060405180830381855afa158015614566573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061458991906157e5565b6040516002906145a0908790600090602001615ed2565b60408051601f19818403018152908290526145ba91615ec0565b602060405180830381855afa1580156145d7573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906145fa91906157e5565b60408051602081019390935282015260600160408051601f198184030181529082905261462691615ec0565b602060405180830381855afa158015614643573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061466691906157e5565b9050600280838a60405160200161467e929190615ef4565b60408051601f198184030181529082905261469891615ec0565b602060405180830381855afa1580156146b5573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906146d891906157e5565b60408051634059730760d81b60208201526000602882015290810184905260029060600160408051601f198184030181529082905261471691615ec0565b602060405180830381855afa158015614733573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061475691906157e5565b60408051602081019390935282015260600160408051601f198184030181529082905261478291615ec0565b602060405180830381855afa15801561479f573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906147c291906157e5565b98975050505050505050565b6147d6614c14565b60006147e183613778565b80546001600160a01b036301000000820416845262ffffff8116602085015261ffff600160b81b820481166040860152600160c81b820481166060860152600160d81b820416608085015290915060ff600160e81b90910416600281111561484b5761484b615476565b8260a00190600281111561486157614861615476565b9081600281111561487457614874615476565b81525050600080600061488a8560000151613450565b9194509250905060008560a0015160028111156148a9576148a9615476565b146148b55760006148b7565b805b60e086015260048401546148cc908490613c40565b6148d69083615854565b60c08601525092949350505050565b600081815260018301602052604081205461492c57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610df2565b506000610df2565b60008181526001830160205260408120548015614a1d576000614958600183615854565b855490915060009061496c90600190615854565b90508181146149d157600086600001828154811061498c5761498c61583e565b90600052602060002001549050808760000184815481106149af576149af61583e565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806149e2576149e2615f1a565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610df2565b6000915050610df2565b5b601f811115614a48578251825260209283019290910190601f1901614a28565b80156110565782518251600019600160086020869003021b01908116901991909116178252505050565b604080516101a08101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082015260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081019190915290565b60405180608001604052806000815260200160008152602001614afe614a72565b8152602001614b2760405180606001604052806000815260200160008152602001600081525090565b905290565b828054614b38906158f8565b90600052602060002090601f016020900481019282614b5a5760008555614ba0565b82601f10614b735782800160ff19823516178555614ba0565b82800160010185558215614ba0579182015b82811115614ba0578235825591602001919060010190614b85565b50614bac929150614c59565b5090565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160608101825260008082526020820152908101614b27614bb0565b604080516101008101825260008082526020820181905291810182905260608101829052608081018290529060a0820190815260200160008152602001600081525090565b5b80821115614bac5760008155600101614c5a565b600060208284031215614c8057600080fd5b81356001600160e01b031981168114611c4857600080fd5b600060208284031215614caa57600080fd5b5035919050565b81518152602080830151908201526040808301519082015260608101610df2565b60008060408385031215614ce557600080fd5b50508035926020909101359150565b60008083601f840112614d0657600080fd5b5081356001600160401b03811115614d1d57600080fd5b602083019150836020828501011115614d3557600080fd5b9250929050565b600080600080600060608688031215614d5457600080fd5b8535945060208601356001600160401b0380821115614d7257600080fd5b614d7e89838a01614cf4565b90965094506040880135915080821115614d9757600080fd5b50614da488828901614cf4565b969995985093965092949392505050565b80356001600160a01b0381168114614dcc57600080fd5b919050565b60008060408385031215614de457600080fd5b82359150614df460208401614db5565b90509250929050565b805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301525050565b602080825282518282018190526000919060409081850190868401855b82811015614ea45781518051855286810151151587860152850151614e8f86860182614dfd565b50610140939093019290850190600101614e68565b5091979650505050505050565b60008060008060008060a08789031215614eca57600080fd5b86359550602087013594506040870135935060608701356001600160401b03811115614ef557600080fd5b614f0189828a01614cf4565b979a9699509497949695608090950135949350505050565b60005b83811015614f34578181015183820152602001614f1c565b83811115612cc75750506000910152565b60008151808452614f5d816020860160208601614f19565b601f01601f19169290920160200192915050565b805162ffffff16825260006101a06020830151614f9960208601826001600160a01b03169052565b506040830151614faf604086018261ffff169052565b506060830151614fc5606086018261ffff169052565b506080830151614fdb608086018261ffff169052565b5060a0830151614ff060a086018260ff169052565b5060c08301518160c086015261500882860182614f45565b91505060e083015161502560e08601826001600160401b03169052565b50610100838101519085015261012080840151908501526101408084015161ffff1690850152610160808401516001600160401b0390811691860191909152610180938401511692909301919091525090565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561510f57603f19898403018552815160c08151855288820151898601528782015181898701526150d582870182614f71565b60609384015180518886015260208101516080890152604081015160a089015293909250905050958801959350509086019060010161509f565b509098975050505050505050565b60008060006060848603121561513257600080fd5b61513b84614db5565b925061514960208501614db5565b9150604084013590509250925092565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156151ae57603f1988860301845261519c858351614f71565b94509285019290850190600101615180565b5092979650505050505050565b60008083601f8401126151cd57600080fd5b5081356001600160401b038111156151e457600080fd5b6020830191508360208260051b8501011115614d3557600080fd5b6000806000806060858703121561521557600080fd5b84356001600160401b0381111561522b57600080fd5b615237878288016151bb565b90989097506020870135966040013595509350505050565b600080600080600080600060e0888a03121561526a57600080fd5b505085359760208701359750604087013596606081013596506080810135955060a0810135945060c0013592509050565b801515811461393857600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156152e7576152e76152a9565b604052919050565b60008060008084860360e081121561530657600080fd5b8535945060208601359350604086013561531f8161529b565b92506080605f198201121561533357600080fd5b50604051608081018181106001600160401b0382111715615356576153566152a9565b8060405250606086013581526080860135602082015260a0860135604082015260c086013560608201528091505092959194509250565b60006001600160401b038211156153a6576153a66152a9565b5060051b60200190565b600082601f8301126153c157600080fd5b813560206153d66153d18361538d565b6152bf565b82815260059290921b840181019181810190868411156153f557600080fd5b8286015b848110156124d157803583529183019183016153f9565b60006020828403121561542257600080fd5b81356001600160401b0381111561543857600080fd5b61339a848285016153b0565b6000806000806080858703121561545a57600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052602160045260246000fd5b600381106154aa57634e487b7160e01b600052602160045260246000fd5b9052565b60208101610df2828461548c565b60008060008060008060008060006101008a8c0312156154db57600080fd5b89356001600160401b038111156154f157600080fd5b6154fd8c828d01614cf4565b909a509850615510905060208b01614db5565b989b979a509798604081013598506060810135976080820135975060a0820135965060c0820135955060e0909101359350915050565b6000806000806060858703121561555c57600080fd5b843593506020850135925060408501356001600160401b0381111561558057600080fd5b61558c87828801614cf4565b95989497509550505050565b6101008101610df28284614dfd565b600080600080604085870312156155bd57600080fd5b84356001600160401b03808211156155d457600080fd5b6155e0888389016151bb565b909650945060208701359150808211156155f957600080fd5b5061558c878288016151bb565b600081518084526020808501945080840160005b838110156156365781518752958201959082019060010161561a565b509495945050505050565b60a0808252865190820181905260009060209060c0840190828a01845b828110156156835781516001600160a01b03168452928401929084019060010161565e565b505050838103828501526156978189615606565b8481036040860152875180825283890192509083019060005b818110156156d55783516001600160601b0316835292840192918401916001016156b0565b50506001600160601b038716606086015292506156f0915050565b8260808301529695505050505050565b602081526000611c486020830184614f71565b82815260406020820152600061339a6040830184615606565b6000806040838503121561573f57600080fd5b8235915060208301356003811061575557600080fd5b809150509250929050565b60008060006060848603121561577557600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561579f57600080fd5b8235915060208301356001600160401b038111156157bc57600080fd5b6157c8858286016153b0565b9150509250929050565b602081526000611c486020830184615606565b6000602082840312156157f757600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082615839576158396157fe565b500490565b634e487b7160e01b600052603260045260246000fd5b60008282101561586657615866615814565b500390565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6040815260006158a860408301868861586b565b82810360208401526158bb81858761586b565b979650505050505050565b8581528460208201526080604082015260006158e660808301858761586b565b90508260608301529695505050505050565b600181811c9082168061590c57607f821691505b60208210811415611bf357634e487b7160e01b600052602260045260246000fd5b60008235605e1983360301811261594357600080fd5b9190910192915050565b6000808335601e1984360301811261596457600080fd5b8301803591506001600160401b0382111561597e57600080fd5b602001915036819003821315614d3557600080fd5b8581526080602082015260006159ad60808301868861586b565b604083019490945250606001529392505050565b60208152600061339a60208301848661586b565b60006000198214156159e9576159e9615814565b5060010190565b600080600080600080600080610100898b031215615a0d57600080fd5b505086516020880151604089015160608a015160808b015160a08c015160c08d015160e0909d0151959e949d50929b919a50985090965094509092509050565b600062ffffff808316818516808303821115615a6b57615a6b615814565b01949350505050565b60008219821115615a8757615a87615814565b500190565b600060018060a01b03808716835260606020840152615aaf60608401868861586b565b915080841660408401525095945050505050565b6000816000190483118215151615615add57615add615814565b500290565b838152604060208201526000611cd660408301848661586b565b600082601f830112615b0d57600080fd5b81516001600160401b03811115615b2657615b266152a9565b615b39601f8201601f19166020016152bf565b818152846020838601011115615b4e57600080fd5b61339a826020830160208701614f19565b60008060408385031215615b7257600080fd5b82516001600160401b0380821115615b8957600080fd5b615b9586838701615afc565b93506020850151915080821115615bab57600080fd5b506157c885828601615afc565b634e487b7160e01b600052600160045260246000fd5b602081526000611c486020830184614f45565b60006001600160601b03808316818516808303821115615a6b57615a6b615814565b600060208284031215615c1557600080fd5b8151611c488161529b565b600082601f830112615c3157600080fd5b81516020615c416153d18361538d565b82815260059290921b84018101918181019086841115615c6057600080fd5b8286015b848110156124d15780518352918301918301615c64565b600060208284031215615c8d57600080fd5b81516001600160401b03811115615ca357600080fd5b61339a84828501615c20565b60006001600160601b0383811690831681811015615ccf57615ccf615814565b039392505050565b600080600060608486031215615cec57600080fd5b8351925060208401519150604084015190509250925092565b606081526000615d186060830186615606565b8281036020840152615d2a8186615606565b915050826040830152949350505050565b60008060408385031215615d4e57600080fd5b8251915060208301516001600160401b03811115615d6b57600080fd5b6157c885828601615c20565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615daf816017850160208801614f19565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615de0816028840160208801614f19565b01602801949350505050565b600082615dfb57615dfb6157fe565b500690565b608081526000615e136080830187614f45565b8281036020840152615e258187614f45565b90508281036040840152615e398186614f45565b91505082606083015295945050505050565b60408101615e59828561548c565b6001600160a01b039290921660209190910152919050565b600081615e8057615e80615814565b506000190190565b60008351615e9a818460208801614f19565b6fffffffffffffffffffffffffffffffff19939093169190920190815260100192915050565b60008251615943818460208701614f19565b60008351615ee4818460208801614f19565b9190910191825250602001919050565b82815260008251615f0c816020850160208701614f19565b919091016020019392505050565b634e487b7160e01b600052603160045260246000fdfe8f8c450dae5029cd48cd91dd9db65da48fb742893edfc7941250f6721d93cbbe9a627a5d4aa7c17f87ff26e3fe9a42c2b6c559e8b41a42282d0ecebb17c0e4d3c23292b191d95d2a7dd94fc6436eb44338fda9e1307d9394fd27c28157c1b33c3105bcbf19d4417b73ae0e58d508a65ecf75665e46c2622d8521732de6080c48a264697066735822122075326e39f348a71e5550c61485363bae72b2ff45d197d8b5ee464d943f1ad6f464736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa
-----Decoded View---------------
Arg [0] : _depositContract (address): 0x00000000219ab540356cBB839Cbe05303d7705Fa
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.