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 Exited And St... | 745593 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745593 | 202 days ago | 0 ETH | ||||
| On Exited And St... | 745593 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745593 | 202 days ago | 0 ETH | ||||
| On Rewards Minte... | 745586 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745586 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745586 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745586 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745586 | 202 days ago | 0 ETH | ||||
| On Exited And St... | 745242 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745242 | 202 days ago | 0 ETH | ||||
| On Exited And St... | 745242 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745242 | 202 days ago | 0 ETH | ||||
| On Rewards Minte... | 745235 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745235 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745235 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745235 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 745235 | 202 days ago | 0 ETH | ||||
| On Exited And St... | 744527 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 744527 | 202 days ago | 0 ETH | ||||
| On Exited And St... | 744527 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 744527 | 202 days ago | 0 ETH | ||||
| On Rewards Minte... | 744520 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 744520 | 202 days ago | 0 ETH | ||||
| Get Staking Modu... | 744520 | 202 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:
NodeOperatorsRegistry
Compiler Version
v0.4.24+commit.e67f0147
Optimization Enabled:
Yes with 200 runs
Other Settings:
constantinople EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 // See contracts/COMPILERS.md pragma solidity 0.4.24; import {AragonApp} from "@aragon/os/contracts/apps/AragonApp.sol"; import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol"; import {UnstructuredStorage} from "@aragon/os/contracts/common/UnstructuredStorage.sol"; import {Math256} from "../../common/lib/Math256.sol"; import {MinFirstAllocationStrategy} from "../../common/lib/MinFirstAllocationStrategy.sol"; import {ILidoLocator} from "../../common/interfaces/ILidoLocator.sol"; import {IBurner} from "../../common/interfaces/IBurner.sol"; import {SigningKeys} from "../lib/SigningKeys.sol"; import {Packed64x4} from "../lib/Packed64x4.sol"; import {Versioned} from "../utils/Versioned.sol"; interface IStETH { function sharesOf(address _account) external view returns (uint256); function transferShares(address _recipient, uint256 _sharesAmount) external returns (uint256); function approve(address _spender, uint256 _amount) external returns (bool); } /// @title Node Operator registry /// @notice Node Operator registry manages signing keys and other node operator data. /// @dev Must implement the full version of IStakingModule interface, not only the one declared locally. /// It's also responsible for distributing rewards to node operators. /// NOTE: the code below assumes moderate amount of node operators, i.e. up to `MAX_NODE_OPERATORS_COUNT`. contract NodeOperatorsRegistry is AragonApp, Versioned { using SafeMath for uint256; using UnstructuredStorage for bytes32; using SigningKeys for bytes32; using Packed64x4 for Packed64x4.Packed; // // EVENTS // event NodeOperatorAdded(uint256 nodeOperatorId, string name, address rewardAddress, uint64 stakingLimit); event NodeOperatorActiveSet(uint256 indexed nodeOperatorId, bool active); event NodeOperatorNameSet(uint256 indexed nodeOperatorId, string name); event NodeOperatorRewardAddressSet(uint256 indexed nodeOperatorId, address rewardAddress); event NodeOperatorTotalKeysTrimmed(uint256 indexed nodeOperatorId, uint64 totalKeysTrimmed); event KeysOpIndexSet(uint256 keysOpIndex); event StakingModuleTypeSet(bytes32 moduleType); event RewardsDistributed(address indexed rewardAddress, uint256 sharesAmount); event RewardDistributionStateChanged(RewardDistributionState state); event LocatorContractSet(address locatorAddress); event VettedSigningKeysCountChanged(uint256 indexed nodeOperatorId, uint256 approvedValidatorsCount); event DepositedSigningKeysCountChanged(uint256 indexed nodeOperatorId, uint256 depositedValidatorsCount); event ExitedSigningKeysCountChanged(uint256 indexed nodeOperatorId, uint256 exitedValidatorsCount); event TotalSigningKeysCountChanged(uint256 indexed nodeOperatorId, uint256 totalValidatorsCount); event NonceChanged(uint256 nonce); event StuckPenaltyDelayChanged(uint256 stuckPenaltyDelay); event StuckPenaltyStateChanged( uint256 indexed nodeOperatorId, uint256 stuckValidatorsCount, uint256 refundedValidatorsCount, uint256 stuckPenaltyEndTimestamp ); event TargetValidatorsCountChanged(uint256 indexed nodeOperatorId, uint256 targetValidatorsCount, uint256 targetLimitMode); event NodeOperatorPenalized(address indexed recipientAddress, uint256 sharesPenalizedAmount); event NodeOperatorPenaltyCleared(uint256 indexed nodeOperatorId); // Enum to represent the state of the reward distribution process enum RewardDistributionState { TransferredToModule, // New reward portion minted and transferred to the module ReadyForDistribution, // Operators' statistics updated, reward ready for distribution Distributed // Reward distributed among operators } // // ACL // // bytes32 public constant MANAGE_SIGNING_KEYS = keccak256("MANAGE_SIGNING_KEYS"); bytes32 public constant MANAGE_SIGNING_KEYS = 0x75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee; // bytes32 public constant SET_NODE_OPERATOR_LIMIT_ROLE = keccak256("SET_NODE_OPERATOR_LIMIT_ROLE"); bytes32 public constant SET_NODE_OPERATOR_LIMIT_ROLE = 0x07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d794754; // bytes32 public constant ACTIVATE_NODE_OPERATOR_ROLE = keccak256("MANAGE_NODE_OPERATOR_ROLE"); bytes32 public constant MANAGE_NODE_OPERATOR_ROLE = 0x78523850fdd761612f46e844cf5a16bda6b3151d6ae961fd7e8e7b92bfbca7f8; // bytes32 public constant STAKING_ROUTER_ROLE = keccak256("STAKING_ROUTER_ROLE"); bytes32 public constant STAKING_ROUTER_ROLE = 0xbb75b874360e0bfd87f964eadd8276d8efb7c942134fc329b513032d0803e0c6; // // CONSTANTS // uint256 public constant MAX_NODE_OPERATORS_COUNT = 200; uint256 public constant MAX_NODE_OPERATOR_NAME_LENGTH = 255; uint256 public constant MAX_STUCK_PENALTY_DELAY = 365 days; uint256 internal constant UINT64_MAX = 0xFFFFFFFFFFFFFFFF; // SigningKeysStats /// @dev Operator's max validator keys count approved for deposit by the DAO uint8 internal constant TOTAL_VETTED_KEYS_COUNT_OFFSET = 0; /// @dev Number of keys in the EXITED state of this operator for all time uint8 internal constant TOTAL_EXITED_KEYS_COUNT_OFFSET = 1; /// @dev Total number of keys of this operator for all time uint8 internal constant TOTAL_KEYS_COUNT_OFFSET = 2; /// @dev Number of keys of this operator which were in DEPOSITED state for all time uint8 internal constant TOTAL_DEPOSITED_KEYS_COUNT_OFFSET = 3; // TargetValidatorsStats /// @dev Target limit mode, allows limiting target active validators count for operator (0 = disabled, 1 = soft mode, 2 = forced mode) uint8 internal constant TARGET_LIMIT_MODE_OFFSET = 0; /// @dev relative target active validators limit for operator, set by DAO /// @notice used to check how many keys should go to exit, 0 - means all deposited keys would be exited uint8 internal constant TARGET_VALIDATORS_COUNT_OFFSET = 1; /// @dev actual operators's number of keys which could be deposited uint8 internal constant MAX_VALIDATORS_COUNT_OFFSET = 2; // StuckPenaltyStats /// @dev stuck keys count from oracle report uint8 internal constant STUCK_VALIDATORS_COUNT_OFFSET = 0; /// @dev refunded keys count from dao uint8 internal constant REFUNDED_VALIDATORS_COUNT_OFFSET = 1; /// @dev extra penalty time after stuck keys resolved (refunded and/or exited) /// @notice field is also used as flag for "half-cleaned" penalty status /// Operator is PENALIZED if `STUCK_VALIDATORS_COUNT > REFUNDED_VALIDATORS_COUNT` or /// `STUCK_VALIDATORS_COUNT <= REFUNDED_VALIDATORS_COUNT && STUCK_PENALTY_END_TIMESTAMP <= refund timestamp + STUCK_PENALTY_DELAY` /// When operator refund all stuck validators and time has pass STUCK_PENALTY_DELAY, but STUCK_PENALTY_END_TIMESTAMP not zeroed, /// then Operator can receive rewards but can't get new deposits until the new Oracle report or `clearNodeOperatorPenalty` is called. uint8 internal constant STUCK_PENALTY_END_TIMESTAMP_OFFSET = 2; // Summary SigningKeysStats uint8 internal constant SUMMARY_MAX_VALIDATORS_COUNT_OFFSET = 0; /// @dev Number of keys of all operators which were in the EXITED state for all time uint8 internal constant SUMMARY_EXITED_KEYS_COUNT_OFFSET = 1; /// @dev [deprecated] Total number of keys of all operators for all time uint8 internal constant SUMMARY_TOTAL_KEYS_COUNT_OFFSET = 2; /// @dev Number of keys of all operators which were in the DEPOSITED state for all time uint8 internal constant SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET = 3; // // UNSTRUCTURED STORAGE POSITIONS // // bytes32 internal constant SIGNING_KEYS_MAPPING_NAME = keccak256("lido.NodeOperatorsRegistry.signingKeysMappingName"); bytes32 internal constant SIGNING_KEYS_MAPPING_NAME = 0xeb2b7ad4d8ce5610cfb46470f03b14c197c2b751077c70209c5d0139f7c79ee9; // bytes32 internal constant LIDO_LOCATOR_POSITION = keccak256("lido.NodeOperatorsRegistry.lidoLocator"); bytes32 internal constant LIDO_LOCATOR_POSITION = 0xfb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d03537; /// @dev Total number of operators // bytes32 internal constant TOTAL_OPERATORS_COUNT_POSITION = keccak256("lido.NodeOperatorsRegistry.totalOperatorsCount"); bytes32 internal constant TOTAL_OPERATORS_COUNT_POSITION = 0xe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e8; /// @dev Cached number of active operators // bytes32 internal constant ACTIVE_OPERATORS_COUNT_POSITION = keccak256("lido.NodeOperatorsRegistry.activeOperatorsCount"); bytes32 internal constant ACTIVE_OPERATORS_COUNT_POSITION = 0x6f5220989faafdc182d508d697678366f4e831f5f56166ad69bfc253fc548fb1; /// @dev link to the index of operations with keys // bytes32 internal constant KEYS_OP_INDEX_POSITION = keccak256("lido.NodeOperatorsRegistry.keysOpIndex"); bytes32 internal constant KEYS_OP_INDEX_POSITION = 0xcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e; /// @dev module type // bytes32 internal constant TYPE_POSITION = keccak256("lido.NodeOperatorsRegistry.type"); bytes32 internal constant TYPE_POSITION = 0xbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d0; // bytes32 internal constant STUCK_PENALTY_DELAY_POSITION = keccak256("lido.NodeOperatorsRegistry.stuckPenaltyDelay"); bytes32 internal constant STUCK_PENALTY_DELAY_POSITION = 0x8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e; // bytes32 internal constant REWARD_DISTRIBUTION_STATE = keccak256("lido.NodeOperatorsRegistry.rewardDistributionState"); bytes32 internal constant REWARD_DISTRIBUTION_STATE = 0x4ddbb0dcdc5f7692e494c15a7fca1f9eb65f31da0b5ce1c3381f6a1a1fd579b6; // // DATA TYPES // /// @dev Node Operator parameters and internal state struct NodeOperator { /// @dev Flag indicating if the operator can participate in further staking and reward distribution bool active; /// @dev Ethereum address on Execution Layer which receives stETH rewards for this operator address rewardAddress; /// @dev Human-readable name string name; /// @dev The below variables store the signing keys info of the node operator. /// signingKeysStats - contains packed variables: uint64 exitedSigningKeysCount, uint64 depositedSigningKeysCount, /// uint64 vettedSigningKeysCount, uint64 totalSigningKeysCount /// /// These variables can take values in the following ranges: /// /// 0 <= exitedSigningKeysCount <= depositedSigningKeysCount /// exitedSigningKeysCount <= depositedSigningKeysCount <= vettedSigningKeysCount /// depositedSigningKeysCount <= vettedSigningKeysCount <= totalSigningKeysCount /// depositedSigningKeysCount <= totalSigningKeysCount <= UINT64_MAX /// /// Additionally, the exitedSigningKeysCount and depositedSigningKeysCount values are monotonically increasing: /// : : : : : /// [....exitedSigningKeysCount....]-------->: : : /// [....depositedSigningKeysCount :.........]-------->: : /// [....vettedSigningKeysCount....:.........:<--------]-------->: /// [....totalSigningKeysCount.....:.........:<--------:---------]-------> /// : : : : : Packed64x4.Packed signingKeysStats; Packed64x4.Packed stuckPenaltyStats; Packed64x4.Packed targetValidatorsStats; } struct NodeOperatorSummary { Packed64x4.Packed summarySigningKeysStats; } // // STORAGE VARIABLES // /// @dev Mapping of all node operators. Mapping is used to be able to extend the struct. mapping(uint256 => NodeOperator) internal _nodeOperators; NodeOperatorSummary internal _nodeOperatorSummary; // // METHODS // function initialize(address _locator, bytes32 _type, uint256 _stuckPenaltyDelay) public onlyInit { // Initializations for v1 --> v2 _initialize_v2(_locator, _type, _stuckPenaltyDelay); // Initializations for v2 --> v3 _initialize_v3(); initialized(); } /// @notice A function to finalize upgrade to v2 (from v1). Can be called only once /// For more details see https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-10.md function finalizeUpgrade_v2(address _locator, bytes32 _type, uint256 _stuckPenaltyDelay) external { require(hasInitialized(), "CONTRACT_NOT_INITIALIZED"); _checkContractVersion(0); _initialize_v2(_locator, _type, _stuckPenaltyDelay); uint256 totalOperators = getNodeOperatorsCount(); Packed64x4.Packed memory signingKeysStats; Packed64x4.Packed memory operatorTargetStats; Packed64x4.Packed memory summarySigningKeysStats = Packed64x4.Packed(0); uint256 vettedSigningKeysCountBefore; uint256 totalSigningKeysCount; uint256 depositedSigningKeysCount; for (uint256 nodeOperatorId; nodeOperatorId < totalOperators; ++nodeOperatorId) { signingKeysStats = _loadOperatorSigningKeysStats(nodeOperatorId); vettedSigningKeysCountBefore = signingKeysStats.get(TOTAL_VETTED_KEYS_COUNT_OFFSET); totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); depositedSigningKeysCount = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); uint256 vettedSigningKeysCountAfter; if (!_nodeOperators[nodeOperatorId].active) { // trim vetted signing keys count when node operator is not active vettedSigningKeysCountAfter = depositedSigningKeysCount; } else { vettedSigningKeysCountAfter = Math256.min( totalSigningKeysCount, Math256.max(depositedSigningKeysCount, vettedSigningKeysCountBefore) ); } if (vettedSigningKeysCountBefore != vettedSigningKeysCountAfter) { signingKeysStats.set(TOTAL_VETTED_KEYS_COUNT_OFFSET, vettedSigningKeysCountAfter); _saveOperatorSigningKeysStats(nodeOperatorId, signingKeysStats); emit VettedSigningKeysCountChanged(nodeOperatorId, vettedSigningKeysCountAfter); } operatorTargetStats = _loadOperatorTargetValidatorsStats(nodeOperatorId); operatorTargetStats.set(MAX_VALIDATORS_COUNT_OFFSET, vettedSigningKeysCountAfter); _saveOperatorTargetValidatorsStats(nodeOperatorId, operatorTargetStats); summarySigningKeysStats.add(SUMMARY_MAX_VALIDATORS_COUNT_OFFSET, vettedSigningKeysCountAfter); summarySigningKeysStats.add(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET, depositedSigningKeysCount); summarySigningKeysStats.add( SUMMARY_EXITED_KEYS_COUNT_OFFSET, signingKeysStats.get(TOTAL_EXITED_KEYS_COUNT_OFFSET) ); } _saveSummarySigningKeysStats(summarySigningKeysStats); _increaseValidatorsKeysNonce(); } function _initialize_v2(address _locator, bytes32 _type, uint256 _stuckPenaltyDelay) internal { _onlyNonZeroAddress(_locator); LIDO_LOCATOR_POSITION.setStorageAddress(_locator); TYPE_POSITION.setStorageBytes32(_type); _setContractVersion(2); _setStuckPenaltyDelay(_stuckPenaltyDelay); // set unlimited allowance for burner from staking router // to burn stuck keys penalized shares IStETH(getLocator().lido()).approve(getLocator().burner(), ~uint256(0)); emit LocatorContractSet(_locator); emit StakingModuleTypeSet(_type); } function finalizeUpgrade_v3() external { require(hasInitialized(), "CONTRACT_NOT_INITIALIZED"); _checkContractVersion(2); _initialize_v3(); // clear deprecated total keys count storage Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); summarySigningKeysStats.set(SUMMARY_TOTAL_KEYS_COUNT_OFFSET, 0); _saveSummarySigningKeysStats(summarySigningKeysStats); } function _initialize_v3() internal { _setContractVersion(3); _updateRewardDistributionState(RewardDistributionState.Distributed); } /// @notice Add node operator named `name` with reward address `rewardAddress` and staking limit = 0 validators /// @param _name Human-readable name /// @param _rewardAddress Ethereum 1 address which receives stETH rewards for this operator /// @return id a unique key of the added operator function addNodeOperator(string _name, address _rewardAddress) external returns (uint256 id) { _onlyValidNodeOperatorName(_name); _onlyValidRewardAddress(_rewardAddress); _auth(MANAGE_NODE_OPERATOR_ROLE); id = getNodeOperatorsCount(); require(id < MAX_NODE_OPERATORS_COUNT, "MAX_OPERATORS_COUNT_EXCEEDED"); TOTAL_OPERATORS_COUNT_POSITION.setStorageUint256(id + 1); NodeOperator storage operator = _nodeOperators[id]; uint256 activeOperatorsCount = getActiveNodeOperatorsCount(); ACTIVE_OPERATORS_COUNT_POSITION.setStorageUint256(activeOperatorsCount + 1); operator.active = true; operator.name = _name; operator.rewardAddress = _rewardAddress; emit NodeOperatorAdded(id, _name, _rewardAddress, 0); } /// @notice Activates deactivated node operator with given id /// @param _nodeOperatorId Node operator id to activate function activateNodeOperator(uint256 _nodeOperatorId) external { _onlyExistedNodeOperator(_nodeOperatorId); _auth(MANAGE_NODE_OPERATOR_ROLE); _onlyCorrectNodeOperatorState(!getNodeOperatorIsActive(_nodeOperatorId)); ACTIVE_OPERATORS_COUNT_POSITION.setStorageUint256(getActiveNodeOperatorsCount() + 1); _nodeOperators[_nodeOperatorId].active = true; emit NodeOperatorActiveSet(_nodeOperatorId, true); _increaseValidatorsKeysNonce(); } /// @notice Deactivates active node operator with given id /// @param _nodeOperatorId Node operator id to deactivate function deactivateNodeOperator(uint256 _nodeOperatorId) external { _onlyExistedNodeOperator(_nodeOperatorId); _auth(MANAGE_NODE_OPERATOR_ROLE); _onlyCorrectNodeOperatorState(getNodeOperatorIsActive(_nodeOperatorId)); uint256 activeOperatorsCount = getActiveNodeOperatorsCount(); ACTIVE_OPERATORS_COUNT_POSITION.setStorageUint256(activeOperatorsCount.sub(1)); _nodeOperators[_nodeOperatorId].active = false; emit NodeOperatorActiveSet(_nodeOperatorId, false); Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); uint256 vettedSigningKeysCount = signingKeysStats.get(TOTAL_VETTED_KEYS_COUNT_OFFSET); uint256 depositedSigningKeysCount = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); // reset vetted keys count to the deposited validators count if (vettedSigningKeysCount > depositedSigningKeysCount) { signingKeysStats.set(TOTAL_VETTED_KEYS_COUNT_OFFSET, depositedSigningKeysCount); _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); emit VettedSigningKeysCountChanged(_nodeOperatorId, depositedSigningKeysCount); _updateSummaryMaxValidatorsCount(_nodeOperatorId); } _increaseValidatorsKeysNonce(); } /// @notice Change human-readable name of the node operator with given id /// @param _nodeOperatorId Node operator id to set name for /// @param _name New human-readable name of the node operator function setNodeOperatorName(uint256 _nodeOperatorId, string _name) external { _onlyValidNodeOperatorName(_name); _onlyExistedNodeOperator(_nodeOperatorId); _auth(MANAGE_NODE_OPERATOR_ROLE); _requireNotSameValue(keccak256(bytes(_nodeOperators[_nodeOperatorId].name)) != keccak256(bytes(_name))); _nodeOperators[_nodeOperatorId].name = _name; emit NodeOperatorNameSet(_nodeOperatorId, _name); } /// @notice Change reward address of the node operator with given id /// @param _nodeOperatorId Node operator id to set reward address for /// @param _rewardAddress Execution layer Ethereum address to set as reward address function setNodeOperatorRewardAddress(uint256 _nodeOperatorId, address _rewardAddress) external { _onlyValidRewardAddress(_rewardAddress); _onlyExistedNodeOperator(_nodeOperatorId); _auth(MANAGE_NODE_OPERATOR_ROLE); _requireNotSameValue(_nodeOperators[_nodeOperatorId].rewardAddress != _rewardAddress); _nodeOperators[_nodeOperatorId].rewardAddress = _rewardAddress; emit NodeOperatorRewardAddressSet(_nodeOperatorId, _rewardAddress); } /// @notice Set the maximum number of validators to stake for the node operator with given id /// @dev Current implementation preserves invariant: depositedSigningKeysCount <= vettedSigningKeysCount <= totalSigningKeysCount. /// If _vettedSigningKeysCount out of range [depositedSigningKeysCount, totalSigningKeysCount], the new vettedSigningKeysCount /// value will be set to the nearest range border. /// @param _nodeOperatorId Node operator id to set staking limit for /// @param _vettedSigningKeysCount New staking limit of the node operator function setNodeOperatorStakingLimit(uint256 _nodeOperatorId, uint64 _vettedSigningKeysCount) external { _onlyExistedNodeOperator(_nodeOperatorId); _authP(SET_NODE_OPERATOR_LIMIT_ROLE, arr(uint256(_nodeOperatorId), uint256(_vettedSigningKeysCount))); _onlyCorrectNodeOperatorState(getNodeOperatorIsActive(_nodeOperatorId)); _updateVettedSigningKeysCount(_nodeOperatorId, _vettedSigningKeysCount, true /* _allowIncrease */); _increaseValidatorsKeysNonce(); } /// @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 _nodeOperatorIds, bytes _vettedSigningKeysCounts ) external { _auth(STAKING_ROUTER_ROLE); uint256 nodeOperatorsCount = _checkReportPayload(_nodeOperatorIds.length, _vettedSigningKeysCounts.length); uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); uint256 nodeOperatorId; uint256 vettedKeysCount; uint256 _nodeOperatorIdsOffset; uint256 _vettedKeysCountsOffset; /// @dev calldata layout: /// | func sig (4 bytes) | ABI-enc data | /// /// ABI-enc data: /// /// | 32 bytes | 32 bytes | 32 bytes | ... | 32 bytes | ...... | /// | ids len offset | counts len offset | ids len | ids | counts len | counts | assembly { _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) _vettedKeysCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot)) } for (uint256 i; i < nodeOperatorsCount;) { /// @solidity memory-safe-assembly assembly { nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) vettedKeysCount := shr(128, calldataload(add(_vettedKeysCountsOffset, mul(i, 16)))) i := add(i, 1) } _requireValidRange(nodeOperatorId < totalNodeOperatorsCount); _updateVettedSigningKeysCount(nodeOperatorId, vettedKeysCount, false /* only decrease */); } _increaseValidatorsKeysNonce(); } function _updateVettedSigningKeysCount( uint256 _nodeOperatorId, uint256 _vettedSigningKeysCount, bool _allowIncrease ) internal { Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); uint256 vettedSigningKeysCountBefore = signingKeysStats.get(TOTAL_VETTED_KEYS_COUNT_OFFSET); uint256 depositedSigningKeysCount = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); uint256 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); uint256 vettedSigningKeysCountAfter = Math256.min( totalSigningKeysCount, Math256.max(_vettedSigningKeysCount, depositedSigningKeysCount) ); if (vettedSigningKeysCountAfter == vettedSigningKeysCountBefore) return; require( _allowIncrease || vettedSigningKeysCountAfter < vettedSigningKeysCountBefore, "VETTED_KEYS_COUNT_INCREASED" ); signingKeysStats.set(TOTAL_VETTED_KEYS_COUNT_OFFSET, vettedSigningKeysCountAfter); _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); emit VettedSigningKeysCountChanged(_nodeOperatorId, vettedSigningKeysCountAfter); _updateSummaryMaxValidatorsCount(_nodeOperatorId); } /// @notice Called by StakingRouter to signal that stETH rewards were minted for this module. function onRewardsMinted(uint256 /* _totalShares */) external { _auth(STAKING_ROUTER_ROLE); _updateRewardDistributionState(RewardDistributionState.TransferredToModule); } function _checkReportPayload(uint256 idsLength, uint256 countsLength) internal pure returns (uint256 count) { count = idsLength / 8; require(countsLength / 16 == count && idsLength % 8 == 0 && countsLength % 16 == 0, "INVALID_REPORT_DATA"); } /// @notice Called by StakingRouter to update the number of the validators of the given node /// operator that were requested to exit but failed to do so in the max allowed time /// /// @param _nodeOperatorIds bytes packed array of the node operators id /// @param _stuckValidatorsCounts bytes packed array of the new number of stuck validators for the node operators function updateStuckValidatorsCount(bytes _nodeOperatorIds, bytes _stuckValidatorsCounts) external { _auth(STAKING_ROUTER_ROLE); uint256 nodeOperatorsCount = _checkReportPayload(_nodeOperatorIds.length, _stuckValidatorsCounts.length); uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); uint256 nodeOperatorId; uint256 validatorsCount; uint256 _nodeOperatorIdsOffset; uint256 _stuckValidatorsCountsOffset; /// @dev calldata layout: /// | func sig (4 bytes) | ABI-enc data | /// /// ABI-enc data: /// /// | 32 bytes | 32 bytes | 32 bytes | ... | 32 bytes | ...... | /// | ids len offset | counts len offset | ids len | ids | counts len | counts | assembly { _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) _stuckValidatorsCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot)) } for (uint256 i; i < nodeOperatorsCount;) { /// @solidity memory-safe-assembly assembly { nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) validatorsCount := shr(128, calldataload(add(_stuckValidatorsCountsOffset, mul(i, 16)))) i := add(i, 1) } _requireValidRange(nodeOperatorId < totalNodeOperatorsCount); _updateStuckValidatorsCount(nodeOperatorId, validatorsCount); } _increaseValidatorsKeysNonce(); } /// @notice Called by StakingRouter to update 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 _nodeOperatorIds, bytes _exitedValidatorsCounts ) external { _auth(STAKING_ROUTER_ROLE); uint256 nodeOperatorsCount = _checkReportPayload(_nodeOperatorIds.length, _exitedValidatorsCounts.length); uint256 totalNodeOperatorsCount = getNodeOperatorsCount(); uint256 nodeOperatorId; uint256 validatorsCount; uint256 _nodeOperatorIdsOffset; uint256 _exitedValidatorsCountsOffset; /// @dev see comments for `updateStuckValidatorsCount` assembly { _nodeOperatorIdsOffset := add(calldataload(4), 36) // arg1 calldata offset + 4 (signature len) + 32 (length slot) _exitedValidatorsCountsOffset := add(calldataload(36), 36) // arg2 calldata offset + 4 (signature len) + 32 (length slot)) } for (uint256 i; i < nodeOperatorsCount;) { /// @solidity memory-safe-assembly assembly { nodeOperatorId := shr(192, calldataload(add(_nodeOperatorIdsOffset, mul(i, 8)))) validatorsCount := shr(128, calldataload(add(_exitedValidatorsCountsOffset, mul(i, 16)))) i := add(i, 1) } _requireValidRange(nodeOperatorId < totalNodeOperatorsCount); _updateExitedValidatorsCount(nodeOperatorId, validatorsCount, false); } _increaseValidatorsKeysNonce(); } /// @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 { _onlyExistedNodeOperator(_nodeOperatorId); _auth(STAKING_ROUTER_ROLE); _updateRefundValidatorsKeysCount(_nodeOperatorId, _refundedValidatorsCount); _increaseValidatorsKeysNonce(); } /// @notice Permissionless method for distributing all accumulated module rewards among node operators /// based on the latest accounting report. /// /// @dev Rewards can be distributed after all necessary data required to distribute rewards among operators /// has been delivered, including exited and stuck keys. /// /// The reward distribution lifecycle: /// /// 1. TransferredToModule: Rewards are transferred to the module during an oracle main report. /// 2. ReadyForDistribution: All necessary data required to distribute rewards among operators has been delivered. /// 3. Distributed: Rewards have been successfully distributed. /// /// The function can only be called when the state is ReadyForDistribution. /// /// @dev Rewards can be distributed after node operators' statistics are updated until the next reward /// is transferred to the module during the next oracle frame. function distributeReward() external { require(getRewardDistributionState() == RewardDistributionState.ReadyForDistribution, "DISTRIBUTION_NOT_READY"); _updateRewardDistributionState(RewardDistributionState.Distributed); _distributeRewards(); } /// @notice Called by StakingRouter after it finishes updating exited and stuck validators /// counts for this module's node operators. /// /// Guaranteed to be called after an oracle report is applied, regardless of whether any node /// operator in this module has actually received any updated counts as a result of the report /// but given that the total number of exited validators returned from getStakingModuleSummary /// is the same as StakingRouter expects based on the total count received from the oracle. function onExitedAndStuckValidatorsCountsUpdated() external { _auth(STAKING_ROUTER_ROLE); _updateRewardDistributionState(RewardDistributionState.ReadyForDistribution); } /// @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 /// @param _stuckValidatorsCount New number of STUCK validator for the node operator function unsafeUpdateValidatorsCount( uint256 _nodeOperatorId, uint256 _exitedValidatorsCount, uint256 _stuckValidatorsCount ) external { _onlyExistedNodeOperator(_nodeOperatorId); _auth(STAKING_ROUTER_ROLE); _updateStuckValidatorsCount(_nodeOperatorId, _stuckValidatorsCount); _updateExitedValidatorsCount(_nodeOperatorId, _exitedValidatorsCount, true /* _allowDecrease */ ); _increaseValidatorsKeysNonce(); } function _updateExitedValidatorsCount(uint256 _nodeOperatorId, uint256 _exitedValidatorsCount, bool _allowDecrease) internal { Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); uint256 oldExitedValidatorsCount = signingKeysStats.get(TOTAL_EXITED_KEYS_COUNT_OFFSET); if (_exitedValidatorsCount == oldExitedValidatorsCount) return; require( _allowDecrease || _exitedValidatorsCount > oldExitedValidatorsCount, "EXITED_VALIDATORS_COUNT_DECREASED" ); uint256 depositedValidatorsCount = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); uint256 stuckValidatorsCount = _loadOperatorStuckPenaltyStats(_nodeOperatorId).get(STUCK_VALIDATORS_COUNT_OFFSET); // sustain invariant exited + stuck <= deposited assert(depositedValidatorsCount >= stuckValidatorsCount); _requireValidRange(_exitedValidatorsCount <= depositedValidatorsCount - stuckValidatorsCount); signingKeysStats.set(TOTAL_EXITED_KEYS_COUNT_OFFSET, _exitedValidatorsCount); _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); emit ExitedSigningKeysCountChanged(_nodeOperatorId, _exitedValidatorsCount); Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); uint256 exitedValidatorsAbsDiff = Math256.absDiff(_exitedValidatorsCount, oldExitedValidatorsCount); if (_exitedValidatorsCount > oldExitedValidatorsCount) { summarySigningKeysStats.add(SUMMARY_EXITED_KEYS_COUNT_OFFSET, exitedValidatorsAbsDiff); } else { summarySigningKeysStats.sub(SUMMARY_EXITED_KEYS_COUNT_OFFSET, exitedValidatorsAbsDiff); } _saveSummarySigningKeysStats(summarySigningKeysStats); _updateSummaryMaxValidatorsCount(_nodeOperatorId); } /// @notice Updates the limit of the validators that can be used for deposit by DAO /// @param _nodeOperatorId Id of the node operator /// @param _isTargetLimitActive Flag indicating if the soft target limit is active /// @param _targetLimit Target limit of the node operator /// @dev This function is deprecated, use updateTargetValidatorsLimits instead function updateTargetValidatorsLimits(uint256 _nodeOperatorId, bool _isTargetLimitActive, uint256 _targetLimit) public { updateTargetValidatorsLimits(_nodeOperatorId, _isTargetLimitActive ? 1 : 0, _targetLimit); } /// @notice Updates the limit of the validators that can be used for deposit by DAO /// @param _nodeOperatorId Id of the node operator /// @param _targetLimitMode target limit mode (0 = disabled, 1 = soft mode, 2 = forced mode) /// @param _targetLimit Target limit of the node operator function updateTargetValidatorsLimits(uint256 _nodeOperatorId, uint256 _targetLimitMode, uint256 _targetLimit) public { _onlyExistedNodeOperator(_nodeOperatorId); _auth(STAKING_ROUTER_ROLE); _requireValidRange(_targetLimit <= UINT64_MAX); Packed64x4.Packed memory operatorTargetStats = _loadOperatorTargetValidatorsStats(_nodeOperatorId); operatorTargetStats.set(TARGET_LIMIT_MODE_OFFSET, _targetLimitMode); if (_targetLimitMode == 0) { _targetLimit = 0; } operatorTargetStats.set(TARGET_VALIDATORS_COUNT_OFFSET, _targetLimit); _saveOperatorTargetValidatorsStats(_nodeOperatorId, operatorTargetStats); emit TargetValidatorsCountChanged(_nodeOperatorId, _targetLimit, _targetLimitMode); _updateSummaryMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); } /** * @notice Set the stuck signings keys count */ function _updateStuckValidatorsCount(uint256 _nodeOperatorId, uint256 _stuckValidatorsCount) internal { Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); uint256 curStuckValidatorsCount = stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET); if (_stuckValidatorsCount == curStuckValidatorsCount) return; Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); uint256 exitedValidatorsCount = signingKeysStats.get(TOTAL_EXITED_KEYS_COUNT_OFFSET); uint256 depositedValidatorsCount = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); // sustain invariant exited + stuck <= deposited assert(depositedValidatorsCount >= exitedValidatorsCount); _requireValidRange(_stuckValidatorsCount <= depositedValidatorsCount - exitedValidatorsCount); uint256 curRefundedValidatorsCount = stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET); if (_stuckValidatorsCount <= curRefundedValidatorsCount && curStuckValidatorsCount > curRefundedValidatorsCount) { stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, block.timestamp + getStuckPenaltyDelay()); } stuckPenaltyStats.set(STUCK_VALIDATORS_COUNT_OFFSET, _stuckValidatorsCount); _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); emit StuckPenaltyStateChanged( _nodeOperatorId, _stuckValidatorsCount, curRefundedValidatorsCount, stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) ); _updateSummaryMaxValidatorsCount(_nodeOperatorId); } function _updateRefundValidatorsKeysCount(uint256 _nodeOperatorId, uint256 _refundedValidatorsCount) internal { Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); uint256 curRefundedValidatorsCount = stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET); if (_refundedValidatorsCount == curRefundedValidatorsCount) return; Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); _requireValidRange(_refundedValidatorsCount <= signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET)); uint256 curStuckValidatorsCount = stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET); if (_refundedValidatorsCount >= curStuckValidatorsCount && curRefundedValidatorsCount < curStuckValidatorsCount) { stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, block.timestamp + getStuckPenaltyDelay()); } stuckPenaltyStats.set(REFUNDED_VALIDATORS_COUNT_OFFSET, _refundedValidatorsCount); _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); emit StuckPenaltyStateChanged( _nodeOperatorId, curStuckValidatorsCount, _refundedValidatorsCount, stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) ); _updateSummaryMaxValidatorsCount(_nodeOperatorId); } // @dev Recalculate and update the max validator count for operator and summary stats function _updateSummaryMaxValidatorsCount(uint256 _nodeOperatorId) internal { (uint256 oldMaxSigningKeysCount, uint256 newMaxSigningKeysCount) = _applyNodeOperatorLimits(_nodeOperatorId); if (newMaxSigningKeysCount == oldMaxSigningKeysCount) return; Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); uint256 maxSigningKeysCountAbsDiff = Math256.absDiff(newMaxSigningKeysCount, oldMaxSigningKeysCount); if (newMaxSigningKeysCount > oldMaxSigningKeysCount) { summarySigningKeysStats.add(SUMMARY_MAX_VALIDATORS_COUNT_OFFSET, maxSigningKeysCountAbsDiff); } else { summarySigningKeysStats.sub(SUMMARY_MAX_VALIDATORS_COUNT_OFFSET, maxSigningKeysCountAbsDiff); } _saveSummarySigningKeysStats(summarySigningKeysStats); } /// @notice Invalidates all unused deposit data for all node operators function onWithdrawalCredentialsChanged() external { _auth(STAKING_ROUTER_ROLE); uint256 operatorsCount = getNodeOperatorsCount(); if (operatorsCount > 0) { _invalidateReadyToDepositKeysRange(0, operatorsCount - 1); } } /// @notice Invalidates all unused validators keys for node operators in the given range /// @param _indexFrom the first index (inclusive) of the node operator to invalidate keys for /// @param _indexTo the last index (inclusive) of the node operator to invalidate keys for function invalidateReadyToDepositKeysRange(uint256 _indexFrom, uint256 _indexTo) external { _auth(MANAGE_NODE_OPERATOR_ROLE); _invalidateReadyToDepositKeysRange(_indexFrom, _indexTo); } function _invalidateReadyToDepositKeysRange(uint256 _indexFrom, uint256 _indexTo) internal { _requireValidRange(_indexFrom <= _indexTo && _indexTo < getNodeOperatorsCount()); uint256 trimmedKeysCount; uint256 totalTrimmedKeysCount; uint256 totalSigningKeysCount; uint256 depositedSigningKeysCount; Packed64x4.Packed memory signingKeysStats; for (uint256 nodeOperatorId = _indexFrom; nodeOperatorId <= _indexTo; ++nodeOperatorId) { signingKeysStats = _loadOperatorSigningKeysStats(nodeOperatorId); totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); depositedSigningKeysCount = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); if (totalSigningKeysCount == depositedSigningKeysCount) continue; assert(totalSigningKeysCount > depositedSigningKeysCount); trimmedKeysCount = totalSigningKeysCount - depositedSigningKeysCount; totalTrimmedKeysCount += trimmedKeysCount; signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, depositedSigningKeysCount); signingKeysStats.set(TOTAL_VETTED_KEYS_COUNT_OFFSET, depositedSigningKeysCount); _saveOperatorSigningKeysStats(nodeOperatorId, signingKeysStats); _updateSummaryMaxValidatorsCount(nodeOperatorId); emit TotalSigningKeysCountChanged(nodeOperatorId, depositedSigningKeysCount); emit VettedSigningKeysCountChanged(nodeOperatorId, depositedSigningKeysCount); emit NodeOperatorTotalKeysTrimmed(nodeOperatorId, uint64(trimmedKeysCount)); } if (totalTrimmedKeysCount > 0) { _increaseValidatorsKeysNonce(); } } /// @notice Obtains deposit data to be used by StakingRouter to deposit to the Ethereum Deposit /// contract /// @param _depositsCount Number of deposits to be done /// @return publicKeys Batch of the concatenated public validators keys /// @return signatures Batch of the concatenated deposit signatures for returned public keys function obtainDepositData( uint256 _depositsCount, bytes /* _depositCalldata */ ) external returns (bytes memory publicKeys, bytes memory signatures) { _auth(STAKING_ROUTER_ROLE); if (_depositsCount == 0) return (new bytes(0), new bytes(0)); ( uint256 allocatedKeysCount, uint256[] memory nodeOperatorIds, uint256[] memory activeKeysCountAfterAllocation ) = _getSigningKeysAllocationData(_depositsCount); require(allocatedKeysCount == _depositsCount, "INVALID_ALLOCATED_KEYS_COUNT"); (publicKeys, signatures) = _loadAllocatedSigningKeys( allocatedKeysCount, nodeOperatorIds, activeKeysCountAfterAllocation ); _increaseValidatorsKeysNonce(); } function _getNodeOperator(uint256 _nodeOperatorId) internal view returns (uint256 exitedSigningKeysCount, uint256 depositedSigningKeysCount, uint256 maxSigningKeysCount) { Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); Packed64x4.Packed memory operatorTargetStats = _loadOperatorTargetValidatorsStats(_nodeOperatorId); exitedSigningKeysCount = signingKeysStats.get(TOTAL_EXITED_KEYS_COUNT_OFFSET); depositedSigningKeysCount = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); maxSigningKeysCount = operatorTargetStats.get(MAX_VALIDATORS_COUNT_OFFSET); // Validate data boundaries invariants here to not use SafeMath in caller methods assert(maxSigningKeysCount >= depositedSigningKeysCount && depositedSigningKeysCount >= exitedSigningKeysCount); } function _applyNodeOperatorLimits(uint256 _nodeOperatorId) internal returns (uint256 oldMaxSigningKeysCount, uint256 newMaxSigningKeysCount) { Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); Packed64x4.Packed memory operatorTargetStats = _loadOperatorTargetValidatorsStats(_nodeOperatorId); uint256 depositedSigningKeysCount = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); // It's expected that validators don't suffer from penalties most of the time, // so optimistically, set the count of max validators equal to the vetted validators count. newMaxSigningKeysCount = signingKeysStats.get(TOTAL_VETTED_KEYS_COUNT_OFFSET); if (!isOperatorPenaltyCleared(_nodeOperatorId)) { // when the node operator is penalized zeroing its depositable validators count newMaxSigningKeysCount = depositedSigningKeysCount; } else if (operatorTargetStats.get(TARGET_LIMIT_MODE_OFFSET) != 0) { // apply target limit when it's active and the node operator is not penalized newMaxSigningKeysCount = Math256.max( // max validators count can't be less than the deposited validators count // even when the target limit is less than the current active validators count depositedSigningKeysCount, Math256.min( // max validators count can't be greater than the vetted validators count newMaxSigningKeysCount, // SafeMath.add() isn't used below because the sum is always // less or equal to 2 * UINT64_MAX signingKeysStats.get(TOTAL_EXITED_KEYS_COUNT_OFFSET) + operatorTargetStats.get(TARGET_VALIDATORS_COUNT_OFFSET) ) ); } oldMaxSigningKeysCount = operatorTargetStats.get(MAX_VALIDATORS_COUNT_OFFSET); if (oldMaxSigningKeysCount != newMaxSigningKeysCount) { operatorTargetStats.set(MAX_VALIDATORS_COUNT_OFFSET, newMaxSigningKeysCount); _saveOperatorTargetValidatorsStats(_nodeOperatorId, operatorTargetStats); } } function _getSigningKeysAllocationData(uint256 _keysCount) internal view returns (uint256 allocatedKeysCount, uint256[] memory nodeOperatorIds, uint256[] memory activeKeyCountsAfterAllocation) { uint256 activeNodeOperatorsCount = getActiveNodeOperatorsCount(); nodeOperatorIds = new uint256[](activeNodeOperatorsCount); activeKeyCountsAfterAllocation = new uint256[](activeNodeOperatorsCount); uint256[] memory activeKeysCapacities = new uint256[](activeNodeOperatorsCount); uint256 activeNodeOperatorIndex; uint256 nodeOperatorsCount = getNodeOperatorsCount(); uint256 maxSigningKeysCount; uint256 depositedSigningKeysCount; uint256 exitedSigningKeysCount; for (uint256 nodeOperatorId; nodeOperatorId < nodeOperatorsCount; ++nodeOperatorId) { (exitedSigningKeysCount, depositedSigningKeysCount, maxSigningKeysCount) = _getNodeOperator(nodeOperatorId); // the node operator has no available signing keys if (depositedSigningKeysCount == maxSigningKeysCount) continue; nodeOperatorIds[activeNodeOperatorIndex] = nodeOperatorId; activeKeyCountsAfterAllocation[activeNodeOperatorIndex] = depositedSigningKeysCount - exitedSigningKeysCount; activeKeysCapacities[activeNodeOperatorIndex] = maxSigningKeysCount - exitedSigningKeysCount; ++activeNodeOperatorIndex; } if (activeNodeOperatorIndex == 0) return (0, new uint256[](0), new uint256[](0)); /// @dev shrink the length of the resulting arrays if some active node operators have no available keys to be deposited if (activeNodeOperatorIndex < activeNodeOperatorsCount) { assembly { mstore(nodeOperatorIds, activeNodeOperatorIndex) mstore(activeKeyCountsAfterAllocation, activeNodeOperatorIndex) mstore(activeKeysCapacities, activeNodeOperatorIndex) } } (allocatedKeysCount, activeKeyCountsAfterAllocation) = MinFirstAllocationStrategy.allocate(activeKeyCountsAfterAllocation, activeKeysCapacities, _keysCount); /// @dev method NEVER allocates more keys than was requested assert(_keysCount >= allocatedKeysCount); } function _loadAllocatedSigningKeys( uint256 _keysCountToLoad, uint256[] memory _nodeOperatorIds, uint256[] memory _activeKeyCountsAfterAllocation ) internal returns (bytes memory pubkeys, bytes memory signatures) { (pubkeys, signatures) = SigningKeys.initKeysSigsBuf(_keysCountToLoad); uint256 loadedKeysCount = 0; uint256 depositedSigningKeysCountBefore; uint256 depositedSigningKeysCountAfter; uint256 keysCount; Packed64x4.Packed memory signingKeysStats; for (uint256 i; i < _nodeOperatorIds.length; ++i) { signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorIds[i]); depositedSigningKeysCountBefore = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); depositedSigningKeysCountAfter = signingKeysStats.get(TOTAL_EXITED_KEYS_COUNT_OFFSET) + _activeKeyCountsAfterAllocation[i]; if (depositedSigningKeysCountAfter == depositedSigningKeysCountBefore) continue; // For gas savings SafeMath.add() wasn't used on depositedSigningKeysCountAfter // calculation, so below we check that operation finished without overflow // In case of overflow: // depositedSigningKeysCountAfter < signingKeysStats.get(TOTAL_EXITED_KEYS_COUNT_OFFSET) // what violates invariant: // depositedSigningKeysCount >= exitedSigningKeysCount assert(depositedSigningKeysCountAfter > depositedSigningKeysCountBefore); keysCount = depositedSigningKeysCountAfter - depositedSigningKeysCountBefore; SIGNING_KEYS_MAPPING_NAME.loadKeysSigs( _nodeOperatorIds[i], depositedSigningKeysCountBefore, keysCount, pubkeys, signatures, loadedKeysCount ); loadedKeysCount += keysCount; emit DepositedSigningKeysCountChanged(_nodeOperatorIds[i], depositedSigningKeysCountAfter); signingKeysStats.set(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET, depositedSigningKeysCountAfter); _saveOperatorSigningKeysStats(_nodeOperatorIds[i], signingKeysStats); _updateSummaryMaxValidatorsCount(_nodeOperatorIds[i]); } assert(loadedKeysCount == _keysCountToLoad); Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); summarySigningKeysStats.add(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET, loadedKeysCount); _saveSummarySigningKeysStats(summarySigningKeysStats); } /// @notice Returns the node operator by id /// @param _nodeOperatorId Node Operator id /// @param _fullInfo If true, name will be returned as well function getNodeOperator(uint256 _nodeOperatorId, bool _fullInfo) external view returns ( bool active, string name, address rewardAddress, uint64 totalVettedValidators, uint64 totalExitedValidators, uint64 totalAddedValidators, uint64 totalDepositedValidators ) { _onlyExistedNodeOperator(_nodeOperatorId); NodeOperator storage nodeOperator = _nodeOperators[_nodeOperatorId]; active = nodeOperator.active; rewardAddress = nodeOperator.rewardAddress; name = _fullInfo ? nodeOperator.name : ""; // reading name is 2+ SLOADs Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); totalVettedValidators = uint64(signingKeysStats.get(TOTAL_VETTED_KEYS_COUNT_OFFSET)); totalExitedValidators = uint64(signingKeysStats.get(TOTAL_EXITED_KEYS_COUNT_OFFSET)); totalAddedValidators = uint64(signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET)); totalDepositedValidators = uint64(signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET)); } /// @notice Returns the rewards distribution proportional to the effective stake for each node operator. /// @param _totalRewardShares Total amount of reward shares to distribute. function getRewardsDistribution(uint256 _totalRewardShares) public view returns (address[] memory recipients, uint256[] memory shares, bool[] memory penalized) { uint256 nodeOperatorCount = getNodeOperatorsCount(); uint256 activeCount = getActiveNodeOperatorsCount(); recipients = new address[](activeCount); shares = new uint256[](activeCount); penalized = new bool[](activeCount); uint256 idx = 0; uint256 totalActiveValidatorsCount = 0; Packed64x4.Packed memory signingKeysStats; for (uint256 operatorId; operatorId < nodeOperatorCount; ++operatorId) { if (!getNodeOperatorIsActive(operatorId)) continue; signingKeysStats = _loadOperatorSigningKeysStats(operatorId); uint256 totalExitedValidators = signingKeysStats.get(TOTAL_EXITED_KEYS_COUNT_OFFSET); uint256 totalDepositedValidators = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); // validate invariant to not use SafeMath.sub() assert(totalDepositedValidators >= totalExitedValidators); uint256 activeValidatorsCount = totalDepositedValidators - totalExitedValidators; // SafeMath.add() isn't used below because the following is always true: // totalActiveValidatorsCount <= MAX_NODE_OPERATORS_COUNT * UINT64_MAX totalActiveValidatorsCount += activeValidatorsCount; recipients[idx] = _nodeOperators[operatorId].rewardAddress; // prefill shares array with 'key share' for recipient, see below shares[idx] = activeValidatorsCount; penalized[idx] = isOperatorPenalized(operatorId); ++idx; } if (totalActiveValidatorsCount == 0) return (recipients, shares, penalized); for (idx = 0; idx < activeCount; ++idx) { /// @dev unsafe division used below for gas savings. It's safe in the current case /// because SafeMath.div() only validates that the divider isn't equal to zero. /// totalActiveValidatorsCount guaranteed greater than zero. shares[idx] = shares[idx].mul(_totalRewardShares) / totalActiveValidatorsCount; } return (recipients, shares, penalized); } /// @notice Add `_quantity` validator signing keys to the keys of the node operator #`_nodeOperatorId`. Concatenated keys are: `_pubkeys` /// @dev Along with each key the DAO has to provide a signatures for the /// (pubkey, withdrawal_credentials, 32000000000) message. /// Given that information, the contract'll be able to call /// deposit_contract.deposit on-chain. /// @param _nodeOperatorId Node Operator id /// @param _keysCount Number of signing keys provided /// @param _publicKeys Several concatenated validator signing keys /// @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages function addSigningKeys(uint256 _nodeOperatorId, uint256 _keysCount, bytes _publicKeys, bytes _signatures) external { _addSigningKeys(_nodeOperatorId, _keysCount, _publicKeys, _signatures); } /// @notice Add `_quantity` validator signing keys of operator #`_id` to the set of usable keys. Concatenated keys are: `_pubkeys`. Can be done by node operator in question by using the designated rewards address. /// @dev Along with each key the DAO has to provide a signatures for the /// (pubkey, withdrawal_credentials, 32000000000) message. /// Given that information, the contract'll be able to call /// deposit_contract.deposit on-chain. /// @param _nodeOperatorId Node Operator id /// @param _keysCount Number of signing keys provided /// @param _publicKeys Several concatenated validator signing keys /// @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages /// @dev DEPRECATED use addSigningKeys instead function addSigningKeysOperatorBH(uint256 _nodeOperatorId, uint256 _keysCount, bytes _publicKeys, bytes _signatures) external { _addSigningKeys(_nodeOperatorId, _keysCount, _publicKeys, _signatures); } function _addSigningKeys(uint256 _nodeOperatorId, uint256 _keysCount, bytes _publicKeys, bytes _signatures) internal { _onlyExistedNodeOperator(_nodeOperatorId); _onlyNodeOperatorManager(msg.sender, _nodeOperatorId); _requireValidRange(_keysCount != 0 && _keysCount <= UINT64_MAX); Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); uint256 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); _requireValidRange(totalSigningKeysCount.add(_keysCount) <= UINT64_MAX); totalSigningKeysCount = SIGNING_KEYS_MAPPING_NAME.saveKeysSigs(_nodeOperatorId, totalSigningKeysCount, _keysCount, _publicKeys, _signatures); emit TotalSigningKeysCountChanged(_nodeOperatorId, totalSigningKeysCount); signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysCount); _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); _increaseValidatorsKeysNonce(); } /// @notice Removes a validator signing key #`_index` from the keys of the node operator #`_nodeOperatorId` /// @param _nodeOperatorId Node Operator id /// @param _index Index of the key, starting with 0 /// @dev DEPRECATED use removeSigningKeys instead function removeSigningKey(uint256 _nodeOperatorId, uint256 _index) external { _removeUnusedSigningKeys(_nodeOperatorId, _index, 1); } /// @notice Removes an #`_keysCount` of validator signing keys starting from #`_index` of operator #`_id` usable keys. Executed on behalf of DAO. /// @param _nodeOperatorId Node Operator id /// @param _fromIndex Index of the key, starting with 0 /// @param _keysCount Number of keys to remove function removeSigningKeys(uint256 _nodeOperatorId, uint256 _fromIndex, uint256 _keysCount) external { _removeUnusedSigningKeys(_nodeOperatorId, _fromIndex, _keysCount); } /// @notice Removes a validator signing key #`_index` of operator #`_id` from the set of usable keys. Executed on behalf of Node Operator. /// @param _nodeOperatorId Node Operator id /// @param _index Index of the key, starting with 0 /// @dev DEPRECATED use removeSigningKeys instead function removeSigningKeyOperatorBH(uint256 _nodeOperatorId, uint256 _index) external { _removeUnusedSigningKeys(_nodeOperatorId, _index, 1); } /// @notice Removes an #`_keysCount` of validator signing keys starting from #`_index` of operator #`_id` usable keys. Executed on behalf of Node Operator. /// @param _nodeOperatorId Node Operator id /// @param _fromIndex Index of the key, starting with 0 /// @param _keysCount Number of keys to remove /// @dev DEPRECATED use removeSigningKeys instead function removeSigningKeysOperatorBH(uint256 _nodeOperatorId, uint256 _fromIndex, uint256 _keysCount) external { _removeUnusedSigningKeys(_nodeOperatorId, _fromIndex, _keysCount); } function _removeUnusedSigningKeys(uint256 _nodeOperatorId, uint256 _fromIndex, uint256 _keysCount) internal { _onlyExistedNodeOperator(_nodeOperatorId); _onlyNodeOperatorManager(msg.sender, _nodeOperatorId); // preserve the previous behavior of the method here and just return earlier if (_keysCount == 0) return; Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); uint256 totalSigningKeysCount = signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); // comparing _fromIndex.add(_keysCount) <= totalSigningKeysCount is enough as totalSigningKeysCount is always less than UINT64_MAX _requireValidRange( _fromIndex >= signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET) && _fromIndex.add(_keysCount) <= totalSigningKeysCount ); totalSigningKeysCount = SIGNING_KEYS_MAPPING_NAME.removeKeysSigs(_nodeOperatorId, _fromIndex, _keysCount, totalSigningKeysCount); signingKeysStats.set(TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysCount); emit TotalSigningKeysCountChanged(_nodeOperatorId, totalSigningKeysCount); uint256 vettedSigningKeysCount = signingKeysStats.get(TOTAL_VETTED_KEYS_COUNT_OFFSET); if (_fromIndex < vettedSigningKeysCount) { // decreasing the staking limit so the key at _index can't be used anymore signingKeysStats.set(TOTAL_VETTED_KEYS_COUNT_OFFSET, _fromIndex); emit VettedSigningKeysCountChanged(_nodeOperatorId, _fromIndex); } _saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats); _updateSummaryMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); } /// @notice Returns total number of signing keys of the node operator #`_nodeOperatorId` function getTotalSigningKeyCount(uint256 _nodeOperatorId) external view returns (uint256) { _onlyExistedNodeOperator(_nodeOperatorId); Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); return signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET); } /// @notice Returns number of usable signing keys of the node operator #`_nodeOperatorId` function getUnusedSigningKeyCount(uint256 _nodeOperatorId) external view returns (uint256) { _onlyExistedNodeOperator(_nodeOperatorId); Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); return signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET).sub(signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET)); } /// @notice Returns n-th signing key of the node operator #`_nodeOperatorId` /// @param _nodeOperatorId Node Operator id /// @param _index Index of the key, starting with 0 /// @return key Key /// @return depositSignature Signature needed for a deposit_contract.deposit call /// @return used Flag indication if the key was used in the staking function getSigningKey(uint256 _nodeOperatorId, uint256 _index) external view returns (bytes key, bytes depositSignature, bool used) { bool[] memory keyUses; (key, depositSignature, keyUses) = getSigningKeys(_nodeOperatorId, _index, 1); used = keyUses[0]; } /// @notice Returns n signing keys of the node operator #`_nodeOperatorId` /// @param _nodeOperatorId Node Operator id /// @param _offset Offset of the key, starting with 0 /// @param _limit Number of keys to return /// @return pubkeys Keys concatenated into the bytes batch /// @return signatures Signatures concatenated into the bytes batch needed for a deposit_contract.deposit call /// @return used Array of flags indicated if the key was used in the staking function getSigningKeys(uint256 _nodeOperatorId, uint256 _offset, uint256 _limit) public view returns (bytes memory pubkeys, bytes memory signatures, bool[] memory used) { _onlyExistedNodeOperator(_nodeOperatorId); Packed64x4.Packed memory signingKeysStats = _loadOperatorSigningKeysStats(_nodeOperatorId); _requireValidRange(_offset.add(_limit) <= signingKeysStats.get(TOTAL_KEYS_COUNT_OFFSET)); uint256 depositedSigningKeysCount = signingKeysStats.get(TOTAL_DEPOSITED_KEYS_COUNT_OFFSET); (pubkeys, signatures) = SigningKeys.initKeysSigsBuf(_limit); used = new bool[](_limit); SIGNING_KEYS_MAPPING_NAME.loadKeysSigs(_nodeOperatorId, _offset, _limit, pubkeys, signatures, 0); for (uint256 i; i < _limit; ++i) { used[i] = (_offset + i) < depositedSigningKeysCount; } } /// @notice Returns the type of the staking module function getType() external view returns (bytes32) { return TYPE_POSITION.getStorageBytes32(); } function getStakingModuleSummary() external view returns (uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount) { Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); totalExitedValidators = summarySigningKeysStats.get(SUMMARY_EXITED_KEYS_COUNT_OFFSET); totalDepositedValidators = summarySigningKeysStats.get(SUMMARY_DEPOSITED_KEYS_COUNT_OFFSET); depositableValidatorsCount = summarySigningKeysStats.get(SUMMARY_MAX_VALIDATORS_COUNT_OFFSET).sub(totalDepositedValidators); } function getNodeOperatorSummary(uint256 _nodeOperatorId) external view returns ( uint256 targetLimitMode, uint256 targetValidatorsCount, uint256 stuckValidatorsCount, uint256 refundedValidatorsCount, uint256 stuckPenaltyEndTimestamp, uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount ) { _onlyExistedNodeOperator(_nodeOperatorId); Packed64x4.Packed memory operatorTargetStats = _loadOperatorTargetValidatorsStats(_nodeOperatorId); Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); targetLimitMode = operatorTargetStats.get(TARGET_LIMIT_MODE_OFFSET); targetValidatorsCount = operatorTargetStats.get(TARGET_VALIDATORS_COUNT_OFFSET); stuckValidatorsCount = stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET); refundedValidatorsCount = stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET); stuckPenaltyEndTimestamp = stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET); (totalExitedValidators, totalDepositedValidators, depositableValidatorsCount) = _getNodeOperatorValidatorsSummary(_nodeOperatorId); } function _getNodeOperatorValidatorsSummary(uint256 _nodeOperatorId) internal view returns ( uint256 totalExitedValidators, uint256 totalDepositedValidators, uint256 depositableValidatorsCount ) { uint256 totalMaxValidators; (totalExitedValidators, totalDepositedValidators, totalMaxValidators) = _getNodeOperator(_nodeOperatorId); depositableValidatorsCount = totalMaxValidators - totalDepositedValidators; } function _isOperatorPenalized(Packed64x4.Packed memory stuckPenaltyStats) internal view returns (bool) { return stuckPenaltyStats.get(REFUNDED_VALIDATORS_COUNT_OFFSET) < stuckPenaltyStats.get(STUCK_VALIDATORS_COUNT_OFFSET) || block.timestamp <= stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET); } function isOperatorPenalized(uint256 _nodeOperatorId) public view returns (bool) { Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); return _isOperatorPenalized(stuckPenaltyStats); } function isOperatorPenaltyCleared(uint256 _nodeOperatorId) public view returns (bool) { Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); return !_isOperatorPenalized(stuckPenaltyStats) && stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) == 0; } function clearNodeOperatorPenalty(uint256 _nodeOperatorId) external returns (bool) { Packed64x4.Packed memory stuckPenaltyStats = _loadOperatorStuckPenaltyStats(_nodeOperatorId); require( !_isOperatorPenalized(stuckPenaltyStats) && stuckPenaltyStats.get(STUCK_PENALTY_END_TIMESTAMP_OFFSET) != 0, "CANT_CLEAR_PENALTY" ); stuckPenaltyStats.set(STUCK_PENALTY_END_TIMESTAMP_OFFSET, 0); _saveOperatorStuckPenaltyStats(_nodeOperatorId, stuckPenaltyStats); _updateSummaryMaxValidatorsCount(_nodeOperatorId); _increaseValidatorsKeysNonce(); emit NodeOperatorPenaltyCleared(_nodeOperatorId); return true; } /// @notice Returns total number of node operators function getNodeOperatorsCount() public view returns (uint256) { return TOTAL_OPERATORS_COUNT_POSITION.getStorageUint256(); } /// @notice Returns number of active node operators function getActiveNodeOperatorsCount() public view returns (uint256) { return ACTIVE_OPERATORS_COUNT_POSITION.getStorageUint256(); } /// @notice Returns if the node operator with given id is active function getNodeOperatorIsActive(uint256 _nodeOperatorId) public view returns (bool) { return _nodeOperators[_nodeOperatorId].active; } /// @notice Returns up to `_limit` node operator ids starting from the `_offset`. function getNodeOperatorIds(uint256 _offset, uint256 _limit) external view returns (uint256[] memory nodeOperatorIds) { uint256 nodeOperatorsCount = getNodeOperatorsCount(); if (_offset >= nodeOperatorsCount || _limit == 0) return; nodeOperatorIds = new uint256[](Math256.min(_limit, nodeOperatorsCount - _offset)); for (uint256 i = 0; i < nodeOperatorIds.length; ++i) { nodeOperatorIds[i] = _offset + i; } } /// @notice Returns a counter that MUST change it's value when any of the following happens: /// 1. a node operator's deposit data is added /// 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 function getNonce() external view returns (uint256) { return KEYS_OP_INDEX_POSITION.getStorageUint256(); } /// @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 DEPRECATED use getNonce() instead function getKeysOpIndex() external view returns (uint256) { return KEYS_OP_INDEX_POSITION.getStorageUint256(); } /// @notice distributes rewards among node operators /// @return the amount of stETH shares distributed among node operators function _distributeRewards() internal returns (uint256 distributed) { IStETH stETH = IStETH(getLocator().lido()); uint256 sharesToDistribute = stETH.sharesOf(address(this)); if (sharesToDistribute == 0) { return; } (address[] memory recipients, uint256[] memory shares, bool[] memory penalized) = getRewardsDistribution(sharesToDistribute); uint256 toBurn; for (uint256 idx; idx < recipients.length; ++idx) { /// @dev skip ultra-low amounts processing to avoid transfer zero amount in case of a penalty if (shares[idx] < 2) continue; if (penalized[idx]) { /// @dev half reward punishment /// @dev ignore remainder since it accumulated on contract balance shares[idx] >>= 1; toBurn = toBurn.add(shares[idx]); emit NodeOperatorPenalized(recipients[idx], shares[idx]); } stETH.transferShares(recipients[idx], shares[idx]); distributed = distributed.add(shares[idx]); emit RewardsDistributed(recipients[idx], shares[idx]); } if (toBurn > 0) { IBurner(getLocator().burner()).requestBurnShares(address(this), toBurn); } } function getLocator() public view returns (ILidoLocator) { return ILidoLocator(LIDO_LOCATOR_POSITION.getStorageAddress()); } function getStuckPenaltyDelay() public view returns (uint256) { return STUCK_PENALTY_DELAY_POSITION.getStorageUint256(); } function setStuckPenaltyDelay(uint256 _delay) external { _auth(MANAGE_NODE_OPERATOR_ROLE); _setStuckPenaltyDelay(_delay); } /// @dev Get the current reward distribution state, anyone can monitor this state /// and distribute reward (call distributeReward method) among operators when it's `ReadyForDistribution` function getRewardDistributionState() public view returns (RewardDistributionState) { uint256 state = REWARD_DISTRIBUTION_STATE.getStorageUint256(); return RewardDistributionState(state); } function _updateRewardDistributionState(RewardDistributionState _state) internal { REWARD_DISTRIBUTION_STATE.setStorageUint256(uint256(_state)); emit RewardDistributionStateChanged(_state); } /// @dev set new stuck penalty delay, duration in sec function _setStuckPenaltyDelay(uint256 _delay) internal { _requireValidRange(_delay <= MAX_STUCK_PENALTY_DELAY); STUCK_PENALTY_DELAY_POSITION.setStorageUint256(_delay); emit StuckPenaltyDelayChanged(_delay); } function _increaseValidatorsKeysNonce() internal { uint256 keysOpIndex = KEYS_OP_INDEX_POSITION.getStorageUint256() + 1; KEYS_OP_INDEX_POSITION.setStorageUint256(keysOpIndex); /// @dev [DEPRECATED] event preserved for tooling compatibility emit KeysOpIndexSet(keysOpIndex); emit NonceChanged(keysOpIndex); } function _loadSummarySigningKeysStats() internal view returns (Packed64x4.Packed memory) { return _nodeOperatorSummary.summarySigningKeysStats; } function _saveSummarySigningKeysStats(Packed64x4.Packed memory _val) internal { _nodeOperatorSummary.summarySigningKeysStats = _val; } function _loadOperatorTargetValidatorsStats(uint256 _nodeOperatorId) internal view returns (Packed64x4.Packed memory) { return _nodeOperators[_nodeOperatorId].targetValidatorsStats; } function _saveOperatorTargetValidatorsStats(uint256 _nodeOperatorId, Packed64x4.Packed memory _val) internal { _nodeOperators[_nodeOperatorId].targetValidatorsStats = _val; } function _loadOperatorStuckPenaltyStats(uint256 _nodeOperatorId) internal view returns (Packed64x4.Packed memory) { return _nodeOperators[_nodeOperatorId].stuckPenaltyStats; } function _saveOperatorStuckPenaltyStats(uint256 _nodeOperatorId, Packed64x4.Packed memory _val) internal { _nodeOperators[_nodeOperatorId].stuckPenaltyStats = _val; } function _loadOperatorSigningKeysStats(uint256 _nodeOperatorId) internal view returns (Packed64x4.Packed memory) { return _nodeOperators[_nodeOperatorId].signingKeysStats; } function _saveOperatorSigningKeysStats(uint256 _nodeOperatorId, Packed64x4.Packed memory _val) internal { _nodeOperators[_nodeOperatorId].signingKeysStats = _val; } function _requireAuth(bool _pass) internal pure { require(_pass, "APP_AUTH_FAILED"); } function _requireNotSameValue(bool _pass) internal pure { require(_pass, "VALUE_IS_THE_SAME"); } function _requireValidRange(bool _pass) internal pure { require(_pass, "OUT_OF_RANGE"); } function _onlyCorrectNodeOperatorState(bool _pass) internal pure { require(_pass, "WRONG_OPERATOR_ACTIVE_STATE"); } function _auth(bytes32 _role) internal view { _requireAuth(canPerform(msg.sender, _role, new uint256[](0))); } function _authP(bytes32 _role, uint256[] _params) internal view { _requireAuth(canPerform(msg.sender, _role, _params)); } function _onlyNodeOperatorManager(address _sender, uint256 _nodeOperatorId) internal view { bool isRewardAddress = _sender == _nodeOperators[_nodeOperatorId].rewardAddress; bool isActive = _nodeOperators[_nodeOperatorId].active; _requireAuth((isRewardAddress && isActive) || canPerform(_sender, MANAGE_SIGNING_KEYS, arr(_nodeOperatorId))); } function _onlyExistedNodeOperator(uint256 _nodeOperatorId) internal view { _requireValidRange(_nodeOperatorId < getNodeOperatorsCount()); } function _onlyValidNodeOperatorName(string _name) internal pure { require(bytes(_name).length > 0 && bytes(_name).length <= MAX_NODE_OPERATOR_NAME_LENGTH, "WRONG_NAME_LENGTH"); } function _onlyValidRewardAddress(address _rewardAddress) internal view { _onlyNonZeroAddress(_rewardAddress); // The Lido address is forbidden explicitly because stETH transfers on this contract will revert // See onExitedAndStuckValidatorsCountsUpdated() and StETH._transferShares() for details require(_rewardAddress != getLocator().lido(), "LIDO_REWARD_ADDRESS"); } function _onlyNonZeroAddress(address _a) internal pure { require(_a != address(0), "ZERO_ADDRESS"); } }
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
contract ACLSyntaxSugar {
function arr() internal pure returns (uint256[]) {
return new uint256[](0);
}
function arr(bytes32 _a) internal pure returns (uint256[] r) {
return arr(uint256(_a));
}
function arr(bytes32 _a, bytes32 _b) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b));
}
function arr(address _a) internal pure returns (uint256[] r) {
return arr(uint256(_a));
}
function arr(address _a, address _b) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b));
}
function arr(address _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
return arr(uint256(_a), _b, _c);
}
function arr(address _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
return arr(uint256(_a), _b, _c, _d);
}
function arr(address _a, uint256 _b) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b));
}
function arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b), _c, _d, _e);
}
function arr(address _a, address _b, address _c) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b), uint256(_c));
}
function arr(address _a, address _b, uint256 _c) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b), uint256(_c));
}
function arr(uint256 _a) internal pure returns (uint256[] r) {
r = new uint256[](1);
r[0] = _a;
}
function arr(uint256 _a, uint256 _b) internal pure returns (uint256[] r) {
r = new uint256[](2);
r[0] = _a;
r[1] = _b;
}
function arr(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
r = new uint256[](3);
r[0] = _a;
r[1] = _b;
r[2] = _c;
}
function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
r = new uint256[](4);
r[0] = _a;
r[1] = _b;
r[2] = _c;
r[3] = _d;
}
function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
r = new uint256[](5);
r[0] = _a;
r[1] = _b;
r[2] = _c;
r[3] = _d;
r[4] = _e;
}
}
contract ACLHelpers {
function decodeParamOp(uint256 _x) internal pure returns (uint8 b) {
return uint8(_x >> (8 * 30));
}
function decodeParamId(uint256 _x) internal pure returns (uint8 b) {
return uint8(_x >> (8 * 31));
}
function decodeParamsList(uint256 _x) internal pure returns (uint32 a, uint32 b, uint32 c) {
a = uint32(_x);
b = uint32(_x >> (8 * 4));
c = uint32(_x >> (8 * 8));
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
interface IACL {
function initialize(address permissionsCreator) external;
// TODO: this should be external
// See https://github.com/ethereum/solidity/issues/4832
function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../common/UnstructuredStorage.sol";
import "../kernel/IKernel.sol";
contract AppStorage {
using UnstructuredStorage for bytes32;
/* Hardcoded constants to save gas
bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
*/
bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
function kernel() public view returns (IKernel) {
return IKernel(KERNEL_POSITION.getStorageAddress());
}
function appId() public view returns (bytes32) {
return APP_ID_POSITION.getStorageBytes32();
}
function setKernel(IKernel _kernel) internal {
KERNEL_POSITION.setStorageAddress(address(_kernel));
}
function setAppId(bytes32 _appId) internal {
APP_ID_POSITION.setStorageBytes32(_appId);
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./AppStorage.sol";
import "../acl/ACLSyntaxSugar.sol";
import "../common/Autopetrified.sol";
import "../common/ConversionHelpers.sol";
import "../common/ReentrancyGuard.sol";
import "../common/VaultRecoverable.sol";
import "../evmscript/EVMScriptRunner.sol";
// Contracts inheriting from AragonApp are, by default, immediately petrified upon deployment so
// that they can never be initialized.
// Unless overriden, this behaviour enforces those contracts to be usable only behind an AppProxy.
// ReentrancyGuard, EVMScriptRunner, and ACLSyntaxSugar are not directly used by this contract, but
// are included so that they are automatically usable by subclassing contracts
contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, ReentrancyGuard, EVMScriptRunner, ACLSyntaxSugar {
string private constant ERROR_AUTH_FAILED = "APP_AUTH_FAILED";
modifier auth(bytes32 _role) {
require(canPerform(msg.sender, _role, new uint256[](0)), ERROR_AUTH_FAILED);
_;
}
modifier authP(bytes32 _role, uint256[] _params) {
require(canPerform(msg.sender, _role, _params), ERROR_AUTH_FAILED);
_;
}
/**
* @dev Check whether an action can be performed by a sender for a particular role on this app
* @param _sender Sender of the call
* @param _role Role on this app
* @param _params Permission params for the role
* @return Boolean indicating whether the sender has the permissions to perform the action.
* Always returns false if the app hasn't been initialized yet.
*/
function canPerform(address _sender, bytes32 _role, uint256[] _params) public view returns (bool) {
if (!hasInitialized()) {
return false;
}
IKernel linkedKernel = kernel();
if (address(linkedKernel) == address(0)) {
return false;
}
return linkedKernel.hasPermission(
_sender,
address(this),
_role,
ConversionHelpers.dangerouslyCastUintArrayToBytes(_params)
);
}
/**
* @dev Get the recovery vault for the app
* @return Recovery vault address for the app
*/
function getRecoveryVault() public view returns (address) {
// Funds recovery via a vault is only available when used with a kernel
return kernel().getRecoveryVault(); // if kernel is not set, it will revert
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./Petrifiable.sol";
contract Autopetrified is Petrifiable {
constructor() public {
// Immediately petrify base (non-proxy) instances of inherited contracts on deploy.
// This renders them uninitializable (and unusable without a proxy).
petrify();
}
}pragma solidity ^0.4.24;
library ConversionHelpers {
string private constant ERROR_IMPROPER_LENGTH = "CONVERSION_IMPROPER_LENGTH";
function dangerouslyCastUintArrayToBytes(uint256[] memory _input) internal pure returns (bytes memory output) {
// Force cast the uint256[] into a bytes array, by overwriting its length
// Note that the bytes array doesn't need to be initialized as we immediately overwrite it
// with the input and a new length. The input becomes invalid from this point forward.
uint256 byteLength = _input.length * 32;
assembly {
output := _input
mstore(output, byteLength)
}
}
function dangerouslyCastBytesToUintArray(bytes memory _input) internal pure returns (uint256[] memory output) {
// Force cast the bytes array into a uint256[], by overwriting its length
// Note that the uint256[] doesn't need to be initialized as we immediately overwrite it
// with the input and a new length. The input becomes invalid from this point forward.
uint256 intsLength = _input.length / 32;
require(_input.length == intsLength * 32, ERROR_IMPROPER_LENGTH);
assembly {
output := _input
mstore(output, intsLength)
}
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
// aragonOS and aragon-apps rely on address(0) to denote native ETH, in
// contracts where both tokens and ETH are accepted
contract EtherTokenConstant {
address internal constant ETH = address(0);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./TimeHelpers.sol";
import "./UnstructuredStorage.sol";
contract Initializable is TimeHelpers {
using UnstructuredStorage for bytes32;
// keccak256("aragonOS.initializable.initializationBlock")
bytes32 internal constant INITIALIZATION_BLOCK_POSITION = 0xebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e;
string private constant ERROR_ALREADY_INITIALIZED = "INIT_ALREADY_INITIALIZED";
string private constant ERROR_NOT_INITIALIZED = "INIT_NOT_INITIALIZED";
modifier onlyInit {
require(getInitializationBlock() == 0, ERROR_ALREADY_INITIALIZED);
_;
}
modifier isInitialized {
require(hasInitialized(), ERROR_NOT_INITIALIZED);
_;
}
/**
* @return Block number in which the contract was initialized
*/
function getInitializationBlock() public view returns (uint256) {
return INITIALIZATION_BLOCK_POSITION.getStorageUint256();
}
/**
* @return Whether the contract has been initialized by the time of the current block
*/
function hasInitialized() public view returns (bool) {
uint256 initializationBlock = getInitializationBlock();
return initializationBlock != 0 && getBlockNumber() >= initializationBlock;
}
/**
* @dev Function to be called by top level contract after initialization has finished.
*/
function initialized() internal onlyInit {
INITIALIZATION_BLOCK_POSITION.setStorageUint256(getBlockNumber());
}
/**
* @dev Function to be called by top level contract after initialization to enable the contract
* at a future block number rather than immediately.
*/
function initializedAt(uint256 _blockNumber) internal onlyInit {
INITIALIZATION_BLOCK_POSITION.setStorageUint256(_blockNumber);
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
contract IsContract {
/*
* NOTE: this should NEVER be used for authentication
* (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
*
* This is only intended to be used as a sanity check that an address is actually a contract,
* RATHER THAN an address not being a contract.
*/
function isContract(address _target) internal view returns (bool) {
if (_target == address(0)) {
return false;
}
uint256 size;
assembly { size := extcodesize(_target) }
return size > 0;
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
interface IVaultRecoverable {
event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
function transferToVault(address token) external;
function allowRecoverability(address token) external view returns (bool);
function getRecoveryVault() external view returns (address);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./Initializable.sol";
contract Petrifiable is Initializable {
// Use block UINT256_MAX (which should be never) as the initializable date
uint256 internal constant PETRIFIED_BLOCK = uint256(-1);
function isPetrified() public view returns (bool) {
return getInitializationBlock() == PETRIFIED_BLOCK;
}
/**
* @dev Function to be called by top level contract to prevent being initialized.
* Useful for freezing base contracts when they're used behind proxies.
*/
function petrify() internal onlyInit {
initializedAt(PETRIFIED_BLOCK);
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../common/UnstructuredStorage.sol";
contract ReentrancyGuard {
using UnstructuredStorage for bytes32;
/* Hardcoded constants to save gas
bytes32 internal constant REENTRANCY_MUTEX_POSITION = keccak256("aragonOS.reentrancyGuard.mutex");
*/
bytes32 private constant REENTRANCY_MUTEX_POSITION = 0xe855346402235fdd185c890e68d2c4ecad599b88587635ee285bce2fda58dacb;
string private constant ERROR_REENTRANT = "REENTRANCY_REENTRANT_CALL";
modifier nonReentrant() {
// Ensure mutex is unlocked
require(!REENTRANCY_MUTEX_POSITION.getStorageBool(), ERROR_REENTRANT);
// Lock mutex before function call
REENTRANCY_MUTEX_POSITION.setStorageBool(true);
// Perform function call
_;
// Unlock mutex after function call
REENTRANCY_MUTEX_POSITION.setStorageBool(false);
}
}// Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol)
// and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143)
pragma solidity ^0.4.24;
import "../lib/token/ERC20.sol";
library SafeERC20 {
// Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`:
// https://github.com/ethereum/solidity/issues/3544
bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb;
string private constant ERROR_TOKEN_BALANCE_REVERTED = "SAFE_ERC_20_BALANCE_REVERTED";
string private constant ERROR_TOKEN_ALLOWANCE_REVERTED = "SAFE_ERC_20_ALLOWANCE_REVERTED";
function invokeAndCheckSuccess(address _addr, bytes memory _calldata)
private
returns (bool)
{
bool ret;
assembly {
let ptr := mload(0x40) // free memory pointer
let success := call(
gas, // forward all gas
_addr, // address
0, // no value
add(_calldata, 0x20), // calldata start
mload(_calldata), // calldata length
ptr, // write output over free memory
0x20 // uint256 return
)
if gt(success, 0) {
// Check number of bytes returned from last function call
switch returndatasize
// No bytes returned: assume success
case 0 {
ret := 1
}
// 32 bytes returned: check if non-zero
case 0x20 {
// Only return success if returned data was true
// Already have output in ptr
ret := eq(mload(ptr), 1)
}
// Not sure what was returned: don't mark as success
default { }
}
}
return ret;
}
function staticInvoke(address _addr, bytes memory _calldata)
private
view
returns (bool, uint256)
{
bool success;
uint256 ret;
assembly {
let ptr := mload(0x40) // free memory pointer
success := staticcall(
gas, // forward all gas
_addr, // address
add(_calldata, 0x20), // calldata start
mload(_calldata), // calldata length
ptr, // write output over free memory
0x20 // uint256 return
)
if gt(success, 0) {
ret := mload(ptr)
}
}
return (success, ret);
}
/**
* @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false).
* Note that this makes an external call to the token.
*/
function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) {
bytes memory transferCallData = abi.encodeWithSelector(
TRANSFER_SELECTOR,
_to,
_amount
);
return invokeAndCheckSuccess(_token, transferCallData);
}
/**
* @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false).
* Note that this makes an external call to the token.
*/
function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) {
bytes memory transferFromCallData = abi.encodeWithSelector(
_token.transferFrom.selector,
_from,
_to,
_amount
);
return invokeAndCheckSuccess(_token, transferFromCallData);
}
/**
* @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false).
* Note that this makes an external call to the token.
*/
function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) {
bytes memory approveCallData = abi.encodeWithSelector(
_token.approve.selector,
_spender,
_amount
);
return invokeAndCheckSuccess(_token, approveCallData);
}
/**
* @dev Static call into ERC20.balanceOf().
* Reverts if the call fails for some reason (should never fail).
*/
function staticBalanceOf(ERC20 _token, address _owner) internal view returns (uint256) {
bytes memory balanceOfCallData = abi.encodeWithSelector(
_token.balanceOf.selector,
_owner
);
(bool success, uint256 tokenBalance) = staticInvoke(_token, balanceOfCallData);
require(success, ERROR_TOKEN_BALANCE_REVERTED);
return tokenBalance;
}
/**
* @dev Static call into ERC20.allowance().
* Reverts if the call fails for some reason (should never fail).
*/
function staticAllowance(ERC20 _token, address _owner, address _spender) internal view returns (uint256) {
bytes memory allowanceCallData = abi.encodeWithSelector(
_token.allowance.selector,
_owner,
_spender
);
(bool success, uint256 allowance) = staticInvoke(_token, allowanceCallData);
require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
return allowance;
}
/**
* @dev Static call into ERC20.totalSupply().
* Reverts if the call fails for some reason (should never fail).
*/
function staticTotalSupply(ERC20 _token) internal view returns (uint256) {
bytes memory totalSupplyCallData = abi.encodeWithSelector(_token.totalSupply.selector);
(bool success, uint256 totalSupply) = staticInvoke(_token, totalSupplyCallData);
require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
return totalSupply;
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./Uint256Helpers.sol";
contract TimeHelpers {
using Uint256Helpers for uint256;
/**
* @dev Returns the current block number.
* Using a function rather than `block.number` allows us to easily mock the block number in
* tests.
*/
function getBlockNumber() internal view returns (uint256) {
return block.number;
}
/**
* @dev Returns the current block number, converted to uint64.
* Using a function rather than `block.number` allows us to easily mock the block number in
* tests.
*/
function getBlockNumber64() internal view returns (uint64) {
return getBlockNumber().toUint64();
}
/**
* @dev Returns the current timestamp.
* Using a function rather than `block.timestamp` allows us to easily mock it in
* tests.
*/
function getTimestamp() internal view returns (uint256) {
return block.timestamp; // solium-disable-line security/no-block-members
}
/**
* @dev Returns the current timestamp, converted to uint64.
* Using a function rather than `block.timestamp` allows us to easily mock it in
* tests.
*/
function getTimestamp64() internal view returns (uint64) {
return getTimestamp().toUint64();
}
}pragma solidity ^0.4.24;
library Uint256Helpers {
uint256 private constant MAX_UINT64 = uint64(-1);
string private constant ERROR_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG";
function toUint64(uint256 a) internal pure returns (uint64) {
require(a <= MAX_UINT64, ERROR_NUMBER_TOO_BIG);
return uint64(a);
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
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
*/
pragma solidity ^0.4.24;
import "../lib/token/ERC20.sol";
import "./EtherTokenConstant.sol";
import "./IsContract.sol";
import "./IVaultRecoverable.sol";
import "./SafeERC20.sol";
contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract {
using SafeERC20 for ERC20;
string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED";
string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT";
string private constant ERROR_TOKEN_TRANSFER_FAILED = "RECOVER_TOKEN_TRANSFER_FAILED";
/**
* @notice Send funds to recovery Vault. This contract should never receive funds,
* but in case it does, this function allows one to recover them.
* @param _token Token balance to be sent to recovery vault.
*/
function transferToVault(address _token) external {
require(allowRecoverability(_token), ERROR_DISALLOWED);
address vault = getRecoveryVault();
require(isContract(vault), ERROR_VAULT_NOT_CONTRACT);
uint256 balance;
if (_token == ETH) {
balance = address(this).balance;
vault.transfer(balance);
} else {
ERC20 token = ERC20(_token);
balance = token.staticBalanceOf(this);
require(token.safeTransfer(vault, balance), ERROR_TOKEN_TRANSFER_FAILED);
}
emit RecoverToVault(vault, _token, balance);
}
/**
* @dev By default deriving from AragonApp makes it recoverable
* @param token Token address that would be recovered
* @return bool whether the app allows the recovery
*/
function allowRecoverability(address token) public view returns (bool) {
return true;
}
// Cast non-implemented interface to be public so we can use it internally
function getRecoveryVault() public view returns (address);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./IEVMScriptExecutor.sol";
import "./IEVMScriptRegistry.sol";
import "../apps/AppStorage.sol";
import "../kernel/KernelConstants.sol";
import "../common/Initializable.sol";
contract EVMScriptRunner is AppStorage, Initializable, EVMScriptRegistryConstants, KernelNamespaceConstants {
string private constant ERROR_EXECUTOR_UNAVAILABLE = "EVMRUN_EXECUTOR_UNAVAILABLE";
string private constant ERROR_PROTECTED_STATE_MODIFIED = "EVMRUN_PROTECTED_STATE_MODIFIED";
/* This is manually crafted in assembly
string private constant ERROR_EXECUTOR_INVALID_RETURN = "EVMRUN_EXECUTOR_INVALID_RETURN";
*/
event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData);
function getEVMScriptExecutor(bytes _script) public view returns (IEVMScriptExecutor) {
return IEVMScriptExecutor(getEVMScriptRegistry().getScriptExecutor(_script));
}
function getEVMScriptRegistry() public view returns (IEVMScriptRegistry) {
address registryAddr = kernel().getApp(KERNEL_APP_ADDR_NAMESPACE, EVMSCRIPT_REGISTRY_APP_ID);
return IEVMScriptRegistry(registryAddr);
}
function runScript(bytes _script, bytes _input, address[] _blacklist)
internal
isInitialized
protectState
returns (bytes)
{
IEVMScriptExecutor executor = getEVMScriptExecutor(_script);
require(address(executor) != address(0), ERROR_EXECUTOR_UNAVAILABLE);
bytes4 sig = executor.execScript.selector;
bytes memory data = abi.encodeWithSelector(sig, _script, _input, _blacklist);
bytes memory output;
assembly {
let success := delegatecall(
gas, // forward all gas
executor, // address
add(data, 0x20), // calldata start
mload(data), // calldata length
0, // don't write output (we'll handle this ourselves)
0 // don't write output
)
output := mload(0x40) // free mem ptr get
switch success
case 0 {
// If the call errored, forward its full error data
returndatacopy(output, 0, returndatasize)
revert(output, returndatasize)
}
default {
switch gt(returndatasize, 0x3f)
case 0 {
// Need at least 0x40 bytes returned for properly ABI-encoded bytes values,
// revert with "EVMRUN_EXECUTOR_INVALID_RETURN"
// See remix: doing a `revert("EVMRUN_EXECUTOR_INVALID_RETURN")` always results in
// this memory layout
mstore(output, 0x08c379a000000000000000000000000000000000000000000000000000000000) // error identifier
mstore(add(output, 0x04), 0x0000000000000000000000000000000000000000000000000000000000000020) // starting offset
mstore(add(output, 0x24), 0x000000000000000000000000000000000000000000000000000000000000001e) // reason length
mstore(add(output, 0x44), 0x45564d52554e5f4558454355544f525f494e56414c49445f52455455524e0000) // reason
revert(output, 100) // 100 = 4 + 3 * 32 (error identifier + 3 words for the ABI encoded error)
}
default {
// Copy result
//
// Needs to perform an ABI decode for the expected `bytes` return type of
// `executor.execScript()` as solidity will automatically ABI encode the returned bytes as:
// [ position of the first dynamic length return value = 0x20 (32 bytes) ]
// [ output length (32 bytes) ]
// [ output content (N bytes) ]
//
// Perform the ABI decode by ignoring the first 32 bytes of the return data
let copysize := sub(returndatasize, 0x20)
returndatacopy(output, 0x20, copysize)
mstore(0x40, add(output, copysize)) // free mem ptr set
}
}
}
emit ScriptResult(address(executor), _script, _input, output);
return output;
}
modifier protectState {
address preKernel = address(kernel());
bytes32 preAppId = appId();
_; // exec
require(address(kernel()) == preKernel, ERROR_PROTECTED_STATE_MODIFIED);
require(appId() == preAppId, ERROR_PROTECTED_STATE_MODIFIED);
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
interface IEVMScriptExecutor {
function execScript(bytes script, bytes input, address[] blacklist) external returns (bytes);
function executorType() external pure returns (bytes32);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./IEVMScriptExecutor.sol";
contract EVMScriptRegistryConstants {
/* Hardcoded constants to save gas
bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = apmNamehash("evmreg");
*/
bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = 0xddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd61;
}
interface IEVMScriptRegistry {
function addScriptExecutor(IEVMScriptExecutor executor) external returns (uint id);
function disableScriptExecutor(uint256 executorId) external;
// TODO: this should be external
// See https://github.com/ethereum/solidity/issues/4832
function getScriptExecutor(bytes script) public view returns (IEVMScriptExecutor);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../acl/IACL.sol";
import "../common/IVaultRecoverable.sol";
interface IKernelEvents {
event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
}
// This should be an interface, but interfaces can't inherit yet :(
contract IKernel is IKernelEvents, IVaultRecoverable {
function acl() public view returns (IACL);
function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
function setApp(bytes32 namespace, bytes32 appId, address app) public;
function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
contract KernelAppIds {
/* Hardcoded constants to save gas
bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
*/
bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
}
contract KernelNamespaceConstants {
/* Hardcoded constants to save gas
bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
*/
bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
}// See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol
// Adapted to use pragma ^0.4.24 and satisfy our linter rules
pragma solidity ^0.4.24;
/**
* @title SafeMath
* @dev Math operations with safety checks that revert on error
*/
library SafeMath {
string private constant ERROR_ADD_OVERFLOW = "MATH_ADD_OVERFLOW";
string private constant ERROR_SUB_UNDERFLOW = "MATH_SUB_UNDERFLOW";
string private constant ERROR_MUL_OVERFLOW = "MATH_MUL_OVERFLOW";
string private constant ERROR_DIV_ZERO = "MATH_DIV_ZERO";
/**
* @dev Multiplies two numbers, reverts on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (_a == 0) {
return 0;
}
uint256 c = _a * _b;
require(c / _a == _b, ERROR_MUL_OVERFLOW);
return c;
}
/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*/
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0
uint256 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
require(_b <= _a, ERROR_SUB_UNDERFLOW);
uint256 c = _a - _b;
return c;
}
/**
* @dev Adds two numbers, reverts on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns (uint256) {
uint256 c = _a + _b;
require(c >= _a, ERROR_ADD_OVERFLOW);
return c;
}
/**
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, ERROR_DIV_ZERO);
return a % b;
}
}// See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol
// Adapted for uint64, pragma ^0.4.24, and satisfying our linter rules
// Also optimized the mul() implementation, see https://github.com/aragon/aragonOS/pull/417
pragma solidity ^0.4.24;
/**
* @title SafeMath64
* @dev Math operations for uint64 with safety checks that revert on error
*/
library SafeMath64 {
string private constant ERROR_ADD_OVERFLOW = "MATH64_ADD_OVERFLOW";
string private constant ERROR_SUB_UNDERFLOW = "MATH64_SUB_UNDERFLOW";
string private constant ERROR_MUL_OVERFLOW = "MATH64_MUL_OVERFLOW";
string private constant ERROR_DIV_ZERO = "MATH64_DIV_ZERO";
/**
* @dev Multiplies two numbers, reverts on overflow.
*/
function mul(uint64 _a, uint64 _b) internal pure returns (uint64) {
uint256 c = uint256(_a) * uint256(_b);
require(c < 0x010000000000000000, ERROR_MUL_OVERFLOW); // 2**64 (less gas this way)
return uint64(c);
}
/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*/
function div(uint64 _a, uint64 _b) internal pure returns (uint64) {
require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0
uint64 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint64 _a, uint64 _b) internal pure returns (uint64) {
require(_b <= _a, ERROR_SUB_UNDERFLOW);
uint64 c = _a - _b;
return c;
}
/**
* @dev Adds two numbers, reverts on overflow.
*/
function add(uint64 _a, uint64 _b) internal pure returns (uint64) {
uint64 c = _a + _b;
require(c >= _a, ERROR_ADD_OVERFLOW);
return c;
}
/**
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint64 a, uint64 b) internal pure returns (uint64) {
require(b != 0, ERROR_DIV_ZERO);
return a % b;
}
}// See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/ERC20.sol
pragma solidity ^0.4.24;
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 {
function totalSupply() public view returns (uint256);
function balanceOf(address _who) public view returns (uint256);
function allowance(address _owner, address _spender)
public view returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
function approve(address _spender, uint256 _value)
public returns (bool);
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool);
event Transfer(
address indexed from,
address indexed to,
uint256 value
);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}// 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; import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol"; /// @notice Provides an interface for gas-efficient operations on four uint64 type /// variables tightly packed into one uint256 variable stored in memory library Packed64x4 { using SafeMath for uint256; using Packed64x4 for Packed64x4.Packed; uint256 internal constant UINT64_MAX = 0xFFFFFFFFFFFFFFFF; struct Packed { uint256 v; } /// @dev Returns uint64 variable stored on position `n` as uint256 function get(Packed memory _self, uint8 n) internal pure returns (uint256 r) { r = (_self.v >> (64 * n)) & UINT64_MAX; } /// @dev Writes value stored in passed `x` variable on position `n`. /// The passed value must be less or equal to UINT64_MAX. /// If the passed value exceeds UINT64_MAX method will /// revert with a "PACKED_OVERFLOW" error message function set(Packed memory _self, uint8 n, uint256 x) internal pure { require(x <= UINT64_MAX, "PACKED_OVERFLOW"); _self.v = _self.v & ~(UINT64_MAX << (64 * n)) | ((x & UINT64_MAX) << (64 * n)); } /// @dev Adds value stored in passed `x` variable to variable stored on position `n` /// using SafeMath lib function add(Packed memory _self, uint8 n, uint256 x) internal pure { set(_self, n, get(_self, n).add(x)); } /// @dev Subtract value stored in passed `x` variable from variable stored on position `n` /// using SafeMath lib function sub(Packed memory _self, uint8 n, uint256 x) internal pure { set(_self, n, get(_self, n).sub(x)); } }
// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 // See contracts/COMPILERS.md pragma solidity 0.4.24; import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol"; import {SafeMath64} from "@aragon/os/contracts/lib/math/SafeMath64.sol"; /// @title Library for manage operator keys in storage /// @author KRogLA library SigningKeys { using SafeMath for uint256; using SafeMath64 for uint64; using SigningKeys for bytes32; uint64 internal constant PUBKEY_LENGTH = 48; uint64 internal constant SIGNATURE_LENGTH = 96; uint256 internal constant UINT64_MAX = 0xFFFFFFFFFFFFFFFF; event SigningKeyAdded(uint256 indexed nodeOperatorId, bytes pubkey); event SigningKeyRemoved(uint256 indexed nodeOperatorId, bytes pubkey); function getKeyOffset(bytes32 _position, uint256 _nodeOperatorId, uint256 _keyIndex) internal pure returns (uint256) { return uint256(keccak256(abi.encodePacked(_position, _nodeOperatorId, _keyIndex))); } /// @dev store opeartor keys to storage /// @param _position storage slot /// @param _nodeOperatorId operator id /// @param _startIndex start index /// @param _keysCount keys count to load /// @param _pubkeys kes buffer to read from /// @param _signatures signatures buffer to read from /// @return new total keys count function saveKeysSigs( bytes32 _position, uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount, bytes _pubkeys, bytes _signatures ) internal returns (uint256) { require(_keysCount > 0 && _startIndex.add(_keysCount) <= UINT64_MAX, "INVALID_KEYS_COUNT"); require( _pubkeys.length == _keysCount.mul(PUBKEY_LENGTH) && _signatures.length == _keysCount.mul(SIGNATURE_LENGTH), "LENGTH_MISMATCH" ); uint256 curOffset; bool isEmpty; bytes memory tmpKey = new bytes(48); for (uint256 i; i < _keysCount;) { curOffset = _position.getKeyOffset(_nodeOperatorId, _startIndex); assembly { let _ofs := add(add(_pubkeys, 0x20), mul(i, 48)) //PUBKEY_LENGTH = 48 let _part1 := mload(_ofs) // bytes 0..31 let _part2 := mload(add(_ofs, 0x10)) // bytes 16..47 isEmpty := iszero(or(_part1, _part2)) mstore(add(tmpKey, 0x30), _part2) // store 2nd part first mstore(add(tmpKey, 0x20), _part1) // store 1st part with overwrite bytes 16-31 } require(!isEmpty, "EMPTY_KEY"); assembly { // store key sstore(curOffset, mload(add(tmpKey, 0x20))) // store bytes 0..31 sstore(add(curOffset, 1), shl(128, mload(add(tmpKey, 0x30)))) // store bytes 32..47 // store signature let _ofs := add(add(_signatures, 0x20), mul(i, 96)) //SIGNATURE_LENGTH = 96 sstore(add(curOffset, 2), mload(_ofs)) sstore(add(curOffset, 3), mload(add(_ofs, 0x20))) sstore(add(curOffset, 4), mload(add(_ofs, 0x40))) i := add(i, 1) _startIndex := add(_startIndex, 1) } emit SigningKeyAdded(_nodeOperatorId, tmpKey); } return _startIndex; } /// @dev remove opeartor keys from storage /// @param _position storage slot /// @param _nodeOperatorId operator id /// @param _startIndex start index /// @param _keysCount keys count to load /// @param _totalKeysCount current total keys count for operator /// @return new _totalKeysCount function removeKeysSigs( bytes32 _position, uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount, uint256 _totalKeysCount ) internal returns (uint256) { require( _keysCount > 0 && _startIndex.add(_keysCount) <= _totalKeysCount && _totalKeysCount <= UINT64_MAX, "INVALID_KEYS_COUNT" ); uint256 curOffset; uint256 lastOffset; uint256 j; bytes memory tmpKey = new bytes(48); // removing from the last index for (uint256 i = _startIndex + _keysCount; i > _startIndex;) { curOffset = _position.getKeyOffset(_nodeOperatorId, i - 1); assembly { // read key mstore(add(tmpKey, 0x30), shr(128, sload(add(curOffset, 1)))) // bytes 16..47 mstore(add(tmpKey, 0x20), sload(curOffset)) // bytes 0..31 } if (i < _totalKeysCount) { lastOffset = _position.getKeyOffset(_nodeOperatorId, _totalKeysCount - 1); // move last key to deleted key index for (j = 0; j < 5;) { assembly { sstore(add(curOffset, j), sload(add(lastOffset, j))) j := add(j, 1) } } curOffset = lastOffset; } // clear storage for (j = 0; j < 5;) { assembly { sstore(add(curOffset, j), 0) j := add(j, 1) } } assembly { _totalKeysCount := sub(_totalKeysCount, 1) i := sub(i, 1) } emit SigningKeyRemoved(_nodeOperatorId, tmpKey); } return _totalKeysCount; } /// @dev laod opeartor keys from storage /// @param _position storage slot /// @param _nodeOperatorId operator id /// @param _startIndex start index /// @param _keysCount keys count to load /// @param _pubkeys preallocated kes buffer to read in /// @param _signatures preallocated signatures buffer to read in /// @param _bufOffset start offset in `_pubkeys`/`_signatures` buffer to place values (in number of keys) function loadKeysSigs( bytes32 _position, uint256 _nodeOperatorId, uint256 _startIndex, uint256 _keysCount, bytes memory _pubkeys, bytes memory _signatures, uint256 _bufOffset ) internal view { uint256 curOffset; for (uint256 i; i < _keysCount;) { curOffset = _position.getKeyOffset(_nodeOperatorId, _startIndex + i); assembly { // read key let _ofs := add(add(_pubkeys, 0x20), mul(add(_bufOffset, i), 48)) //PUBKEY_LENGTH = 48 mstore(add(_ofs, 0x10), shr(128, sload(add(curOffset, 1)))) // bytes 16..47 mstore(_ofs, sload(curOffset)) // bytes 0..31 // store signature _ofs := add(add(_signatures, 0x20), mul(add(_bufOffset, i), 96)) //SIGNATURE_LENGTH = 96 mstore(_ofs, sload(add(curOffset, 2))) mstore(add(_ofs, 0x20), sload(add(curOffset, 3))) mstore(add(_ofs, 0x40), sload(add(curOffset, 4))) i := add(i, 1) } } } function initKeysSigsBuf(uint256 _count) internal pure returns (bytes memory, bytes memory) { return (new bytes(_count.mul(PUBKEY_LENGTH)), new bytes(_count.mul(SIGNATURE_LENGTH))); } }
// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.4.24; import "@aragon/os/contracts/common/UnstructuredStorage.sol"; /** * @title Adapted code of /contracts/0.8.9/utils/Versioned.sol * * This contract contains only core part of original Versioned.sol * to reduce contract size */ contract Versioned { using UnstructuredStorage for bytes32; event ContractVersionSet(uint256 version); /// @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 = 0x4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6; // keccak256("lido.Versioned.contractVersion"); uint256 internal constant PETRIFIED_VERSION_MARK = uint256(-1); constructor() public { // 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 { require(version == getContractVersion(), "UNEXPECTED_CONTRACT_VERSION"); } function _setContractVersion(uint256 version) internal { CONTRACT_VERSION_POSITION.setStorageUint256(version); emit ContractVersionSet(version); } }
// 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; interface IBurner { /** * Commit cover/non-cover burning requests and logs cover/non-cover shares amount just burnt. * * NB: The real burn enactment to be invoked after the call (via internal Lido._burnShares()) */ function commitSharesToBurn(uint256 _stETHSharesToBurn) external; /** * Request burn shares */ function requestBurnShares(address _from, uint256 _sharesAmount) external; /** * Returns the current amount of shares locked on the contract to be burnt. */ function getSharesRequestedToBurn() external view returns (uint256 coverShares, uint256 nonCoverShares); /** * Returns the total cover shares ever burnt. */ function getCoverSharesBurnt() external view returns (uint256); /** * Returns the total non-cover shares ever burnt. */ function getNonCoverSharesBurnt() external view returns (uint256); }
// 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; interface ILidoLocator { function accountingOracle() external view returns(address); function depositSecurityModule() external view returns(address); function elRewardsVault() external view returns(address); function lido() external view returns(address); function oracleReportSanityChecker() external view returns(address); function burner() external view returns(address); function stakingRouter() external view returns(address); function treasury() external view returns(address); function validatorsExitBusOracle() external view returns(address); function withdrawalQueue() external view returns(address); function withdrawalVault() external view returns(address); function postTokenRebaseReceiver() external view returns(address); function oracleDaemonConfig() external view returns(address); function accounting() external view returns (address); function predepositGuarantee() external view returns (address); function wstETH() external view returns (address); function vaultHub() external view returns (address); function operatorGrid() external view returns (address); /// @notice Returns core Lido protocol component addresses in a single call /// @dev This function provides a gas-efficient way to fetch multiple component addresses in a single call function coreComponents() external view returns( address elRewardsVault, address oracleReportSanityChecker, address stakingRouter, address treasury, address withdrawalQueue, address withdrawalVault ); /// @notice Returns addresses of components involved in processing oracle reports in the Lido contract /// @dev This function provides a gas-efficient way to fetch multiple component addresses in a single call function oracleReportComponents() external view returns( address accountingOracle, address oracleReportSanityChecker, address burner, address withdrawalQueue, address postTokenRebaseReceiver, address stakingRouter, address vaultHub ); }
// 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 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": "constantinople",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/common/lib/MinFirstAllocationStrategy.sol": {
"MinFirstAllocationStrategy": "0x9b322efdb04840052f97649fd0c27b678de88da2"
}
}
}Contract ABI
API[{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_targetLimitMode","type":"uint256"},{"name":"_targetLimit","type":"uint256"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getType","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"clearNodeOperatorPenalty","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getNodeOperatorIds","outputs":[{"name":"nodeOperatorIds","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_offset","type":"uint256"},{"name":"_limit","type":"uint256"}],"name":"getSigningKeys","outputs":[{"name":"pubkeys","type":"bytes"},{"name":"signatures","type":"bytes"},{"name":"used","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorIsActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_name","type":"string"}],"name":"setNodeOperatorName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_totalRewardShares","type":"uint256"}],"name":"getRewardsDistribution","outputs":[{"name":"recipients","type":"address[]"},{"name":"shares","type":"uint256[]"},{"name":"penalized","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_indexFrom","type":"uint256"},{"name":"_indexTo","type":"uint256"}],"name":"invalidateReadyToDepositKeysRange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_delay","type":"uint256"}],"name":"setStuckPenaltyDelay","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"finalizeUpgrade_v3","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStuckPenaltyDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getRewardDistributionState","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fromIndex","type":"uint256"},{"name":"_keysCount","type":"uint256"}],"name":"removeSigningKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenalized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"deactivateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_ROUTER_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_keysCount","type":"uint256"},{"name":"_publicKeys","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"addSigningKeysOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getActiveNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_rewardAddress","type":"address"}],"name":"addNodeOperator","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getUnusedSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","type":"uint256"}],"name":"onRewardsMinted","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_NODE_OPERATOR_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"distributeReward","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"onWithdrawalCredentialsChanged","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"activateNodeOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_rewardAddress","type":"address"}],"name":"setNodeOperatorRewardAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_fullInfo","type":"bool"}],"name":"getNodeOperator","outputs":[{"name":"active","type":"bool"},{"name":"name","type":"string"},{"name":"rewardAddress","type":"address"},{"name":"totalVettedValidators","type":"uint64"},{"name":"totalExitedValidators","type":"uint64"},{"name":"totalAddedValidators","type":"uint64"},{"name":"totalDepositedValidators","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_locator","type":"address"},{"name":"_type","type":"bytes32"},{"name":"_stuckPenaltyDelay","type":"uint256"}],"name":"finalizeUpgrade_v2","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakingModuleSummary","outputs":[{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_exitedValidatorsCounts","type":"bytes"}],"name":"updateExitedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_stuckValidatorsCounts","type":"bytes"}],"name":"updateStuckValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_refundedValidatorsCount","type":"uint256"}],"name":"updateRefundedValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNodeOperatorsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_isTargetLimitActive","type":"bool"},{"name":"_targetLimit","type":"uint256"}],"name":"updateTargetValidatorsLimits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_vettedSigningKeysCount","type":"uint64"}],"name":"setNodeOperatorStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getNodeOperatorSummary","outputs":[{"name":"targetLimitMode","type":"uint256"},{"name":"targetValidatorsCount","type":"uint256"},{"name":"stuckValidatorsCount","type":"uint256"},{"name":"refundedValidatorsCount","type":"uint256"},{"name":"stuckPenaltyEndTimestamp","type":"uint256"},{"name":"totalExitedValidators","type":"uint256"},{"name":"totalDepositedValidators","type":"uint256"},{"name":"depositableValidatorsCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"getSigningKey","outputs":[{"name":"key","type":"bytes"},{"name":"depositSignature","type":"bytes"},{"name":"used","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorIds","type":"bytes"},{"name":"_vettedSigningKeysCounts","type":"bytes"}],"name":"decreaseVettedSigningKeysCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_depositsCount","type":"uint256"},{"name":"","type":"bytes"}],"name":"obtainDepositData","outputs":[{"name":"publicKeys","type":"bytes"},{"name":"signatures","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getKeysOpIndex","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNonce","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"getTotalSigningKeyCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_STUCK_PENALTY_DELAY","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"onExitedAndStuckValidatorsCountsUpdated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_NODE_OPERATORS_COUNT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"removeSigningKeyOperatorBH","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_nodeOperatorId","type":"uint256"},{"name":"_exitedValidatorsCount","type":"uint256"},{"name":"_stuckValidatorsCount","type":"uint256"}],"name":"unsafeUpdateValidatorsCount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_SIGNING_KEYS","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_nodeOperatorId","type":"uint256"}],"name":"isOperatorPenaltyCleared","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"},{"indexed":false,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"stakingLimit","type":"uint64"}],"name":"NodeOperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"NodeOperatorActiveSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"name","type":"string"}],"name":"NodeOperatorNameSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"rewardAddress","type":"address"}],"name":"NodeOperatorRewardAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalKeysTrimmed","type":"uint64"}],"name":"NodeOperatorTotalKeysTrimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keysOpIndex","type":"uint256"}],"name":"KeysOpIndexSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"moduleType","type":"bytes32"}],"name":"StakingModuleTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"rewardAddress","type":"address"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"RewardsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"state","type":"uint8"}],"name":"RewardDistributionStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"locatorAddress","type":"address"}],"name":"LocatorContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"approvedValidatorsCount","type":"uint256"}],"name":"VettedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"depositedValidatorsCount","type":"uint256"}],"name":"DepositedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"exitedValidatorsCount","type":"uint256"}],"name":"ExitedSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"totalValidatorsCount","type":"uint256"}],"name":"TotalSigningKeysCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"nonce","type":"uint256"}],"name":"NonceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"stuckPenaltyDelay","type":"uint256"}],"name":"StuckPenaltyDelayChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"stuckValidatorsCount","type":"uint256"},{"indexed":false,"name":"refundedValidatorsCount","type":"uint256"},{"indexed":false,"name":"stuckPenaltyEndTimestamp","type":"uint256"}],"name":"StuckPenaltyStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"},{"indexed":false,"name":"targetValidatorsCount","type":"uint256"},{"indexed":false,"name":"targetLimitMode","type":"uint256"}],"name":"TargetValidatorsCountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"recipientAddress","type":"address"},{"indexed":false,"name":"sharesPenalizedAmount","type":"uint256"}],"name":"NodeOperatorPenalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"nodeOperatorId","type":"uint256"}],"name":"NodeOperatorPenaltyCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"}]Contract Creation Code
6080604052620000146200005460201b60201c565b6200004e7f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a660001962000156602090811b6200400c17901c565b6200026b565b620000646200015a60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a454400000000000000006020820152901562000140576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101562000104578181015183820152602001620000ea565b50505050905090810190601f168015620001325780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50620001546000196200018d60201b60201c565b565b9055565b6000620001886000805160206200605083398151915260001b600019166200026760201b6200344b1760201c565b905090565b6200019d6200015a60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156200023c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101562000104578181015183820152602001620000ea565b5062000264600080516020620060508339815191528262000156602090811b6200400c17901c565b50565b5490565b615dd5806200027b6000396000f3006080604052600436106103105760003560e01c63ffffffff1680630803fac01461031557806308a679ad1461033e578063096b7b351461035e57806315dae03e146103925780632914b9bd146103b957806330a90f011461042e57806332f0a3b5146104465780634febc81b1461045b57806359e25c12146104c65780635ddde810146106035780635e2fb908146106215780635e57d7421461063957806362dcfda11461065d57806365cc369a1461073a578063684560a2146107555780636ccc75621461077c5780636d395b7e146107945780636da7d0a7146107a95780636ef355f1146107be5780636f817294146107d95780637038b1411461060357806375049ad81461081257806375a080d51461082a5780637e7db6e11461084257806380231f1514610863578063805911ae1461035e57806380afdea8146108785780638469cbd31461088d57806385fa63d7146108a25780638aa10435146108d05780638b3dd749146108e55780638ca7c052146108fa5780638d7e4017146109125780638ece99951461092a5780638f73c5ae1461093f57806390c09bdb1461095457806391dcd6b214610969578063973e9328146109815780639a56983c146109a55780639a7c2ade14610a815780639abddf0914610aa85780639b00c14614610adb5780639b3d190014610b075780639d4941d814610b33578063a1658fad14610b54578063a2e080f114610bbb578063a479e50814610bd6578063a70c70e414610beb578063a9e7a84614610c00578063ae962acf14610c20578063b3076c3c14610c45578063b449402a14610c9e578063b497183314610da2578063b643189b14610db7578063bee41b5814610de3578063d07442f114610ee5578063d087d28814610ee5578063d4aae0c414610efa578063d8343dcb14610f0f578063d8e71cd114610f24578063db9887ea14610f39578063de4796ed14610f51578063e204d09b14610f66578063e864299e14610f7b578063ec5af3a414610f90578063ed5cfa41146107be578063f2e2ca6314610fa5578063f31bd9c114610fc3578063fbc77ef114610fd8575b600080fd5b34801561032157600080fd5b5061032a610ff0565b604080519115158252519081900360200190f35b34801561034a57600080fd5b5061035c60043560243560443561101a565b005b34801561036a57600080fd5b5061035c600480359060248035916044358083019290820135916064359182019101356110ec565b34801561039e57600080fd5b506103a761115d565b60408051918252519081900360200190f35b3480156103c557600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261041294369492936024939284019190819084018382808284375094975061118e9650505050505050565b60408051600160a060020a039092168252519081900360200190f35b34801561043a57600080fd5b5061032a600435611271565b34801561045257600080fd5b50610412611365565b34801561046757600080fd5b506104766004356024356113da565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104b257818101518382015260200161049a565b505050509050019250505060405180910390f35b3480156104d257600080fd5b506104e4600435602435604435611471565b60405180806020018060200180602001848103845287818151815260200191508051906020019080838360005b83811015610529578181015183820152602001610511565b50505050905090810190601f1680156105565780820380516001836020036101000a031916815260200191505b50848103835286518152865160209182019188019080838360005b83811015610589578181015183820152602001610571565b50505050905090810190601f1680156105b65780820380516001836020036101000a031916815260200191505b508481038252855181528551602091820191808801910280838360005b838110156105eb5781810151838201526020016105d3565b50505050905001965050505050505060405180910390f35b34801561060f57600080fd5b5061035c60043560243560443561156f565b34801561062d57600080fd5b5061032a60043561157f565b34801561064557600080fd5b5061035c600480359060248035908101910135611594565b34801561066957600080fd5b5061067560043561170c565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156106bd5781810151838201526020016106a5565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156106fc5781810151838201526020016106e4565b5050505090500184810382528581815181526020019150805190602001906020028083836000838110156105eb5781810151838201526020016105d3565b34801561074657600080fd5b5061035c60043560243561193d565b34801561076157600080fd5b5061035c600160a060020a0360043516602435604435611962565b34801561078857600080fd5b5061035c600435611a47565b3480156107a057600080fd5b5061035c611a6a565b3480156107b557600080fd5b506103a7611b08565b3480156107ca57600080fd5b5061035c600435602435611b33565b3480156107e557600080fd5b506107ee611b3f565b604051808260028111156107fe57fe5b60ff16815260200191505060405180910390f35b34801561081e57600080fd5b5061032a600435611b79565b34801561083657600080fd5b5061035c600435611b9e565b34801561084e57600080fd5b5061032a600160a060020a0360043516611cee565b34801561086f57600080fd5b506103a7611cf4565b34801561088457600080fd5b506103a7611d06565b34801561089957600080fd5b506103a7611d31565b3480156108ae57600080fd5b506103a76024600480358281019291013590600160a060020a03903516611d4a565b3480156108dc57600080fd5b506103a7611f3b565b3480156108f157600080fd5b506103a7611f66565b34801561090657600080fd5b506103a7600435611f91565b34801561091e57600080fd5b5061035c600435611fe0565b34801561093657600080fd5b506103a7612001565b34801561094b57600080fd5b5061035c612013565b34801561096057600080fd5b5061035c61208f565b34801561097557600080fd5b5061035c6004356120c9565b34801561098d57600080fd5b5061035c600435600160a060020a036024351661217c565b3480156109b157600080fd5b506109c26004356024351515612248565b604080518815158152600160a060020a0387169181019190915267ffffffffffffffff8086166060830152848116608083015283811660a0830152821660c082015260e0602080830182815289519284019290925288516101008401918a019080838360005b83811015610a40578181015183820152602001610a28565b50505050905090810190601f168015610a6d5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b348015610a8d57600080fd5b5061035c600160a060020a036004351660243560443561239b565b348015610ab457600080fd5b50610abd6125b0565b60408051938452602084019290925282820152519081900360600190f35b348015610ae757600080fd5b5061035c602460048035828101929082013591813591820191013561260a565b348015610b1357600080fd5b5061035c60246004803582810192908201359181359182019101356126a3565b348015610b3f57600080fd5b5061035c600160a060020a0360043516612725565b348015610b6057600080fd5b50604080516020600460443581810135838102808601850190965280855261032a958335600160a060020a03169560248035963696956064959394920192918291850190849080828437509497506129b49650505050505050565b348015610bc757600080fd5b5061035c600435602435612b01565b348015610be257600080fd5b50610412612b33565b348015610bf757600080fd5b506103a7612be8565b348015610c0c57600080fd5b5061035c6004356024351515604435612c13565b348015610c2c57600080fd5b5061035c60043567ffffffffffffffff60243516612c2f565b348015610c5157600080fd5b50610c5d600435612c97565b604080519889526020890197909752878701959095526060870193909352608086019190915260a085015260c084015260e083015251908190036101000190f35b348015610caa57600080fd5b50610cb9600435602435612d53565b60405180806020018060200184151515158152602001838103835286818151815260200191508051906020019080838360005b83811015610d04578181015183820152602001610cec565b50505050905090810190601f168015610d315780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b83811015610d64578181015183820152602001610d4c565b50505050905090810190601f168015610d915780820380516001836020036101000a031916815260200191505b509550505050505060405180910390f35b348015610dae57600080fd5b506103a7612d91565b348015610dc357600080fd5b5061035c6024600480358281019290820135918135918201910135612d96565b348015610def57600080fd5b50610e07600480359060248035908101910135612e1a565b604051808060200180602001838103835285818151815260200191508051906020019080838360005b83811015610e48578181015183820152602001610e30565b50505050905090810190601f168015610e755780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015610ea8578181015183820152602001610e90565b50505050905090810190601f168015610ed55780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b348015610ef157600080fd5b506103a7612ee8565b348015610f0657600080fd5b50610412612f13565b348015610f1b57600080fd5b50610412612f3e565b348015610f3057600080fd5b506103a7612f69565b348015610f4557600080fd5b506103a7600435612f8d565b348015610f5d57600080fd5b5061032a612fbc565b348015610f7257600080fd5b506103a7612fcf565b348015610f8757600080fd5b5061035c612fd7565b348015610f9c57600080fd5b506103a7612ffa565b348015610fb157600080fd5b5061035c600435602435604435612fff565b348015610fcf57600080fd5b506103a761303d565b348015610fe457600080fd5b5061032a600435613061565b600080610ffb611f66565b905080158015906110135750806110106130a0565b10155b91505b5090565b611022615c69565b61102b846130a4565b611042600080516020615d4a8339815191526130b6565b61105667ffffffffffffffff8311156130f4565b61105f8461314b565b90506110738160008563ffffffff61317716565b82151561107f57600091505b6110918160018463ffffffff61317716565b61109b84826131fe565b6040805183815260208101859052815186927ff92eb109ce5b449e9b121c352c6aeb4319538a90738cb95d84f08e41274e92d2928290030190a26110de84613217565b6110e661328e565b50505050565b611155868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8c018190048102820181019092528a815294508a9350899250829150840183828082843750613357945050505050565b505050505050565b60006111887fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d061344b565b90505b90565b6000611198612b33565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156111f35781810151838201526020016111db565b50505050905090810190601f1680156112205780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561123f57600080fd5b505af1158015611253573d6000803e3d6000fd5b505050506040513d602081101561126957600080fd5b505192915050565b600061127b615c69565b6112848361344f565b905061128f8161347b565b1580156112ab57506112a881600263ffffffff6134c016565b15155b1515611301576040805160e560020a62461bcd02815260206004820152601260248201527f43414e545f434c4541525f50454e414c54590000000000000000000000000000604482015290519081900360640190fd5b611314816002600063ffffffff61317716565b61131e83826134d8565b61132783613217565b61132f61328e565b60405183907f8bc12804ec8f618bd18bedd0b06cba55d3775bf200242bf6cf93860e161c3f8490600090a2600191505b50919050565b600061136f612f13565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156113a957600080fd5b505af11580156113bd573d6000803e3d6000fd5b505050506040513d60208110156113d357600080fd5b5051905090565b60606000806113e7612be8565b915081851015806113f6575083155b1561140057611469565b61140c848684036134f1565b604051908082528060200260200182016040528015611435578160200160208202803883390190505b509250600090505b825181101561146957808501838281518110151561145757fe5b6020908102909101015260010161143d565b505092915050565b606080606061147e615c69565b60008061148a896130a4565b61149389613507565b92506114c06114a984600263ffffffff6134c016565b6114b98a8a63ffffffff61353316565b11156130f4565b6114d183600363ffffffff6134c016565b91506114dc876135cd565b604080518a81526020808c02820101909152919750955087801561150a578160200160208202803883390190505b509350611531600080516020615d8a8339815191528a8a8a8a8a600063ffffffff61365816565b86811015611563578181890110848281518110151561154c57fe5b911515602092830290910190910152600101611531565b50505093509350939050565b61157a8383836136cf565b505050565b60009081526020819052604090205460ff1690565b6115cd82828080601f01602080910402602001604051908101604052809392919081815260200183838082843750613816945050505050565b6115d6836130a4565b6115ed600080516020615d0a8339815191526130b6565b61169982826040518083838082843782019150509250505060405180910390206000191660008086815260200190815260200160002060010160405180828054600181600116156101000203166002900480156116815780601f1061165f576101008083540402835291820191611681565b820191906000526020600020905b81548152906001019060200180831161166d575b5050915050604051809103902060001916141561387f565b60008381526020819052604090206116b5906001018383615c7b565b50827fcb16868f4831cc58a28d413f658752a2958bd1f50e94ed6391716b936c48093b83836040518080602001828103825284848281815260200192508082843760405192018290039550909350505050a2505050565b606080606060008060008061171f615c69565b60008060008061172d612be8565b9850611737611d31565b975087604051908082528060200260200182016040528015611763578160200160208202803883390190505b509b5087604051908082528060200260200182016040528015611790578160200160208202803883390190505b509a50876040519080825280602002602001820160405280156117bd578160200160208202803883390190505b50995060009650600095505b888410156118be576117da8461157f565b15156117e5576118b3565b6117ee84613507565b945061180185600163ffffffff6134c016565b925061181485600363ffffffff6134c016565b91508282101561182057fe5b506000838152602081905260409020548b5183830396870196916101009004600160a060020a0316908d908990811061185557fe5b600160a060020a039092166020928302909101909101528a5181908c908990811061187c57fe5b6020908102909101015261188f84611b79565b8a8881518110151561189d57fe5b9115156020928302909101909101526001909601955b8360010193506117c9565b8515156118ca5761192d565b600096505b8787101561192d57856119008e8d8a8151811015156118ea57fe5b602090810290910101519063ffffffff6138d616565b81151561190957fe5b048b8881518110151561191857fe5b602090810290910101526001909601956118cf565b5050505050505050509193909250565b611954600080516020615d0a8339815191526130b6565b61195e8282613981565b5050565b61196a611f66565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015611a2b5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b838110156119f05781810151838201526020016119d8565b50505050905090810190601f168015611a1d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50611a37838383613afd565b611a3f613d4d565b61157a613d61565b611a5e600080516020615d0a8339815191526130b6565b611a6781613e27565b50565b611a72615c69565b611a7a610ff0565b1515611ad0576040805160e560020a62461bcd02815260206004820152601860248201527f434f4e54524143545f4e4f545f494e495449414c495a45440000000000000000604482015290519081900360640190fd5b611ada6002613e9d565b611ae2613d4d565b611aea613efb565b9050611aff816002600063ffffffff61317716565b611a6781613f17565b60006111887f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e61344b565b61195e828260016136cf565b600080611b6b7f4ddbb0dcdc5f7692e494c15a7fca1f9eb65f31da0b5ce1c3381f6a1a1fd579b661344b565b905080600281111561101357fe5b6000611b83615c69565b611b8c8361344f565b9050611b978161347b565b9392505050565b6000611ba8615c69565b600080611bb4856130a4565b611bcb600080516020615d0a8339815191526130b6565b611bdc611bd78661157f565b613f21565b611be4611d31565b9350611c15611bfa85600163ffffffff613f7816565b600080516020615d2a8339815191529063ffffffff61400c16565b600085815260208181526040808320805460ff1916905580519283525187927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a2611c6685613507565b9250611c7983600063ffffffff6134c016565b9150611c8c83600363ffffffff6134c016565b905080821115611cdf57611ca88360008363ffffffff61317716565b611cb28584614010565b6040805182815290518691600080516020615d6a833981519152919081900360200190a2611cdf85613217565b611ce761328e565b5050505050565b50600190565b600080516020615d4a83398151915281565b60006111887fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b61344b565b6000611188600080516020615d2a83398151915261344b565b6000806000611d8886868080601f01602080910402602001604051908101604052809392919081815260200183838082843750613816945050505050565b611d9184614029565b611da8600080516020615d0a8339815191526130b6565b611db0612be8565b925060c88310611e0a576040805160e560020a62461bcd02815260206004820152601c60248201527f4d41585f4f50455241544f52535f434f554e545f455843454544454400000000604482015290519081900360640190fd5b611e3d7fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e86001850163ffffffff61400c16565b60008381526020819052604090209150611e55611d31565b9050611e78600080516020615d2a8339815191526001830163ffffffff61400c16565b815460ff191660019081178355611e929083018787615c7b565b50815474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a03861690810291909117835560408051858152908101919091526000606082018190526080602083018181529083018890527fc52ec0ad7872dae440d886040390c13677df7bf3cca136d8d81e5e5e7dd62ff19286928a928a928a929160a0820186868082843760405192018290039850909650505050505050a150509392505050565b60006111887f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a661344b565b60006111887febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e61344b565b6000611f9b615c69565b611fa4836130a4565b611fad83613507565b9050611b97611fc382600363ffffffff6134c016565b611fd483600263ffffffff6134c016565b9063ffffffff613f7816565b611ff7600080516020615d4a8339815191526130b6565b611a676000614103565b600080516020615d0a83398151915281565b600161201d611b3f565b600281111561202857fe5b1461207d576040805160e560020a62461bcd02815260206004820152601660248201527f444953545249425554494f4e5f4e4f545f524541445900000000000000000000604482015290519081900360640190fd5b6120876002614103565b611a67614187565b60006120a8600080516020615d4a8339815191526130b6565b6120b0612be8565b90506000811115611a6757611a67600060018303613981565b6120d2816130a4565b6120e9600080516020615d0a8339815191526130b6565b6120fb6120f58261157f565b15613f21565b612124612106611d31565b600080516020615d2a8339815191529060010163ffffffff61400c16565b60008181526020818152604091829020805460ff191660019081179091558251908152915183927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a2611a6761328e565b61218581614029565b61218e826130a4565b6121a5600080516020615d0a8339815191526130b6565b6000828152602081905260409020546121d190600160a060020a0383811661010090920416141561387f565b60008281526020818152604091829020805474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a038616908102919091179091558251908152915184927f9a52205165d510fc1e428886d52108725dc01ed544da1702dc7bd3fdb3f243b292908290030190a25050565b6000606060008060008060008061225d615c69565b6122668b6130a4565b60008b8152602081905260409020805460ff81169a506101009004600160a060020a031697509150896122a757604080516020810190915260008152612334565b60018281018054604080516020600295841615610100026000190190931694909404601f81018390048302850183019091528084529083018282801561232e5780601f106123035761010080835404028352916020019161232e565b820191906000526020600020905b81548152906001019060200180831161231157829003601f168201915b50505050505b975061233f8b613507565b905061235281600063ffffffff6134c016565b955061236581600163ffffffff6134c016565b945061237881600263ffffffff6134c016565b935061238b81600363ffffffff6134c016565b9250505092959891949750929550565b60006123a5615c69565b6123ad615c69565b6123b5615c69565b60008060008060006123c5610ff0565b151561241b576040805160e560020a62461bcd02815260206004820152601860248201527f434f4e54524143545f4e4f545f494e495449414c495a45440000000000000000604482015290519081900360640190fd5b6124256000613e9d565b6124308c8c8c613afd565b612438612be8565b9850602060405190810160405280600081525095505b888210156125915761245f82613507565b975061247288600063ffffffff6134c016565b945061248588600263ffffffff6134c016565b935061249888600363ffffffff6134c016565b60008381526020819052604090205490935060ff1615156124ba5750816124d0565b6124cd846124c88588614617565b6134f1565b90505b848114612518576124e98860008363ffffffff61317716565b6124f38289614010565b6040805182815290518391600080516020615d6a833981519152919081900360200190a25b6125218261314b565b96506125358760028363ffffffff61317716565b61253f82886131fe565b6125518660008363ffffffff61462616565b6125638660038563ffffffff61462616565b61258660016125788a8263ffffffff6134c016565b88919063ffffffff61462616565b81600101915061244e565b61259a86613f17565b6125a261328e565b505050505050505050505050565b60008060006125bd615c69565b6125c5613efb565b90506125d881600163ffffffff6134c016565b93506125eb81600363ffffffff6134c016565b925061260283611fd483600063ffffffff6134c016565b915050909192565b6000808080808080612629600080516020615d4a8339815191526130b6565b6126338a8961464a565b965061263d612be8565b95506024600435019250602480350191505b8681101561268e576008810283013560c01c94506010810282013560801c935060010161267d8686106130f4565b612689858560006146c4565b61264f565b61269661328e565b5050505050505050505050565b60008080808080806126c2600080516020615d4a8339815191526130b6565b6126cc8a8961464a565b96506126d6612be8565b95506024600435019250602480350191505b8681101561268e576008810283013560c01c94506010810282013560801c93506001016127168686106130f4565b612720858561487f565b6126e8565b600080600061273384611cee565b60408051808201909152601281527f5245434f5645525f444953414c4c4f574544000000000000000000000000000060208201529015156127b95760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b506127c2611365565b92506127cd836149c5565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156128535760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b50600160a060020a03841615156128a45760405130319250600160a060020a0384169083156108fc029084906000818181858888f1935050505015801561289e573d6000803e3d6000fd5b50612963565b50826128bf600160a060020a0382163063ffffffff6149eb16565b91506128db600160a060020a038216848463ffffffff614b0016565b60408051808201909152601d81527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c454400000060208201529015156129615760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b505b83600160a060020a031683600160a060020a03167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b6000806129bf610ff0565b15156129ce5760009150612af9565b6129d6612f13565b9050600160a060020a03811615156129f15760009150612af9565b80600160a060020a031663fdef9106863087612a0c88614b8b565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b83811015612a7b578181015183820152602001612a63565b50505050905090810190601f168015612aa85780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015612aca57600080fd5b505af1158015612ade573d6000803e3d6000fd5b505050506040513d6020811015612af457600080fd5b505191505b509392505050565b612b0a826130a4565b612b21600080516020615d4a8339815191526130b6565b612b2b8282614b95565b61195e61328e565b600080612b3e612f13565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b15801561123f57600080fd5b60006111887fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e861344b565b61157a8383612c23576000612c26565b60015b60ff168361101a565b612c38826130a4565b612c757f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d794754612c708467ffffffffffffffff8516614cb6565b614d11565b612c81611bd78361157f565b612b2b828267ffffffffffffffff166001614d1f565b600080600080600080600080612cab615c69565b612cb3615c69565b612cbc8b6130a4565b612cc58b61314b565b9150612cd08b61344f565b9050612ce382600063ffffffff6134c016565b9950612cf682600163ffffffff6134c016565b9850612d0981600063ffffffff6134c016565b9750612d1c81600163ffffffff6134c016565b9650612d2f81600263ffffffff6134c016565b9550612d3a8b614e38565b8095508196508297505050505050919395975091939597565b60608060006060612d6686866001611471565b8051929650909450915081906000908110612d7d57fe5b906020019060200201519150509250925092565b60ff81565b6000808080808080612db5600080516020615d4a8339815191526130b6565b612dbf8a8961464a565b9650612dc9612be8565b95506024600435019250602480350191505b8681101561268e576008810283013560c01c94506010810282013560801c9350600101612e098686106130f4565b612e1585856000614d1f565b612ddb565b60608060008180612e38600080516020615d4a8339815191526130b6565b871515612e5e576040805160008082526020820190815281830190925295509350612edd565b612e6788614e58565b91945092509050878314612ec5576040805160e560020a62461bcd02815260206004820152601c60248201527f494e56414c49445f414c4c4f43415445445f4b4559535f434f554e5400000000604482015290519081900360640190fd5b612ed0838383615151565b9095509350612edd61328e565b505050935093915050565b60006111887fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e61344b565b60006111887f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b61344b565b60006111887ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d0353761344b565b7f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d79475481565b6000612f97615c69565b612fa0836130a4565b612fa983613507565b9050611b9781600263ffffffff6134c016565b6000600019612fc9611f66565b14905090565b6301e1338081565b612fee600080516020615d4a8339815191526130b6565b612ff86001614103565b565b60c881565b613008836130a4565b61301f600080516020615d4a8339815191526130b6565b613029838261487f565b613035838360016146c4565b61157a61328e565b7f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee81565b600061306b615c69565b6130748361344f565b905061307f8161347b565b158015611b97575061309881600263ffffffff6134c016565b159392505050565b4390565b611a676130af612be8565b82106130f4565b611a676130ef338360006040519080825280602002602001820160405280156130e9578160200160208202803883390190505b506129b4565b61532d565b801515611a67576040805160e560020a62461bcd02815260206004820152600c60248201527f4f55545f4f465f52414e47450000000000000000000000000000000000000000604482015290519081900360640190fd5b613153615c69565b50600090815260208181526040918290208251918201909252600490910154815290565b67ffffffffffffffff8111156131d7576040805160e560020a62461bcd02815260206004820152600f60248201527f5041434b45445f4f564552464c4f570000000000000000000000000000000000604482015290519081900360640190fd5b825167ffffffffffffffff91821660409390930260ff1692831b9190921b19909116179052565b6000918252602082905260409091209051600490910155565b600080613222615c69565b600061322d85615384565b935093508383141561323e57611ce7565b613246613efb565b91506132528385615478565b9050838311156132735761326e8260008363ffffffff61462616565b613285565b6132858260008363ffffffff61548f16565b611ce782613f17565b60006132b97fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e61344b565b60010190506132ee7fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e8263ffffffff61400c16565b6040805182815290517ffb992daec9d46d64898e3a9336d02811349df6cbea8b95d4deb2fa6c7b454f0d9181900360200190a16040805182815290517f7220970e1f1f12864ecccd8942690a837c7a8dd45d158cb891eb45a8a69134aa9181900360200190a150565b61335f615c69565b600061336a866130a4565b61337433876154a2565b613393851580159061338e575067ffffffffffffffff8611155b6130f4565b61339c86613507565b91506133af82600263ffffffff6134c016565b90506133cd67ffffffffffffffff6114b9838863ffffffff61353316565b6133ef600080516020615d8a833981519152878388888863ffffffff61550f16565b60408051828152905191925087917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f09181900360200190a26134398260028363ffffffff61317716565b6134438683614010565b61115561328e565b5490565b613457615c69565b50600090815260208181526040918290208251918201909252600390910154815290565b600061348d828263ffffffff6134c016565b61349e83600163ffffffff6134c016565b10806134ba57506134b682600263ffffffff6134c016565b4211155b92915050565b905167ffffffffffffffff604090920260ff161c1690565b6000918252602082905260409091209051600390910155565b60008183106135005781611b97565b5090919050565b61350f615c69565b50600090815260208181526040918290208251918201909252600290910154815290565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f57000000000000000000000000000000602082015260009083830190848210156135c15760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b508091505b5092915050565b6060806135e183603063ffffffff6138d616565b6040519080825280601f01601f19166020018201604052801561360e578160200160208202803883390190505b5061362084606063ffffffff6138d616565b6040519080825280601f01601f19166020018201604052801561364d578160200160208202803883390190505b509092509050915091565b6000805b858110156136c457613677898989840163ffffffff6157c216565b60018082015460801c85840160308181028a01908101929092528354602092830152600284015460609182028901928301526003840154604083015260048401549101529092500161365c565b505050505050505050565b6136d7615c69565b6000806136e3866130a4565b6136ed33876154a2565b8315156136f957611155565b61370286613507565b925061371583600263ffffffff6134c016565b915061374661372b84600363ffffffff6134c016565b861015801561338e5750826114b9878763ffffffff61353316565b613767600080516020615d8a8339815191528787878663ffffffff61585516565b915061377b8360028463ffffffff61317716565b60408051838152905187917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a26137c283600063ffffffff6134c016565b905080851015613803576137de8360008763ffffffff61317716565b6040805186815290518791600080516020615d6a833981519152919081900360200190a25b61380d8684614010565b61344386613217565b60008151118015613829575060ff815111155b1515611a67576040805160e560020a62461bcd02815260206004820152601160248201527f57524f4e475f4e414d455f4c454e475448000000000000000000000000000000604482015290519081900360640190fd5b801515611a67576040805160e560020a62461bcd02815260206004820152601160248201527f56414c55455f49535f5448455f53414d45000000000000000000000000000000604482015290519081900360640190fd5b6000808315156138e957600091506135c6565b508282028284828115156138f957fe5b60408051808201909152601181527f4d4154485f4d554c5f4f564552464c4f57000000000000000000000000000000602082015292919004146135c15760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b60008060008061398f615c69565b60006139ae87891115801561338e57506139a7612be8565b88106130f4565b50865b868111613ae2576139c181613507565b91506139d482600263ffffffff6134c016565b93506139e782600363ffffffff6134c016565b9250828414156139f657613ada565b8284116139ff57fe5b828403955093850193613a1a8260028563ffffffff61317716565b613a2c8260008563ffffffff61317716565b613a368183614010565b613a3f81613217565b60408051848152905182917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a26040805184815290518291600080516020615d6a833981519152919081900360200190a26040805167ffffffffffffffff88168152905182917f9824694569ba758f8872bb150515caaf8f1e2cc27e6805679c4ac8c3b9b83d87919081900360200190a25b6001016139b1565b6000851115613af357613af361328e565b5050505050505050565b613b0683615a5e565b613b367ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d035378463ffffffff61400c16565b613b667fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d08363ffffffff61400c16565b613b706002615abe565b613b7981613e27565b613b81612f3e565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613bbb57600080fd5b505af1158015613bcf573d6000803e3d6000fd5b505050506040513d6020811015613be557600080fd5b5051600160a060020a031663095ea7b3613bfd612f3e565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613c3757600080fd5b505af1158015613c4b573d6000803e3d6000fd5b505050506040513d6020811015613c6157600080fd5b50516040805163ffffffff841660e01b8152600160a060020a03909216600483015260001960248301525160448083019260209291908290030181600087803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b505050506040513d6020811015613cd757600080fd5b505060408051600160a060020a038516815290517fa44aa4b7320163340e971b1f22f153bbb8a0151d783bd58377018ea5bc96d0c99181900360200190a16040805183815290517fdb042010b15d1321c99552200b350bba0a95dfa3d0b43869983ce74b44d644ee9181900360200190a1505050565b613d576003615abe565b612ff86002614103565b613d69611f66565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015613dee5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b50612ff8613dfa6130a0565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61400c16565b613e376301e133808211156130f4565b613e677f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e8263ffffffff61400c16565b6040805182815290517f4cccd9748bff0341d9852cc61d82652a3003dcebea088f05388c0be1f26b4c8a9181900360200190a150565b613ea5611f3b565b8114611a67576040805160e560020a62461bcd02815260206004820152601b60248201527f554e45585045435445445f434f4e54524143545f56455253494f4e0000000000604482015290519081900360640190fd5b613f03615c69565b506040805160208101909152600154815290565b51600155565b5490565b801515611a67576040805160e560020a62461bcd02815260206004820152601b60248201527f57524f4e475f4f50455241544f525f4143544956455f53544154450000000000604482015290519081900360640190fd5b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f57000000000000000000000000000060208201526000908190848411156140045760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b505050900390565b9055565b6000918252602082905260409091209051600290910155565b61403281615a5e565b61403a612f3e565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561407457600080fd5b505af1158015614088573d6000803e3d6000fd5b505050506040513d602081101561409e57600080fd5b5051600160a060020a0382811691161415611a67576040805160e560020a62461bcd02815260206004820152601360248201527f4c49444f5f5245574152445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b61413f81600281111561411257fe5b7f4ddbb0dcdc5f7692e494c15a7fca1f9eb65f31da0b5ce1c3381f6a1a1fd579b69063ffffffff61400c16565b7f7545d380f29a8ae65fafb1acdf2c7762ec02d5607fecbea9dd8d8245e1616d93816040518082600281111561417157fe5b60ff16815260200191505060405180910390a150565b6000806000606080606060008061419c612f3e565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156141d657600080fd5b505af11580156141ea573d6000803e3d6000fd5b505050506040513d602081101561420057600080fd5b5051604080517ff5eb42dc0000000000000000000000000000000000000000000000000000000081523060048201529051919850600160a060020a0389169163f5eb42dc916024808201926020929091908290030181600087803b15801561426757600080fd5b505af115801561427b573d6000803e3d6000fd5b505050506040513d602081101561429157600080fd5b505195508515156142a15761460d565b6142aa8661170c565b9450945094505b845181101561451457600284828151811015156142ca57fe5b9060200190602002015110156142df5761450c565b82818151811015156142ed57fe5b90602001906020020151156143b7576001848281518110151561430c57fe5b602090810290910101805190911c905283516143459085908390811061432e57fe5b60209081029091010151839063ffffffff61353316565b9150848181518110151561435557fe5b90602001906020020151600160a060020a03167fe915a473fc2ef8e0231da98380f853b2aeea117a4392c67e753c54186bfbbd12858381518110151561439757fe5b906020019060200201516040518082815260200191505060405180910390a25b86600160a060020a0316638fcb4e5b86838151811015156143d457fe5b9060200190602002015186848151811015156143ec57fe5b906020019060200201516040518363ffffffff1660e01b81526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b15801561444557600080fd5b505af1158015614459573d6000803e3d6000fd5b505050506040513d602081101561446f57600080fd5b5050835161449a9085908390811061448357fe5b60209081029091010151899063ffffffff61353316565b975084818151811015156144aa57fe5b90602001906020020151600160a060020a03167fdf29796aad820e4bb192f3a8d631b76519bcd2cbe77cc85af20e9df53cece08685838151811015156144ec57fe5b906020019060200201516040518082815260200191505060405180910390a25b6001016142b1565b600082111561460d57614525612f3e565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561455f57600080fd5b505af1158015614573573d6000803e3d6000fd5b505050506040513d602081101561458957600080fd5b5051604080517f46114928000000000000000000000000000000000000000000000000000000008152306004820152602481018590529051600160a060020a039092169163461149289160448082019260009290919082900301818387803b1580156145f457600080fd5b505af1158015614608573d6000803e3d6000fd5b505050505b5050505050505090565b60008183116135005781611b97565b61157a83836146458461463988886134c0565b9063ffffffff61353316565b613177565b600882046010820481148015614661575060088306155b801561466e575060108206155b15156134ba576040805160e560020a62461bcd02815260206004820152601360248201527f494e56414c49445f5245504f52545f4441544100000000000000000000000000604482015290519081900360640190fd5b6146cc615c69565b60008060006146d9615c69565b60006146e489613507565b95506146f786600163ffffffff6134c016565b945084881415614706576136c4565b868061471157508488115b151561478d576040805160e560020a62461bcd02815260206004820152602160248201527f4558495445445f56414c494441544f52535f434f554e545f444543524541534560448201527f4400000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b61479e86600363ffffffff6134c016565b93506147ba60006147ae8b61344f565b9063ffffffff6134c016565b9250828410156147c657fe5b6147d48385038911156130f4565b6147e68660018a63ffffffff61317716565b6147f08987614010565b6040805189815290518a917f0f67960648751434ae86bf350db61194f387fda387e7f568b0ccd0ae0c220166919081900360200190a261482e613efb565b915061483a8886615478565b90508488111561485b576148568260018363ffffffff61462616565b61486d565b61486d8260018363ffffffff61548f16565b61487682613f17565b6136c489613217565b614887615c69565b6000614891615c69565b600080600061489f8861344f565b95506148b286600063ffffffff6134c016565b9450848714156148c157613af3565b6148ca88613507565b93506148dd84600163ffffffff6134c016565b92506148f084600363ffffffff6134c016565b9150828210156148fc57fe5b61490a8383038811156130f4565b61491b86600163ffffffff6134c016565b905080871115801561492c57508085115b1561494e5761494e600261493e611b08565b889190420163ffffffff61317716565b6149608660008963ffffffff61317716565b61496a88876134d8565b877f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb888361499f8a600263ffffffff6134c016565b60408051938452602084019290925282820152519081900360600190a2613af388613217565b600080600160a060020a03831615156149e1576000915061135f565b50506000903b1190565b60408051600160a060020a0383166024808301919091528251808303909101815260449091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790526000908180614a6b8684615b24565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f52455645525445440000000060208201529193509150821515614af65760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b5095945050505050565b60408051600160a060020a038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600090614b828582615b55565b95945050505050565b8051602002815290565b614b9d615c69565b6000614ba7615c69565b6000614bb28661344f565b9350614bc584600163ffffffff6134c016565b925082851415614bd457611155565b614bdd86613507565b9150614bfb614bf383600363ffffffff6134c016565b8611156130f4565b614c0c84600063ffffffff6134c016565b9050808510158015614c1d57508083105b15614c3f57614c3f6002614c2f611b08565b869190420163ffffffff61317716565b614c518460018763ffffffff61317716565b614c5b86856134d8565b857f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb8287614c9088600263ffffffff6134c016565b60408051938452602084019290925282820152519081900360600190a261115586613217565b604080516002808252606080830184529260208301908038833901905050905082816000815181101515614ce657fe5b602090810290910101528051829082906001908110614d0157fe5b6020908102909101015292915050565b61195e6130ef3384846129b4565b614d27615c69565b600080600080614d3688613507565b9450614d4985600063ffffffff6134c016565b9350614d5c85600363ffffffff6134c016565b9250614d6f85600263ffffffff6134c016565b9150614d7f826124c88986614617565b905083811415614d8e57613af3565b8580614d9957508381105b1515614def576040805160e560020a62461bcd02815260206004820152601b60248201527f5645545445445f4b4559535f434f554e545f494e435245415345440000000000604482015290519081900360640190fd5b614e018560008363ffffffff61317716565b614e0b8886614010565b6040805182815290518991600080516020615d6a833981519152919081900360200190a2613af388613217565b600080600080614e4785615ba3565b919790965090869003945092505050565b600060608060006060600080600080600080614e72611d31565b975087604051908082528060200260200182016040528015614e9e578160200160208202803883390190505b50995087604051908082528060200260200182016040528015614ecb578160200160208202803883390190505b50985087604051908082528060200260200182016040528015614ef8578160200160208202803883390190505b509650614f03612be8565b94505b84811015614f8a57614f1781615ba3565b95509350915082841415614f2a57614f82565b808a87815181101515614f3957fe5b602090810290910101528851828403908a9088908110614f5557fe5b60209081029091010152865182850390889088908110614f7157fe5b602090810290910101526001909501945b600101614f06565b851515614fb257604080516000808252602082018181528284019093529c509a509850615142565b87861015614fc457858a528589528587525b739b322efdb04840052f97649fd0c27b678de88da2632529fbc98a898f6040518463ffffffff1660e01b8152600401808060200180602001848152602001838103835286818151815260200191508051906020019060200280838360005b8381101561503a578181015183820152602001615022565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015615079578181015183820152602001615061565b505050509050019550505050505060006040518083038186803b15801561509f57600080fd5b505af41580156150b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160409081528110156150dc57600080fd5b8151602083018051919392830192916401000000008111156150fd57600080fd5b8201602081018481111561511057600080fd5b815185602082028301116401000000008211171561512d57600080fd5b50949f509c505050508b8d1015905061514257fe5b50505050505050509193909250565b606080600080600080615162615c69565b600061516c615c69565b6151758c6135cd565b9099509750600096505b8a518210156152f0576151a88b8381518110151561519957fe5b90602001906020020151613507565b92506151bb83600363ffffffff6134c016565b955089828151811015156151cb57fe5b602090810290910101516151e684600163ffffffff6134c016565b019450858514156151f6576152e5565b8585116151ff57fe5b858503935061523f8b8381518110151561521557fe5b60209081029091010151600080516020615d8a8339815191529088878d8d8d63ffffffff61365816565b8a51968401968b908390811061525157fe5b906020019060200201517f24eb1c9e765ba41accf9437300ea91ece5ed3f897ec3cdee0e9debd7fe309b78866040518082815260200191505060405180910390a26152a48360038763ffffffff61317716565b6152c58b838151811015156152b557fe5b9060200190602002015184614010565b6152e58b838151811015156152d657fe5b90602001906020020151613217565b81600101915061517f565b868c146152f957fe5b615301613efb565b90506153158160038963ffffffff61462616565b61531e81613f17565b50505050505050935093915050565b801515611a67576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b60008061538f615c69565b615397615c69565b60006153a286613507565b92506153ad8661314b565b91506153c083600363ffffffff6134c016565b90506153d383600063ffffffff6134c016565b93506153de86613061565b15156153ec5780935061543a565b6153fd82600063ffffffff6134c016565b1561543a57615437816154328661541b86600163ffffffff6134c016565b61542c88600163ffffffff6134c016565b016134f1565b614617565b93505b61544b82600263ffffffff6134c016565b9450838514615470576154668260028663ffffffff61317716565b61547086836131fe565b505050915091565b600081831161548957828203611b97565b50900390565b61157a838361464584611fd488886134c0565b6000818152602081905260409020546101008104600160a060020a03908116908416149060ff166110e68280156154d65750815b806130ef57506130ef857f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee61550a87615c28565b6129b4565b600080600060606000808811801561553e575067ffffffffffffffff61553b8a8a63ffffffff61353316565b11155b1515615594576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b6155a588603063ffffffff6138d616565b87511480156155c457506155c088606063ffffffff6138d616565b8651145b151561561a576040805160e560020a62461bcd02815260206004820152600f60248201527f4c454e4754485f4d49534d415443480000000000000000000000000000000000604482015290519081900360640190fd5b604080516030808252606082019092529060208201610600803883390190505091505b878110156157b3576156568b8b8b63ffffffff6157c216565b603082810289016020818101519183015192860183905285018190529195501715925082156156cf576040805160e560020a62461bcd02815260206004820152600960248201527f454d5054595f4b45590000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60208201518455603082015160801b600185015560608102602087010180516002860155602081015160038601556040810151600486015560018201915060018a01995050897fc77a17d6b857abe6d6e6c37301621bc72c4dd52fa8830fb54dfa715c04911a89836040518080602001828103825283818151815260200191508051906020019080838360005b8381101561577457818101518382015260200161575c565b50505050905090810190601f1680156157a15780820380516001836020036101000a031916815260200191505b509250505060405180910390a261563d565b50969998505050505050505050565b6040805160208082018690528183018590526060808301859052835180840390910181526080909201928390528151600093918291908401908083835b6020831061581e5780518252601f1990920191602091820191016157ff565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912060001c979650505050505050565b60008060008060606000808811801561587d57508661587a8a8a63ffffffff61353316565b11155b8015615891575067ffffffffffffffff8711155b15156158e7576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b60408051603080825260608201909252906020820161060080388339019050509150508787015b88811115615a4f5761592b8b8b600019840163ffffffff6157c216565b9450600185015460801c603083015284546020830152868110156159855761595e8b8b6000198a0163ffffffff6157c216565b9350600092505b6005831015615981578284015483860155600183019250615965565b8394505b600092505b60058310156159a45760008386015560018301925061598a565b600187039650600181039050897fea4b75aaf57196f73d338cadf79ecd0a437902e2dd0d2c4c2cf3ea71b8ab27b9836040518080602001828103825283818151815260200191508051906020019080838360005b83811015615a105781810151838201526020016159f8565b50505050905090810190601f168015615a3d5780820380516001836020036101000a031916815260200191505b509250505060405180910390a261590e565b50949998505050505050505050565b600160a060020a0381161515611a67576040805160e560020a62461bcd02815260206004820152600c60248201527f5a45524f5f414444524553530000000000000000000000000000000000000000604482015290519081900360640190fd5b615aee7f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a68263ffffffff61400c16565b6040805182815290517ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9181900360200190a150565b6000806000806040516020818751602089018a5afa92506000831115615b4957805191505b50909590945092505050565b6000806040516020818551602087016000895af16000811115615b99573d8015615b865760208114615b8f57615b97565b60019350615b97565b600183511493505b505b5090949350505050565b6000806000615bb0615c69565b615bb8615c69565b615bc186613507565b9150615bcc8661314b565b9050615bdf82600163ffffffff6134c016565b9450615bf282600363ffffffff6134c016565b9350615c0581600263ffffffff6134c016565b9250838310158015615c175750848410155b1515615c1f57fe5b50509193909250565b6040805160018082528183019092526060916020808301908038833901905050905081816000815181101515615c5a57fe5b60209081029091010152919050565b60408051602081019091526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615cbc5782800160ff19823516178555615ce9565b82800160010185558215615ce9579182015b82811115615ce9578235825591602001919060010190615cce565b506110169261118b9250905b808211156110165760008155600101615cf5560078523850fdd761612f46e844cf5a16bda6b3151d6ae961fd7e8e7b92bfbca7f86f5220989faafdc182d508d697678366f4e831f5f56166ad69bfc253fc548fb1bb75b874360e0bfd87f964eadd8276d8efb7c942134fc329b513032d0803e0c6947f955eec7e1f626bee3afd2aa47b5de04ddcdd3fe78dc8838213015ef58dfdeb2b7ad4d8ce5610cfb46470f03b14c197c2b751077c70209c5d0139f7c79ee9a165627a7a7230582053cc36190b35f63a34c4463788f6e8aa4cce60e96d4b1f16f5c39d72502352260029ebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e
Deployed Bytecode
0x6080604052600436106103105760003560e01c63ffffffff1680630803fac01461031557806308a679ad1461033e578063096b7b351461035e57806315dae03e146103925780632914b9bd146103b957806330a90f011461042e57806332f0a3b5146104465780634febc81b1461045b57806359e25c12146104c65780635ddde810146106035780635e2fb908146106215780635e57d7421461063957806362dcfda11461065d57806365cc369a1461073a578063684560a2146107555780636ccc75621461077c5780636d395b7e146107945780636da7d0a7146107a95780636ef355f1146107be5780636f817294146107d95780637038b1411461060357806375049ad81461081257806375a080d51461082a5780637e7db6e11461084257806380231f1514610863578063805911ae1461035e57806380afdea8146108785780638469cbd31461088d57806385fa63d7146108a25780638aa10435146108d05780638b3dd749146108e55780638ca7c052146108fa5780638d7e4017146109125780638ece99951461092a5780638f73c5ae1461093f57806390c09bdb1461095457806391dcd6b214610969578063973e9328146109815780639a56983c146109a55780639a7c2ade14610a815780639abddf0914610aa85780639b00c14614610adb5780639b3d190014610b075780639d4941d814610b33578063a1658fad14610b54578063a2e080f114610bbb578063a479e50814610bd6578063a70c70e414610beb578063a9e7a84614610c00578063ae962acf14610c20578063b3076c3c14610c45578063b449402a14610c9e578063b497183314610da2578063b643189b14610db7578063bee41b5814610de3578063d07442f114610ee5578063d087d28814610ee5578063d4aae0c414610efa578063d8343dcb14610f0f578063d8e71cd114610f24578063db9887ea14610f39578063de4796ed14610f51578063e204d09b14610f66578063e864299e14610f7b578063ec5af3a414610f90578063ed5cfa41146107be578063f2e2ca6314610fa5578063f31bd9c114610fc3578063fbc77ef114610fd8575b600080fd5b34801561032157600080fd5b5061032a610ff0565b604080519115158252519081900360200190f35b34801561034a57600080fd5b5061035c60043560243560443561101a565b005b34801561036a57600080fd5b5061035c600480359060248035916044358083019290820135916064359182019101356110ec565b34801561039e57600080fd5b506103a761115d565b60408051918252519081900360200190f35b3480156103c557600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261041294369492936024939284019190819084018382808284375094975061118e9650505050505050565b60408051600160a060020a039092168252519081900360200190f35b34801561043a57600080fd5b5061032a600435611271565b34801561045257600080fd5b50610412611365565b34801561046757600080fd5b506104766004356024356113da565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104b257818101518382015260200161049a565b505050509050019250505060405180910390f35b3480156104d257600080fd5b506104e4600435602435604435611471565b60405180806020018060200180602001848103845287818151815260200191508051906020019080838360005b83811015610529578181015183820152602001610511565b50505050905090810190601f1680156105565780820380516001836020036101000a031916815260200191505b50848103835286518152865160209182019188019080838360005b83811015610589578181015183820152602001610571565b50505050905090810190601f1680156105b65780820380516001836020036101000a031916815260200191505b508481038252855181528551602091820191808801910280838360005b838110156105eb5781810151838201526020016105d3565b50505050905001965050505050505060405180910390f35b34801561060f57600080fd5b5061035c60043560243560443561156f565b34801561062d57600080fd5b5061032a60043561157f565b34801561064557600080fd5b5061035c600480359060248035908101910135611594565b34801561066957600080fd5b5061067560043561170c565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156106bd5781810151838201526020016106a5565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156106fc5781810151838201526020016106e4565b5050505090500184810382528581815181526020019150805190602001906020028083836000838110156105eb5781810151838201526020016105d3565b34801561074657600080fd5b5061035c60043560243561193d565b34801561076157600080fd5b5061035c600160a060020a0360043516602435604435611962565b34801561078857600080fd5b5061035c600435611a47565b3480156107a057600080fd5b5061035c611a6a565b3480156107b557600080fd5b506103a7611b08565b3480156107ca57600080fd5b5061035c600435602435611b33565b3480156107e557600080fd5b506107ee611b3f565b604051808260028111156107fe57fe5b60ff16815260200191505060405180910390f35b34801561081e57600080fd5b5061032a600435611b79565b34801561083657600080fd5b5061035c600435611b9e565b34801561084e57600080fd5b5061032a600160a060020a0360043516611cee565b34801561086f57600080fd5b506103a7611cf4565b34801561088457600080fd5b506103a7611d06565b34801561089957600080fd5b506103a7611d31565b3480156108ae57600080fd5b506103a76024600480358281019291013590600160a060020a03903516611d4a565b3480156108dc57600080fd5b506103a7611f3b565b3480156108f157600080fd5b506103a7611f66565b34801561090657600080fd5b506103a7600435611f91565b34801561091e57600080fd5b5061035c600435611fe0565b34801561093657600080fd5b506103a7612001565b34801561094b57600080fd5b5061035c612013565b34801561096057600080fd5b5061035c61208f565b34801561097557600080fd5b5061035c6004356120c9565b34801561098d57600080fd5b5061035c600435600160a060020a036024351661217c565b3480156109b157600080fd5b506109c26004356024351515612248565b604080518815158152600160a060020a0387169181019190915267ffffffffffffffff8086166060830152848116608083015283811660a0830152821660c082015260e0602080830182815289519284019290925288516101008401918a019080838360005b83811015610a40578181015183820152602001610a28565b50505050905090810190601f168015610a6d5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b348015610a8d57600080fd5b5061035c600160a060020a036004351660243560443561239b565b348015610ab457600080fd5b50610abd6125b0565b60408051938452602084019290925282820152519081900360600190f35b348015610ae757600080fd5b5061035c602460048035828101929082013591813591820191013561260a565b348015610b1357600080fd5b5061035c60246004803582810192908201359181359182019101356126a3565b348015610b3f57600080fd5b5061035c600160a060020a0360043516612725565b348015610b6057600080fd5b50604080516020600460443581810135838102808601850190965280855261032a958335600160a060020a03169560248035963696956064959394920192918291850190849080828437509497506129b49650505050505050565b348015610bc757600080fd5b5061035c600435602435612b01565b348015610be257600080fd5b50610412612b33565b348015610bf757600080fd5b506103a7612be8565b348015610c0c57600080fd5b5061035c6004356024351515604435612c13565b348015610c2c57600080fd5b5061035c60043567ffffffffffffffff60243516612c2f565b348015610c5157600080fd5b50610c5d600435612c97565b604080519889526020890197909752878701959095526060870193909352608086019190915260a085015260c084015260e083015251908190036101000190f35b348015610caa57600080fd5b50610cb9600435602435612d53565b60405180806020018060200184151515158152602001838103835286818151815260200191508051906020019080838360005b83811015610d04578181015183820152602001610cec565b50505050905090810190601f168015610d315780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b83811015610d64578181015183820152602001610d4c565b50505050905090810190601f168015610d915780820380516001836020036101000a031916815260200191505b509550505050505060405180910390f35b348015610dae57600080fd5b506103a7612d91565b348015610dc357600080fd5b5061035c6024600480358281019290820135918135918201910135612d96565b348015610def57600080fd5b50610e07600480359060248035908101910135612e1a565b604051808060200180602001838103835285818151815260200191508051906020019080838360005b83811015610e48578181015183820152602001610e30565b50505050905090810190601f168015610e755780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015610ea8578181015183820152602001610e90565b50505050905090810190601f168015610ed55780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b348015610ef157600080fd5b506103a7612ee8565b348015610f0657600080fd5b50610412612f13565b348015610f1b57600080fd5b50610412612f3e565b348015610f3057600080fd5b506103a7612f69565b348015610f4557600080fd5b506103a7600435612f8d565b348015610f5d57600080fd5b5061032a612fbc565b348015610f7257600080fd5b506103a7612fcf565b348015610f8757600080fd5b5061035c612fd7565b348015610f9c57600080fd5b506103a7612ffa565b348015610fb157600080fd5b5061035c600435602435604435612fff565b348015610fcf57600080fd5b506103a761303d565b348015610fe457600080fd5b5061032a600435613061565b600080610ffb611f66565b905080158015906110135750806110106130a0565b10155b91505b5090565b611022615c69565b61102b846130a4565b611042600080516020615d4a8339815191526130b6565b61105667ffffffffffffffff8311156130f4565b61105f8461314b565b90506110738160008563ffffffff61317716565b82151561107f57600091505b6110918160018463ffffffff61317716565b61109b84826131fe565b6040805183815260208101859052815186927ff92eb109ce5b449e9b121c352c6aeb4319538a90738cb95d84f08e41274e92d2928290030190a26110de84613217565b6110e661328e565b50505050565b611155868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8c018190048102820181019092528a815294508a9350899250829150840183828082843750613357945050505050565b505050505050565b60006111887fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d061344b565b90505b90565b6000611198612b33565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156111f35781810151838201526020016111db565b50505050905090810190601f1680156112205780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561123f57600080fd5b505af1158015611253573d6000803e3d6000fd5b505050506040513d602081101561126957600080fd5b505192915050565b600061127b615c69565b6112848361344f565b905061128f8161347b565b1580156112ab57506112a881600263ffffffff6134c016565b15155b1515611301576040805160e560020a62461bcd02815260206004820152601260248201527f43414e545f434c4541525f50454e414c54590000000000000000000000000000604482015290519081900360640190fd5b611314816002600063ffffffff61317716565b61131e83826134d8565b61132783613217565b61132f61328e565b60405183907f8bc12804ec8f618bd18bedd0b06cba55d3775bf200242bf6cf93860e161c3f8490600090a2600191505b50919050565b600061136f612f13565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156113a957600080fd5b505af11580156113bd573d6000803e3d6000fd5b505050506040513d60208110156113d357600080fd5b5051905090565b60606000806113e7612be8565b915081851015806113f6575083155b1561140057611469565b61140c848684036134f1565b604051908082528060200260200182016040528015611435578160200160208202803883390190505b509250600090505b825181101561146957808501838281518110151561145757fe5b6020908102909101015260010161143d565b505092915050565b606080606061147e615c69565b60008061148a896130a4565b61149389613507565b92506114c06114a984600263ffffffff6134c016565b6114b98a8a63ffffffff61353316565b11156130f4565b6114d183600363ffffffff6134c016565b91506114dc876135cd565b604080518a81526020808c02820101909152919750955087801561150a578160200160208202803883390190505b509350611531600080516020615d8a8339815191528a8a8a8a8a600063ffffffff61365816565b86811015611563578181890110848281518110151561154c57fe5b911515602092830290910190910152600101611531565b50505093509350939050565b61157a8383836136cf565b505050565b60009081526020819052604090205460ff1690565b6115cd82828080601f01602080910402602001604051908101604052809392919081815260200183838082843750613816945050505050565b6115d6836130a4565b6115ed600080516020615d0a8339815191526130b6565b61169982826040518083838082843782019150509250505060405180910390206000191660008086815260200190815260200160002060010160405180828054600181600116156101000203166002900480156116815780601f1061165f576101008083540402835291820191611681565b820191906000526020600020905b81548152906001019060200180831161166d575b5050915050604051809103902060001916141561387f565b60008381526020819052604090206116b5906001018383615c7b565b50827fcb16868f4831cc58a28d413f658752a2958bd1f50e94ed6391716b936c48093b83836040518080602001828103825284848281815260200192508082843760405192018290039550909350505050a2505050565b606080606060008060008061171f615c69565b60008060008061172d612be8565b9850611737611d31565b975087604051908082528060200260200182016040528015611763578160200160208202803883390190505b509b5087604051908082528060200260200182016040528015611790578160200160208202803883390190505b509a50876040519080825280602002602001820160405280156117bd578160200160208202803883390190505b50995060009650600095505b888410156118be576117da8461157f565b15156117e5576118b3565b6117ee84613507565b945061180185600163ffffffff6134c016565b925061181485600363ffffffff6134c016565b91508282101561182057fe5b506000838152602081905260409020548b5183830396870196916101009004600160a060020a0316908d908990811061185557fe5b600160a060020a039092166020928302909101909101528a5181908c908990811061187c57fe5b6020908102909101015261188f84611b79565b8a8881518110151561189d57fe5b9115156020928302909101909101526001909601955b8360010193506117c9565b8515156118ca5761192d565b600096505b8787101561192d57856119008e8d8a8151811015156118ea57fe5b602090810290910101519063ffffffff6138d616565b81151561190957fe5b048b8881518110151561191857fe5b602090810290910101526001909601956118cf565b5050505050505050509193909250565b611954600080516020615d0a8339815191526130b6565b61195e8282613981565b5050565b61196a611f66565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015611a2b5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b838110156119f05781810151838201526020016119d8565b50505050905090810190601f168015611a1d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50611a37838383613afd565b611a3f613d4d565b61157a613d61565b611a5e600080516020615d0a8339815191526130b6565b611a6781613e27565b50565b611a72615c69565b611a7a610ff0565b1515611ad0576040805160e560020a62461bcd02815260206004820152601860248201527f434f4e54524143545f4e4f545f494e495449414c495a45440000000000000000604482015290519081900360640190fd5b611ada6002613e9d565b611ae2613d4d565b611aea613efb565b9050611aff816002600063ffffffff61317716565b611a6781613f17565b60006111887f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e61344b565b61195e828260016136cf565b600080611b6b7f4ddbb0dcdc5f7692e494c15a7fca1f9eb65f31da0b5ce1c3381f6a1a1fd579b661344b565b905080600281111561101357fe5b6000611b83615c69565b611b8c8361344f565b9050611b978161347b565b9392505050565b6000611ba8615c69565b600080611bb4856130a4565b611bcb600080516020615d0a8339815191526130b6565b611bdc611bd78661157f565b613f21565b611be4611d31565b9350611c15611bfa85600163ffffffff613f7816565b600080516020615d2a8339815191529063ffffffff61400c16565b600085815260208181526040808320805460ff1916905580519283525187927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a2611c6685613507565b9250611c7983600063ffffffff6134c016565b9150611c8c83600363ffffffff6134c016565b905080821115611cdf57611ca88360008363ffffffff61317716565b611cb28584614010565b6040805182815290518691600080516020615d6a833981519152919081900360200190a2611cdf85613217565b611ce761328e565b5050505050565b50600190565b600080516020615d4a83398151915281565b60006111887fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b61344b565b6000611188600080516020615d2a83398151915261344b565b6000806000611d8886868080601f01602080910402602001604051908101604052809392919081815260200183838082843750613816945050505050565b611d9184614029565b611da8600080516020615d0a8339815191526130b6565b611db0612be8565b925060c88310611e0a576040805160e560020a62461bcd02815260206004820152601c60248201527f4d41585f4f50455241544f52535f434f554e545f455843454544454400000000604482015290519081900360640190fd5b611e3d7fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e86001850163ffffffff61400c16565b60008381526020819052604090209150611e55611d31565b9050611e78600080516020615d2a8339815191526001830163ffffffff61400c16565b815460ff191660019081178355611e929083018787615c7b565b50815474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a03861690810291909117835560408051858152908101919091526000606082018190526080602083018181529083018890527fc52ec0ad7872dae440d886040390c13677df7bf3cca136d8d81e5e5e7dd62ff19286928a928a928a929160a0820186868082843760405192018290039850909650505050505050a150509392505050565b60006111887f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a661344b565b60006111887febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e61344b565b6000611f9b615c69565b611fa4836130a4565b611fad83613507565b9050611b97611fc382600363ffffffff6134c016565b611fd483600263ffffffff6134c016565b9063ffffffff613f7816565b611ff7600080516020615d4a8339815191526130b6565b611a676000614103565b600080516020615d0a83398151915281565b600161201d611b3f565b600281111561202857fe5b1461207d576040805160e560020a62461bcd02815260206004820152601660248201527f444953545249425554494f4e5f4e4f545f524541445900000000000000000000604482015290519081900360640190fd5b6120876002614103565b611a67614187565b60006120a8600080516020615d4a8339815191526130b6565b6120b0612be8565b90506000811115611a6757611a67600060018303613981565b6120d2816130a4565b6120e9600080516020615d0a8339815191526130b6565b6120fb6120f58261157f565b15613f21565b612124612106611d31565b600080516020615d2a8339815191529060010163ffffffff61400c16565b60008181526020818152604091829020805460ff191660019081179091558251908152915183927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a2611a6761328e565b61218581614029565b61218e826130a4565b6121a5600080516020615d0a8339815191526130b6565b6000828152602081905260409020546121d190600160a060020a0383811661010090920416141561387f565b60008281526020818152604091829020805474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a038616908102919091179091558251908152915184927f9a52205165d510fc1e428886d52108725dc01ed544da1702dc7bd3fdb3f243b292908290030190a25050565b6000606060008060008060008061225d615c69565b6122668b6130a4565b60008b8152602081905260409020805460ff81169a506101009004600160a060020a031697509150896122a757604080516020810190915260008152612334565b60018281018054604080516020600295841615610100026000190190931694909404601f81018390048302850183019091528084529083018282801561232e5780601f106123035761010080835404028352916020019161232e565b820191906000526020600020905b81548152906001019060200180831161231157829003601f168201915b50505050505b975061233f8b613507565b905061235281600063ffffffff6134c016565b955061236581600163ffffffff6134c016565b945061237881600263ffffffff6134c016565b935061238b81600363ffffffff6134c016565b9250505092959891949750929550565b60006123a5615c69565b6123ad615c69565b6123b5615c69565b60008060008060006123c5610ff0565b151561241b576040805160e560020a62461bcd02815260206004820152601860248201527f434f4e54524143545f4e4f545f494e495449414c495a45440000000000000000604482015290519081900360640190fd5b6124256000613e9d565b6124308c8c8c613afd565b612438612be8565b9850602060405190810160405280600081525095505b888210156125915761245f82613507565b975061247288600063ffffffff6134c016565b945061248588600263ffffffff6134c016565b935061249888600363ffffffff6134c016565b60008381526020819052604090205490935060ff1615156124ba5750816124d0565b6124cd846124c88588614617565b6134f1565b90505b848114612518576124e98860008363ffffffff61317716565b6124f38289614010565b6040805182815290518391600080516020615d6a833981519152919081900360200190a25b6125218261314b565b96506125358760028363ffffffff61317716565b61253f82886131fe565b6125518660008363ffffffff61462616565b6125638660038563ffffffff61462616565b61258660016125788a8263ffffffff6134c016565b88919063ffffffff61462616565b81600101915061244e565b61259a86613f17565b6125a261328e565b505050505050505050505050565b60008060006125bd615c69565b6125c5613efb565b90506125d881600163ffffffff6134c016565b93506125eb81600363ffffffff6134c016565b925061260283611fd483600063ffffffff6134c016565b915050909192565b6000808080808080612629600080516020615d4a8339815191526130b6565b6126338a8961464a565b965061263d612be8565b95506024600435019250602480350191505b8681101561268e576008810283013560c01c94506010810282013560801c935060010161267d8686106130f4565b612689858560006146c4565b61264f565b61269661328e565b5050505050505050505050565b60008080808080806126c2600080516020615d4a8339815191526130b6565b6126cc8a8961464a565b96506126d6612be8565b95506024600435019250602480350191505b8681101561268e576008810283013560c01c94506010810282013560801c93506001016127168686106130f4565b612720858561487f565b6126e8565b600080600061273384611cee565b60408051808201909152601281527f5245434f5645525f444953414c4c4f574544000000000000000000000000000060208201529015156127b95760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b506127c2611365565b92506127cd836149c5565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156128535760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b50600160a060020a03841615156128a45760405130319250600160a060020a0384169083156108fc029084906000818181858888f1935050505015801561289e573d6000803e3d6000fd5b50612963565b50826128bf600160a060020a0382163063ffffffff6149eb16565b91506128db600160a060020a038216848463ffffffff614b0016565b60408051808201909152601d81527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c454400000060208201529015156129615760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b505b83600160a060020a031683600160a060020a03167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b6000806129bf610ff0565b15156129ce5760009150612af9565b6129d6612f13565b9050600160a060020a03811615156129f15760009150612af9565b80600160a060020a031663fdef9106863087612a0c88614b8b565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b83811015612a7b578181015183820152602001612a63565b50505050905090810190601f168015612aa85780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015612aca57600080fd5b505af1158015612ade573d6000803e3d6000fd5b505050506040513d6020811015612af457600080fd5b505191505b509392505050565b612b0a826130a4565b612b21600080516020615d4a8339815191526130b6565b612b2b8282614b95565b61195e61328e565b600080612b3e612f13565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b15801561123f57600080fd5b60006111887fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e861344b565b61157a8383612c23576000612c26565b60015b60ff168361101a565b612c38826130a4565b612c757f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d794754612c708467ffffffffffffffff8516614cb6565b614d11565b612c81611bd78361157f565b612b2b828267ffffffffffffffff166001614d1f565b600080600080600080600080612cab615c69565b612cb3615c69565b612cbc8b6130a4565b612cc58b61314b565b9150612cd08b61344f565b9050612ce382600063ffffffff6134c016565b9950612cf682600163ffffffff6134c016565b9850612d0981600063ffffffff6134c016565b9750612d1c81600163ffffffff6134c016565b9650612d2f81600263ffffffff6134c016565b9550612d3a8b614e38565b8095508196508297505050505050919395975091939597565b60608060006060612d6686866001611471565b8051929650909450915081906000908110612d7d57fe5b906020019060200201519150509250925092565b60ff81565b6000808080808080612db5600080516020615d4a8339815191526130b6565b612dbf8a8961464a565b9650612dc9612be8565b95506024600435019250602480350191505b8681101561268e576008810283013560c01c94506010810282013560801c9350600101612e098686106130f4565b612e1585856000614d1f565b612ddb565b60608060008180612e38600080516020615d4a8339815191526130b6565b871515612e5e576040805160008082526020820190815281830190925295509350612edd565b612e6788614e58565b91945092509050878314612ec5576040805160e560020a62461bcd02815260206004820152601c60248201527f494e56414c49445f414c4c4f43415445445f4b4559535f434f554e5400000000604482015290519081900360640190fd5b612ed0838383615151565b9095509350612edd61328e565b505050935093915050565b60006111887fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e61344b565b60006111887f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b61344b565b60006111887ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d0353761344b565b7f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d79475481565b6000612f97615c69565b612fa0836130a4565b612fa983613507565b9050611b9781600263ffffffff6134c016565b6000600019612fc9611f66565b14905090565b6301e1338081565b612fee600080516020615d4a8339815191526130b6565b612ff86001614103565b565b60c881565b613008836130a4565b61301f600080516020615d4a8339815191526130b6565b613029838261487f565b613035838360016146c4565b61157a61328e565b7f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee81565b600061306b615c69565b6130748361344f565b905061307f8161347b565b158015611b97575061309881600263ffffffff6134c016565b159392505050565b4390565b611a676130af612be8565b82106130f4565b611a676130ef338360006040519080825280602002602001820160405280156130e9578160200160208202803883390190505b506129b4565b61532d565b801515611a67576040805160e560020a62461bcd02815260206004820152600c60248201527f4f55545f4f465f52414e47450000000000000000000000000000000000000000604482015290519081900360640190fd5b613153615c69565b50600090815260208181526040918290208251918201909252600490910154815290565b67ffffffffffffffff8111156131d7576040805160e560020a62461bcd02815260206004820152600f60248201527f5041434b45445f4f564552464c4f570000000000000000000000000000000000604482015290519081900360640190fd5b825167ffffffffffffffff91821660409390930260ff1692831b9190921b19909116179052565b6000918252602082905260409091209051600490910155565b600080613222615c69565b600061322d85615384565b935093508383141561323e57611ce7565b613246613efb565b91506132528385615478565b9050838311156132735761326e8260008363ffffffff61462616565b613285565b6132858260008363ffffffff61548f16565b611ce782613f17565b60006132b97fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e61344b565b60010190506132ee7fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e8263ffffffff61400c16565b6040805182815290517ffb992daec9d46d64898e3a9336d02811349df6cbea8b95d4deb2fa6c7b454f0d9181900360200190a16040805182815290517f7220970e1f1f12864ecccd8942690a837c7a8dd45d158cb891eb45a8a69134aa9181900360200190a150565b61335f615c69565b600061336a866130a4565b61337433876154a2565b613393851580159061338e575067ffffffffffffffff8611155b6130f4565b61339c86613507565b91506133af82600263ffffffff6134c016565b90506133cd67ffffffffffffffff6114b9838863ffffffff61353316565b6133ef600080516020615d8a833981519152878388888863ffffffff61550f16565b60408051828152905191925087917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f09181900360200190a26134398260028363ffffffff61317716565b6134438683614010565b61115561328e565b5490565b613457615c69565b50600090815260208181526040918290208251918201909252600390910154815290565b600061348d828263ffffffff6134c016565b61349e83600163ffffffff6134c016565b10806134ba57506134b682600263ffffffff6134c016565b4211155b92915050565b905167ffffffffffffffff604090920260ff161c1690565b6000918252602082905260409091209051600390910155565b60008183106135005781611b97565b5090919050565b61350f615c69565b50600090815260208181526040918290208251918201909252600290910154815290565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f57000000000000000000000000000000602082015260009083830190848210156135c15760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b508091505b5092915050565b6060806135e183603063ffffffff6138d616565b6040519080825280601f01601f19166020018201604052801561360e578160200160208202803883390190505b5061362084606063ffffffff6138d616565b6040519080825280601f01601f19166020018201604052801561364d578160200160208202803883390190505b509092509050915091565b6000805b858110156136c457613677898989840163ffffffff6157c216565b60018082015460801c85840160308181028a01908101929092528354602092830152600284015460609182028901928301526003840154604083015260048401549101529092500161365c565b505050505050505050565b6136d7615c69565b6000806136e3866130a4565b6136ed33876154a2565b8315156136f957611155565b61370286613507565b925061371583600263ffffffff6134c016565b915061374661372b84600363ffffffff6134c016565b861015801561338e5750826114b9878763ffffffff61353316565b613767600080516020615d8a8339815191528787878663ffffffff61585516565b915061377b8360028463ffffffff61317716565b60408051838152905187917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a26137c283600063ffffffff6134c016565b905080851015613803576137de8360008763ffffffff61317716565b6040805186815290518791600080516020615d6a833981519152919081900360200190a25b61380d8684614010565b61344386613217565b60008151118015613829575060ff815111155b1515611a67576040805160e560020a62461bcd02815260206004820152601160248201527f57524f4e475f4e414d455f4c454e475448000000000000000000000000000000604482015290519081900360640190fd5b801515611a67576040805160e560020a62461bcd02815260206004820152601160248201527f56414c55455f49535f5448455f53414d45000000000000000000000000000000604482015290519081900360640190fd5b6000808315156138e957600091506135c6565b508282028284828115156138f957fe5b60408051808201909152601181527f4d4154485f4d554c5f4f564552464c4f57000000000000000000000000000000602082015292919004146135c15760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b60008060008061398f615c69565b60006139ae87891115801561338e57506139a7612be8565b88106130f4565b50865b868111613ae2576139c181613507565b91506139d482600263ffffffff6134c016565b93506139e782600363ffffffff6134c016565b9250828414156139f657613ada565b8284116139ff57fe5b828403955093850193613a1a8260028563ffffffff61317716565b613a2c8260008563ffffffff61317716565b613a368183614010565b613a3f81613217565b60408051848152905182917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a26040805184815290518291600080516020615d6a833981519152919081900360200190a26040805167ffffffffffffffff88168152905182917f9824694569ba758f8872bb150515caaf8f1e2cc27e6805679c4ac8c3b9b83d87919081900360200190a25b6001016139b1565b6000851115613af357613af361328e565b5050505050505050565b613b0683615a5e565b613b367ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d035378463ffffffff61400c16565b613b667fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d08363ffffffff61400c16565b613b706002615abe565b613b7981613e27565b613b81612f3e565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613bbb57600080fd5b505af1158015613bcf573d6000803e3d6000fd5b505050506040513d6020811015613be557600080fd5b5051600160a060020a031663095ea7b3613bfd612f3e565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613c3757600080fd5b505af1158015613c4b573d6000803e3d6000fd5b505050506040513d6020811015613c6157600080fd5b50516040805163ffffffff841660e01b8152600160a060020a03909216600483015260001960248301525160448083019260209291908290030181600087803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b505050506040513d6020811015613cd757600080fd5b505060408051600160a060020a038516815290517fa44aa4b7320163340e971b1f22f153bbb8a0151d783bd58377018ea5bc96d0c99181900360200190a16040805183815290517fdb042010b15d1321c99552200b350bba0a95dfa3d0b43869983ce74b44d644ee9181900360200190a1505050565b613d576003615abe565b612ff86002614103565b613d69611f66565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015613dee5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b50612ff8613dfa6130a0565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61400c16565b613e376301e133808211156130f4565b613e677f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e8263ffffffff61400c16565b6040805182815290517f4cccd9748bff0341d9852cc61d82652a3003dcebea088f05388c0be1f26b4c8a9181900360200190a150565b613ea5611f3b565b8114611a67576040805160e560020a62461bcd02815260206004820152601b60248201527f554e45585045435445445f434f4e54524143545f56455253494f4e0000000000604482015290519081900360640190fd5b613f03615c69565b506040805160208101909152600154815290565b51600155565b5490565b801515611a67576040805160e560020a62461bcd02815260206004820152601b60248201527f57524f4e475f4f50455241544f525f4143544956455f53544154450000000000604482015290519081900360640190fd5b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f57000000000000000000000000000060208201526000908190848411156140045760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b505050900390565b9055565b6000918252602082905260409091209051600290910155565b61403281615a5e565b61403a612f3e565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561407457600080fd5b505af1158015614088573d6000803e3d6000fd5b505050506040513d602081101561409e57600080fd5b5051600160a060020a0382811691161415611a67576040805160e560020a62461bcd02815260206004820152601360248201527f4c49444f5f5245574152445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b61413f81600281111561411257fe5b7f4ddbb0dcdc5f7692e494c15a7fca1f9eb65f31da0b5ce1c3381f6a1a1fd579b69063ffffffff61400c16565b7f7545d380f29a8ae65fafb1acdf2c7762ec02d5607fecbea9dd8d8245e1616d93816040518082600281111561417157fe5b60ff16815260200191505060405180910390a150565b6000806000606080606060008061419c612f3e565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156141d657600080fd5b505af11580156141ea573d6000803e3d6000fd5b505050506040513d602081101561420057600080fd5b5051604080517ff5eb42dc0000000000000000000000000000000000000000000000000000000081523060048201529051919850600160a060020a0389169163f5eb42dc916024808201926020929091908290030181600087803b15801561426757600080fd5b505af115801561427b573d6000803e3d6000fd5b505050506040513d602081101561429157600080fd5b505195508515156142a15761460d565b6142aa8661170c565b9450945094505b845181101561451457600284828151811015156142ca57fe5b9060200190602002015110156142df5761450c565b82818151811015156142ed57fe5b90602001906020020151156143b7576001848281518110151561430c57fe5b602090810290910101805190911c905283516143459085908390811061432e57fe5b60209081029091010151839063ffffffff61353316565b9150848181518110151561435557fe5b90602001906020020151600160a060020a03167fe915a473fc2ef8e0231da98380f853b2aeea117a4392c67e753c54186bfbbd12858381518110151561439757fe5b906020019060200201516040518082815260200191505060405180910390a25b86600160a060020a0316638fcb4e5b86838151811015156143d457fe5b9060200190602002015186848151811015156143ec57fe5b906020019060200201516040518363ffffffff1660e01b81526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b15801561444557600080fd5b505af1158015614459573d6000803e3d6000fd5b505050506040513d602081101561446f57600080fd5b5050835161449a9085908390811061448357fe5b60209081029091010151899063ffffffff61353316565b975084818151811015156144aa57fe5b90602001906020020151600160a060020a03167fdf29796aad820e4bb192f3a8d631b76519bcd2cbe77cc85af20e9df53cece08685838151811015156144ec57fe5b906020019060200201516040518082815260200191505060405180910390a25b6001016142b1565b600082111561460d57614525612f3e565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561455f57600080fd5b505af1158015614573573d6000803e3d6000fd5b505050506040513d602081101561458957600080fd5b5051604080517f46114928000000000000000000000000000000000000000000000000000000008152306004820152602481018590529051600160a060020a039092169163461149289160448082019260009290919082900301818387803b1580156145f457600080fd5b505af1158015614608573d6000803e3d6000fd5b505050505b5050505050505090565b60008183116135005781611b97565b61157a83836146458461463988886134c0565b9063ffffffff61353316565b613177565b600882046010820481148015614661575060088306155b801561466e575060108206155b15156134ba576040805160e560020a62461bcd02815260206004820152601360248201527f494e56414c49445f5245504f52545f4441544100000000000000000000000000604482015290519081900360640190fd5b6146cc615c69565b60008060006146d9615c69565b60006146e489613507565b95506146f786600163ffffffff6134c016565b945084881415614706576136c4565b868061471157508488115b151561478d576040805160e560020a62461bcd02815260206004820152602160248201527f4558495445445f56414c494441544f52535f434f554e545f444543524541534560448201527f4400000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b61479e86600363ffffffff6134c016565b93506147ba60006147ae8b61344f565b9063ffffffff6134c016565b9250828410156147c657fe5b6147d48385038911156130f4565b6147e68660018a63ffffffff61317716565b6147f08987614010565b6040805189815290518a917f0f67960648751434ae86bf350db61194f387fda387e7f568b0ccd0ae0c220166919081900360200190a261482e613efb565b915061483a8886615478565b90508488111561485b576148568260018363ffffffff61462616565b61486d565b61486d8260018363ffffffff61548f16565b61487682613f17565b6136c489613217565b614887615c69565b6000614891615c69565b600080600061489f8861344f565b95506148b286600063ffffffff6134c016565b9450848714156148c157613af3565b6148ca88613507565b93506148dd84600163ffffffff6134c016565b92506148f084600363ffffffff6134c016565b9150828210156148fc57fe5b61490a8383038811156130f4565b61491b86600163ffffffff6134c016565b905080871115801561492c57508085115b1561494e5761494e600261493e611b08565b889190420163ffffffff61317716565b6149608660008963ffffffff61317716565b61496a88876134d8565b877f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb888361499f8a600263ffffffff6134c016565b60408051938452602084019290925282820152519081900360600190a2613af388613217565b600080600160a060020a03831615156149e1576000915061135f565b50506000903b1190565b60408051600160a060020a0383166024808301919091528251808303909101815260449091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790526000908180614a6b8684615b24565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f52455645525445440000000060208201529193509150821515614af65760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119f05781810151838201526020016119d8565b5095945050505050565b60408051600160a060020a038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600090614b828582615b55565b95945050505050565b8051602002815290565b614b9d615c69565b6000614ba7615c69565b6000614bb28661344f565b9350614bc584600163ffffffff6134c016565b925082851415614bd457611155565b614bdd86613507565b9150614bfb614bf383600363ffffffff6134c016565b8611156130f4565b614c0c84600063ffffffff6134c016565b9050808510158015614c1d57508083105b15614c3f57614c3f6002614c2f611b08565b869190420163ffffffff61317716565b614c518460018763ffffffff61317716565b614c5b86856134d8565b857f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb8287614c9088600263ffffffff6134c016565b60408051938452602084019290925282820152519081900360600190a261115586613217565b604080516002808252606080830184529260208301908038833901905050905082816000815181101515614ce657fe5b602090810290910101528051829082906001908110614d0157fe5b6020908102909101015292915050565b61195e6130ef3384846129b4565b614d27615c69565b600080600080614d3688613507565b9450614d4985600063ffffffff6134c016565b9350614d5c85600363ffffffff6134c016565b9250614d6f85600263ffffffff6134c016565b9150614d7f826124c88986614617565b905083811415614d8e57613af3565b8580614d9957508381105b1515614def576040805160e560020a62461bcd02815260206004820152601b60248201527f5645545445445f4b4559535f434f554e545f494e435245415345440000000000604482015290519081900360640190fd5b614e018560008363ffffffff61317716565b614e0b8886614010565b6040805182815290518991600080516020615d6a833981519152919081900360200190a2613af388613217565b600080600080614e4785615ba3565b919790965090869003945092505050565b600060608060006060600080600080600080614e72611d31565b975087604051908082528060200260200182016040528015614e9e578160200160208202803883390190505b50995087604051908082528060200260200182016040528015614ecb578160200160208202803883390190505b50985087604051908082528060200260200182016040528015614ef8578160200160208202803883390190505b509650614f03612be8565b94505b84811015614f8a57614f1781615ba3565b95509350915082841415614f2a57614f82565b808a87815181101515614f3957fe5b602090810290910101528851828403908a9088908110614f5557fe5b60209081029091010152865182850390889088908110614f7157fe5b602090810290910101526001909501945b600101614f06565b851515614fb257604080516000808252602082018181528284019093529c509a509850615142565b87861015614fc457858a528589528587525b739b322efdb04840052f97649fd0c27b678de88da2632529fbc98a898f6040518463ffffffff1660e01b8152600401808060200180602001848152602001838103835286818151815260200191508051906020019060200280838360005b8381101561503a578181015183820152602001615022565b50505050905001838103825285818151815260200191508051906020019060200280838360005b83811015615079578181015183820152602001615061565b505050509050019550505050505060006040518083038186803b15801561509f57600080fd5b505af41580156150b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160409081528110156150dc57600080fd5b8151602083018051919392830192916401000000008111156150fd57600080fd5b8201602081018481111561511057600080fd5b815185602082028301116401000000008211171561512d57600080fd5b50949f509c505050508b8d1015905061514257fe5b50505050505050509193909250565b606080600080600080615162615c69565b600061516c615c69565b6151758c6135cd565b9099509750600096505b8a518210156152f0576151a88b8381518110151561519957fe5b90602001906020020151613507565b92506151bb83600363ffffffff6134c016565b955089828151811015156151cb57fe5b602090810290910101516151e684600163ffffffff6134c016565b019450858514156151f6576152e5565b8585116151ff57fe5b858503935061523f8b8381518110151561521557fe5b60209081029091010151600080516020615d8a8339815191529088878d8d8d63ffffffff61365816565b8a51968401968b908390811061525157fe5b906020019060200201517f24eb1c9e765ba41accf9437300ea91ece5ed3f897ec3cdee0e9debd7fe309b78866040518082815260200191505060405180910390a26152a48360038763ffffffff61317716565b6152c58b838151811015156152b557fe5b9060200190602002015184614010565b6152e58b838151811015156152d657fe5b90602001906020020151613217565b81600101915061517f565b868c146152f957fe5b615301613efb565b90506153158160038963ffffffff61462616565b61531e81613f17565b50505050505050935093915050565b801515611a67576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b60008061538f615c69565b615397615c69565b60006153a286613507565b92506153ad8661314b565b91506153c083600363ffffffff6134c016565b90506153d383600063ffffffff6134c016565b93506153de86613061565b15156153ec5780935061543a565b6153fd82600063ffffffff6134c016565b1561543a57615437816154328661541b86600163ffffffff6134c016565b61542c88600163ffffffff6134c016565b016134f1565b614617565b93505b61544b82600263ffffffff6134c016565b9450838514615470576154668260028663ffffffff61317716565b61547086836131fe565b505050915091565b600081831161548957828203611b97565b50900390565b61157a838361464584611fd488886134c0565b6000818152602081905260409020546101008104600160a060020a03908116908416149060ff166110e68280156154d65750815b806130ef57506130ef857f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee61550a87615c28565b6129b4565b600080600060606000808811801561553e575067ffffffffffffffff61553b8a8a63ffffffff61353316565b11155b1515615594576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b6155a588603063ffffffff6138d616565b87511480156155c457506155c088606063ffffffff6138d616565b8651145b151561561a576040805160e560020a62461bcd02815260206004820152600f60248201527f4c454e4754485f4d49534d415443480000000000000000000000000000000000604482015290519081900360640190fd5b604080516030808252606082019092529060208201610600803883390190505091505b878110156157b3576156568b8b8b63ffffffff6157c216565b603082810289016020818101519183015192860183905285018190529195501715925082156156cf576040805160e560020a62461bcd02815260206004820152600960248201527f454d5054595f4b45590000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60208201518455603082015160801b600185015560608102602087010180516002860155602081015160038601556040810151600486015560018201915060018a01995050897fc77a17d6b857abe6d6e6c37301621bc72c4dd52fa8830fb54dfa715c04911a89836040518080602001828103825283818151815260200191508051906020019080838360005b8381101561577457818101518382015260200161575c565b50505050905090810190601f1680156157a15780820380516001836020036101000a031916815260200191505b509250505060405180910390a261563d565b50969998505050505050505050565b6040805160208082018690528183018590526060808301859052835180840390910181526080909201928390528151600093918291908401908083835b6020831061581e5780518252601f1990920191602091820191016157ff565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912060001c979650505050505050565b60008060008060606000808811801561587d57508661587a8a8a63ffffffff61353316565b11155b8015615891575067ffffffffffffffff8711155b15156158e7576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b60408051603080825260608201909252906020820161060080388339019050509150508787015b88811115615a4f5761592b8b8b600019840163ffffffff6157c216565b9450600185015460801c603083015284546020830152868110156159855761595e8b8b6000198a0163ffffffff6157c216565b9350600092505b6005831015615981578284015483860155600183019250615965565b8394505b600092505b60058310156159a45760008386015560018301925061598a565b600187039650600181039050897fea4b75aaf57196f73d338cadf79ecd0a437902e2dd0d2c4c2cf3ea71b8ab27b9836040518080602001828103825283818151815260200191508051906020019080838360005b83811015615a105781810151838201526020016159f8565b50505050905090810190601f168015615a3d5780820380516001836020036101000a031916815260200191505b509250505060405180910390a261590e565b50949998505050505050505050565b600160a060020a0381161515611a67576040805160e560020a62461bcd02815260206004820152600c60248201527f5a45524f5f414444524553530000000000000000000000000000000000000000604482015290519081900360640190fd5b615aee7f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a68263ffffffff61400c16565b6040805182815290517ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9181900360200190a150565b6000806000806040516020818751602089018a5afa92506000831115615b4957805191505b50909590945092505050565b6000806040516020818551602087016000895af16000811115615b99573d8015615b865760208114615b8f57615b97565b60019350615b97565b600183511493505b505b5090949350505050565b6000806000615bb0615c69565b615bb8615c69565b615bc186613507565b9150615bcc8661314b565b9050615bdf82600163ffffffff6134c016565b9450615bf282600363ffffffff6134c016565b9350615c0581600263ffffffff6134c016565b9250838310158015615c175750848410155b1515615c1f57fe5b50509193909250565b6040805160018082528183019092526060916020808301908038833901905050905081816000815181101515615c5a57fe5b60209081029091010152919050565b60408051602081019091526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615cbc5782800160ff19823516178555615ce9565b82800160010185558215615ce9579182015b82811115615ce9578235825591602001919060010190615cce565b506110169261118b9250905b808211156110165760008155600101615cf5560078523850fdd761612f46e844cf5a16bda6b3151d6ae961fd7e8e7b92bfbca7f86f5220989faafdc182d508d697678366f4e831f5f56166ad69bfc253fc548fb1bb75b874360e0bfd87f964eadd8276d8efb7c942134fc329b513032d0803e0c6947f955eec7e1f626bee3afd2aa47b5de04ddcdd3fe78dc8838213015ef58dfdeb2b7ad4d8ce5610cfb46470f03b14c197c2b751077c70209c5d0139f7c79ee9a165627a7a7230582053cc36190b35f63a34c4463788f6e8aa4cce60e96d4b1f16f5c39d72502352260029
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.