Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
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); // 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 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) ); summarySigningKeysStats.add(SUMMARY_TOTAL_KEYS_COUNT_OFFSET, totalSigningKeysCount); } _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(); } 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)); _updateVettedSingingKeysCount(_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); _updateVettedSingingKeysCount(nodeOperatorId, vettedKeysCount, false /* only decrease */); } _increaseValidatorsKeysNonce(); } function _updateVettedSingingKeysCount( 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); } /// @notice Permissionless method for distributing all accumulated module rewards among node operators /// based on the latest accounting report. /// /// @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. /// /// ===================================== Start report frame 1 ===================================== /// /// 1. Oracle first phase: Reach hash consensus. /// 2. Oracle second phase: Module receives rewards. /// 3. Oracle third phase: Operator statistics are updated. /// /// ... Reward can be distributed ... /// /// ===================================== Start report frame 2 ===================================== /// /// ... Reward can be distributed ... /// (if not distributed yet) /// /// 1. Oracle first phase: Reach hash consensus. /// 2. Oracle second phase: Module receives rewards. /// /// ... Reward CANNOT be distributed ... /// /// 3. Oracle third phase: Operator statistics are updated. /// /// ... Reward can be distributed ... /// /// ===================================== Start report frame 3 ===================================== 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) { Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); summarySigningKeysStats.sub(SUMMARY_TOTAL_KEYS_COUNT_OFFSET, totalTrimmedKeysCount); _saveSummarySigningKeysStats(summarySigningKeysStats); _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); // upd totals Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); summarySigningKeysStats.add(SUMMARY_TOTAL_KEYS_COUNT_OFFSET, _keysCount); _saveSummarySigningKeysStats(summarySigningKeysStats); _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); // upd totals Packed64x4.Packed memory summarySigningKeysStats = _loadSummarySigningKeysStats(); summarySigningKeysStats.sub(SUMMARY_TOTAL_KEYS_COUNT_OFFSET, _keysCount); _saveSummarySigningKeysStats(summarySigningKeysStats); _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(); } /// @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; 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 } }
// 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; } }
/* * 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-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; } }
// 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 ILidoLocator { function accountingOracle() external view returns(address); function depositSecurityModule() external view returns(address); function elRewardsVault() external view returns(address); function legacyOracle() 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 coreComponents() external view returns( address elRewardsVault, address oracleReportSanityChecker, address stakingRouter, address treasury, address withdrawalQueue, address withdrawalVault ); function oracleReportComponentsForLido() external view returns( address accountingOracle, address elRewardsVault, address oracleReportSanityChecker, address burner, address withdrawalQueue, address withdrawalVault, address postTokenRebaseReceiver ); }
// 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 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: 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 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-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; 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; 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; 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); } }
/* * 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); } }
// 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; } }
/* * 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; 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); } }
// 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-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; 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); }
// 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; 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; 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; }
/* * 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; 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 "./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); } }
{ "remappings": [ "@aragon/=node_modules/@aragon/", "@openzeppelin/=node_modules/@openzeppelin/", "ens/=node_modules/@aragon/os/contracts/lib/ens/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "forge-std/=foundry/lib/forge-std/src/", "hardhat/=node_modules/hardhat/", "math/=node_modules/@aragon/os/contracts/lib/math/", "misc/=node_modules/@aragon/os/contracts/lib/misc/", "openzeppelin-solidity/=node_modules/openzeppelin-solidity/", "token/=node_modules/@aragon/os/contracts/lib/token/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "constantinople", "libraries": { "contracts/common/lib/MinFirstAllocationStrategy.sol": { "MinFirstAllocationStrategy": "0xf95A8103E6d83B4437Ad20454F86a75ecf1E32Ef" } } }
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":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
6080604052620000146200005460201b60201c565b6200004e7f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a660001962000156602090811b6200402817901c565b6200026b565b620000646200015a60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a454400000000000000006020820152901562000140576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101562000104578181015183820152602001620000ea565b50505050905090810190601f168015620001325780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50620001546000196200018d60201b60201c565b565b9055565b6000620001886000805160206200609883398151915260001b600019166200026760201b620034351760201c565b905090565b6200019d6200015a60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156200023c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101562000104578181015183820152602001620000ea565b5062000264600080516020620060988339815191528262000156602090811b6200402817901c565b50565b5490565b615e1d806200027b6000396000f3006080604052600436106103105760003560e01c63ffffffff1680630803fac01461031557806308a679ad1461033e578063096b7b351461035e57806315dae03e146103925780632914b9bd146103b957806330a90f011461042e57806332f0a3b5146104465780634febc81b1461045b57806359e25c12146104c65780635ddde810146106035780635e2fb908146106215780635e57d7421461063957806362dcfda11461065d57806365cc369a1461073a578063684560a2146107555780636ccc75621461077c5780636d395b7e146107945780636da7d0a7146107a95780636ef355f1146107be5780636f817294146107d95780637038b1411461060357806375049ad81461081257806375a080d51461082a5780637e7db6e11461084257806380231f1514610863578063805911ae1461035e57806380afdea8146108785780638469cbd31461088d57806385fa63d7146108a25780638aa10435146108d05780638b3dd749146108e55780638ca7c052146108fa5780638d7e4017146109125780638ece99951461092a5780638f73c5ae1461093f57806390c09bdb1461095457806391dcd6b214610969578063973e9328146109815780639a56983c146109a55780639a7c2ade14610a815780639abddf0914610aa85780639b00c14614610adb5780639b3d190014610b075780639d4941d814610b33578063a1658fad14610b54578063a2e080f114610bbb578063a479e50814610bd6578063a70c70e414610beb578063a9e7a84614610c00578063ae962acf14610c20578063b3076c3c14610c45578063b449402a14610c9e578063b497183314610da2578063b643189b14610db7578063bee41b5814610de3578063d07442f114610ee5578063d087d28814610ee5578063d4aae0c414610efa578063d8343dcb14610f0f578063d8e71cd114610f24578063db9887ea14610f39578063de4796ed14610f51578063e204d09b14610f66578063e864299e14610f7b578063ec5af3a414610f90578063ed5cfa41146107be578063f2e2ca6314610fa5578063f31bd9c114610fc3578063fbc77ef114610fd8575b600080fd5b34801561032157600080fd5b5061032a610ff0565b604080519115158252519081900360200190f35b34801561034a57600080fd5b5061035c60043560243560443561101a565b005b34801561036a57600080fd5b5061035c600480359060248035916044358083019290820135916064359182019101356110ec565b34801561039e57600080fd5b506103a761115d565b60408051918252519081900360200190f35b3480156103c557600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261041294369492936024939284019190819084018382808284375094975061118e9650505050505050565b60408051600160a060020a039092168252519081900360200190f35b34801561043a57600080fd5b5061032a600435611271565b34801561045257600080fd5b50610412611335565b34801561046757600080fd5b506104766004356024356113aa565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104b257818101518382015260200161049a565b505050509050019250505060405180910390f35b3480156104d257600080fd5b506104e4600435602435604435611441565b60405180806020018060200180602001848103845287818151815260200191508051906020019080838360005b83811015610529578181015183820152602001610511565b50505050905090810190601f1680156105565780820380516001836020036101000a031916815260200191505b50848103835286518152865160209182019188019080838360005b83811015610589578181015183820152602001610571565b50505050905090810190601f1680156105b65780820380516001836020036101000a031916815260200191505b508481038252855181528551602091820191808801910280838360005b838110156105eb5781810151838201526020016105d3565b50505050905001965050505050505060405180910390f35b34801561060f57600080fd5b5061035c60043560243560443561153f565b34801561062d57600080fd5b5061032a60043561154f565b34801561064557600080fd5b5061035c600480359060248035908101910135611564565b34801561066957600080fd5b506106756004356116dc565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156106bd5781810151838201526020016106a5565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156106fc5781810151838201526020016106e4565b5050505090500184810382528581815181526020019150805190602001906020028083836000838110156105eb5781810151838201526020016105d3565b34801561074657600080fd5b5061035c60043560243561190d565b34801561076157600080fd5b5061035c600160a060020a0360043516602435604435611932565b34801561078857600080fd5b5061035c600435611a17565b3480156107a057600080fd5b5061035c611a3a565b3480156107b557600080fd5b506103a7611aac565b3480156107ca57600080fd5b5061035c600435602435611ad7565b3480156107e557600080fd5b506107ee611ae3565b604051808260028111156107fe57fe5b60ff16815260200191505060405180910390f35b34801561081e57600080fd5b5061032a600435611b1d565b34801561083657600080fd5b5061035c600435611b42565b34801561084e57600080fd5b5061032a600160a060020a0360043516611c92565b34801561086f57600080fd5b506103a7611c98565b34801561088457600080fd5b506103a7611caa565b34801561089957600080fd5b506103a7611cd5565b3480156108ae57600080fd5b506103a76024600480358281019291013590600160a060020a03903516611cee565b3480156108dc57600080fd5b506103a7611edf565b3480156108f157600080fd5b506103a7611f0a565b34801561090657600080fd5b506103a7600435611f35565b34801561091e57600080fd5b5061035c600435611f84565b34801561093657600080fd5b506103a7611fa5565b34801561094b57600080fd5b5061035c611fb7565b34801561096057600080fd5b5061035c612033565b34801561097557600080fd5b5061035c60043561206d565b34801561098d57600080fd5b5061035c600435600160a060020a0360243516612120565b3480156109b157600080fd5b506109c260043560243515156121ec565b604080518815158152600160a060020a0387169181019190915267ffffffffffffffff8086166060830152848116608083015283811660a0830152821660c082015260e0602080830182815289519284019290925288516101008401918a019080838360005b83811015610a40578181015183820152602001610a28565b50505050905090810190601f168015610a6d5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b348015610a8d57600080fd5b5061035c600160a060020a036004351660243560443561233f565b348015610ab457600080fd5b50610abd612566565b60408051938452602084019290925282820152519081900360600190f35b348015610ae757600080fd5b5061035c60246004803582810192908201359181359182019101356125c0565b348015610b1357600080fd5b5061035c6024600480358281019290820135918135918201910135612659565b348015610b3f57600080fd5b5061035c600160a060020a03600435166126db565b348015610b6057600080fd5b50604080516020600460443581810135838102808601850190965280855261032a958335600160a060020a031695602480359636969560649593949201929182918501908490808284375094975061296a9650505050505050565b348015610bc757600080fd5b5061035c600435602435612ab7565b348015610be257600080fd5b50610412612ae1565b348015610bf757600080fd5b506103a7612b96565b348015610c0c57600080fd5b5061035c6004356024351515604435612bc1565b348015610c2c57600080fd5b5061035c60043567ffffffffffffffff60243516612bdd565b348015610c5157600080fd5b50610c5d600435612c4d565b604080519889526020890197909752878701959095526060870193909352608086019190915260a085015260c084015260e083015251908190036101000190f35b348015610caa57600080fd5b50610cb9600435602435612d09565b60405180806020018060200184151515158152602001838103835286818151815260200191508051906020019080838360005b83811015610d04578181015183820152602001610cec565b50505050905090810190601f168015610d315780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b83811015610d64578181015183820152602001610d4c565b50505050905090810190601f168015610d915780820380516001836020036101000a031916815260200191505b509550505050505060405180910390f35b348015610dae57600080fd5b506103a7612d47565b348015610dc357600080fd5b5061035c6024600480358281019290820135918135918201910135612d4c565b348015610def57600080fd5b50610e07600480359060248035908101910135612dd0565b604051808060200180602001838103835285818151815260200191508051906020019080838360005b83811015610e48578181015183820152602001610e30565b50505050905090810190601f168015610e755780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015610ea8578181015183820152602001610e90565b50505050905090810190601f168015610ed55780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b348015610ef157600080fd5b506103a7612e9e565b348015610f0657600080fd5b50610412612ec9565b348015610f1b57600080fd5b50610412612ef4565b348015610f3057600080fd5b506103a7612f1f565b348015610f4557600080fd5b506103a7600435612f43565b348015610f5d57600080fd5b5061032a612f72565b348015610f7257600080fd5b506103a7612f85565b348015610f8757600080fd5b5061035c612f8d565b348015610f9c57600080fd5b506103a7612fae565b348015610fb157600080fd5b5061035c600435602435604435612fb3565b348015610fcf57600080fd5b506103a7612ff1565b348015610fe457600080fd5b5061032a600435613015565b600080610ffb611f0a565b90508015801590611013575080611010613054565b10155b91505b5090565b611022615cb1565b61102b84613058565b611042600080516020615d9283398151915261306a565b61105667ffffffffffffffff8311156130a8565b61105f846130ff565b90506110738160008563ffffffff61312b16565b82151561107f57600091505b6110918160018463ffffffff61312b16565b61109b84826131b2565b6040805183815260208101859052815186927ff92eb109ce5b449e9b121c352c6aeb4319538a90738cb95d84f08e41274e92d2928290030190a26110de846131cb565b6110e6613242565b50505050565b611155868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8c018190048102820181019092528a815294508a935089925082915084018382808284375061330b945050505050565b505050505050565b60006111887fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d0613435565b90505b90565b6000611198612ae1565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156111f35781810151838201526020016111db565b50505050905090810190601f1680156112205780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561123f57600080fd5b505af1158015611253573d6000803e3d6000fd5b505050506040513d602081101561126957600080fd5b505192915050565b600061127b615cb1565b61128483613439565b905061128f81613465565b1580156112ab57506112a881600263ffffffff6134aa16565b15155b1515611301576040805160e560020a62461bcd02815260206004820152601260248201527f43414e545f434c4541525f50454e414c54590000000000000000000000000000604482015290519081900360640190fd5b611314816002600063ffffffff61312b16565b61131e83826134c2565b611327836131cb565b61132f613242565b50919050565b600061133f612ec9565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561137957600080fd5b505af115801561138d573d6000803e3d6000fd5b505050506040513d60208110156113a357600080fd5b5051905090565b60606000806113b7612b96565b915081851015806113c6575083155b156113d057611439565b6113dc848684036134db565b604051908082528060200260200182016040528015611405578160200160208202803883390190505b509250600090505b825181101561143957808501838281518110151561142757fe5b6020908102909101015260010161140d565b505092915050565b606080606061144e615cb1565b60008061145a89613058565b611463896134f1565b925061149061147984600263ffffffff6134aa16565b6114898a8a63ffffffff61351d16565b11156130a8565b6114a183600363ffffffff6134aa16565b91506114ac876135b7565b604080518a81526020808c0282010190915291975095508780156114da578160200160208202803883390190505b509350611501600080516020615dd28339815191528a8a8a8a8a600063ffffffff61364216565b86811015611533578181890110848281518110151561151c57fe5b911515602092830290910190910152600101611501565b50505093509350939050565b61154a8383836136b9565b505050565b60009081526020819052604090205460ff1690565b61159d82828080601f0160208091040260200160405190810160405280939291908181526020018383808284375061382d945050505050565b6115a683613058565b6115bd600080516020615d5283398151915261306a565b61166982826040518083838082843782019150509250505060405180910390206000191660008086815260200190815260200160002060010160405180828054600181600116156101000203166002900480156116515780601f1061162f576101008083540402835291820191611651565b820191906000526020600020905b81548152906001019060200180831161163d575b50509150506040518091039020600019161415613896565b6000838152602081905260409020611685906001018383615cc3565b50827fcb16868f4831cc58a28d413f658752a2958bd1f50e94ed6391716b936c48093b83836040518080602001828103825284848281815260200192508082843760405192018290039550909350505050a2505050565b60608060606000806000806116ef615cb1565b6000806000806116fd612b96565b9850611707611cd5565b975087604051908082528060200260200182016040528015611733578160200160208202803883390190505b509b5087604051908082528060200260200182016040528015611760578160200160208202803883390190505b509a508760405190808252806020026020018201604052801561178d578160200160208202803883390190505b50995060009650600095505b8884101561188e576117aa8461154f565b15156117b557611883565b6117be846134f1565b94506117d185600163ffffffff6134aa16565b92506117e485600363ffffffff6134aa16565b9150828210156117f057fe5b506000838152602081905260409020548b5183830396870196916101009004600160a060020a0316908d908990811061182557fe5b600160a060020a039092166020928302909101909101528a5181908c908990811061184c57fe5b6020908102909101015261185f84611b1d565b8a8881518110151561186d57fe5b9115156020928302909101909101526001909601955b836001019350611799565b85151561189a576118fd565b600096505b878710156118fd57856118d08e8d8a8151811015156118ba57fe5b602090810290910101519063ffffffff6138ed16565b8115156118d957fe5b048b888151811015156118e857fe5b6020908102909101015260019096019561189f565b5050505050505050509193909250565b611924600080516020615d5283398151915261306a565b61192e8282613998565b5050565b61193a611f0a565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156119fb5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b838110156119c05781810151838201526020016119a8565b50505050905090810190601f1680156119ed5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50611a07838383613b3b565b611a0f613d8b565b61154a613d9f565b611a2e600080516020615d5283398151915261306a565b611a3781613e65565b50565b611a42610ff0565b1515611a98576040805160e560020a62461bcd02815260206004820152601860248201527f434f4e54524143545f4e4f545f494e495449414c495a45440000000000000000604482015290519081900360640190fd5b611aa26002613edb565b611aaa613d8b565b565b60006111887f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e613435565b61192e828260016136b9565b600080611b0f7f4ddbb0dcdc5f7692e494c15a7fca1f9eb65f31da0b5ce1c3381f6a1a1fd579b6613435565b905080600281111561101357fe5b6000611b27615cb1565b611b3083613439565b9050611b3b81613465565b9392505050565b6000611b4c615cb1565b600080611b5885613058565b611b6f600080516020615d5283398151915261306a565b611b80611b7b8661154f565b613f3d565b611b88611cd5565b9350611bb9611b9e85600163ffffffff613f9416565b600080516020615d728339815191529063ffffffff61402816565b600085815260208181526040808320805460ff1916905580519283525187927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a2611c0a856134f1565b9250611c1d83600063ffffffff6134aa16565b9150611c3083600363ffffffff6134aa16565b905080821115611c8357611c4c8360008363ffffffff61312b16565b611c56858461402c565b6040805182815290518691600080516020615db2833981519152919081900360200190a2611c83856131cb565b611c8b613242565b5050505050565b50600190565b600080516020615d9283398151915281565b60006111887fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b613435565b6000611188600080516020615d72833981519152613435565b6000806000611d2c86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375061382d945050505050565b611d3584614045565b611d4c600080516020615d5283398151915261306a565b611d54612b96565b925060c88310611dae576040805160e560020a62461bcd02815260206004820152601c60248201527f4d41585f4f50455241544f52535f434f554e545f455843454544454400000000604482015290519081900360640190fd5b611de17fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e86001850163ffffffff61402816565b60008381526020819052604090209150611df9611cd5565b9050611e1c600080516020615d728339815191526001830163ffffffff61402816565b815460ff191660019081178355611e369083018787615cc3565b50815474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a03861690810291909117835560408051858152908101919091526000606082018190526080602083018181529083018890527fc52ec0ad7872dae440d886040390c13677df7bf3cca136d8d81e5e5e7dd62ff19286928a928a928a929160a0820186868082843760405192018290039850909650505050505050a150509392505050565b60006111887f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6613435565b60006111887febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e613435565b6000611f3f615cb1565b611f4883613058565b611f51836134f1565b9050611b3b611f6782600363ffffffff6134aa16565b611f7883600263ffffffff6134aa16565b9063ffffffff613f9416565b611f9b600080516020615d9283398151915261306a565b611a37600061411f565b600080516020615d5283398151915281565b6001611fc1611ae3565b6002811115611fcc57fe5b14612021576040805160e560020a62461bcd02815260206004820152601660248201527f444953545249425554494f4e5f4e4f545f524541445900000000000000000000604482015290519081900360640190fd5b61202b600261411f565b611a376141a3565b600061204c600080516020615d9283398151915261306a565b612054612b96565b90506000811115611a3757611a37600060018303613998565b61207681613058565b61208d600080516020615d5283398151915261306a565b61209f6120998261154f565b15613f3d565b6120c86120aa611cd5565b600080516020615d728339815191529060010163ffffffff61402816565b60008181526020818152604091829020805460ff191660019081179091558251908152915183927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a2611a37613242565b61212981614045565b61213282613058565b612149600080516020615d5283398151915261306a565b60008281526020819052604090205461217590600160a060020a03838116610100909204161415613896565b60008281526020818152604091829020805474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a038616908102919091179091558251908152915184927f9a52205165d510fc1e428886d52108725dc01ed544da1702dc7bd3fdb3f243b292908290030190a25050565b60006060600080600080600080612201615cb1565b61220a8b613058565b60008b8152602081905260409020805460ff81169a506101009004600160a060020a0316975091508961224b576040805160208101909152600081526122d8565b60018281018054604080516020600295841615610100026000190190931694909404601f8101839004830285018301909152808452908301828280156122d25780601f106122a7576101008083540402835291602001916122d2565b820191906000526020600020905b8154815290600101906020018083116122b557829003601f168201915b50505050505b97506122e38b6134f1565b90506122f681600063ffffffff6134aa16565b955061230981600163ffffffff6134aa16565b945061231c81600263ffffffff6134aa16565b935061232f81600363ffffffff6134aa16565b9250505092959891949750929550565b6000612349615cb1565b612351615cb1565b612359615cb1565b6000806000806000612369610ff0565b15156123bf576040805160e560020a62461bcd02815260206004820152601860248201527f434f4e54524143545f4e4f545f494e495449414c495a45440000000000000000604482015290519081900360640190fd5b6123c96000613edb565b6123d48c8c8c613b3b565b6123dc612b96565b9850602060405190810160405280600081525095505b8882101561254757612403826134f1565b975061241688600063ffffffff6134aa16565b945061242988600263ffffffff6134aa16565b935061243c88600363ffffffff6134aa16565b60008381526020819052604090205490935060ff16151561245e575081612474565b6124718461246c8588614633565b6134db565b90505b8481146124bc5761248d8860008363ffffffff61312b16565b612497828961402c565b6040805182815290518391600080516020615db2833981519152919081900360200190a25b6124c5826130ff565b96506124d98760028363ffffffff61312b16565b6124e382886131b2565b6124f58660008363ffffffff61464216565b6125078660038563ffffffff61464216565b61252a600161251c8a8263ffffffff6134aa16565b88919063ffffffff61464216565b61253c8660028663ffffffff61464216565b8160010191506123f2565b61255086614666565b612558613242565b505050505050505050505050565b6000806000612573615cb1565b61257b61466c565b905061258e81600163ffffffff6134aa16565b93506125a181600363ffffffff6134aa16565b92506125b883611f7883600063ffffffff6134aa16565b915050909192565b60008080808080806125df600080516020615d9283398151915261306a565b6125e98a89614688565b96506125f3612b96565b95506024600435019250602480350191505b86811015612644576008810283013560c01c94506010810282013560801c93506001016126338686106130a8565b61263f85856000614702565b612605565b61264c613242565b5050505050505050505050565b6000808080808080612678600080516020615d9283398151915261306a565b6126828a89614688565b965061268c612b96565b95506024600435019250602480350191505b86811015612644576008810283013560c01c94506010810282013560801c93506001016126cc8686106130a8565b6126d685856148bd565b61269e565b60008060006126e984611c92565b60408051808201909152601281527f5245434f5645525f444953414c4c4f5745440000000000000000000000000000602082015290151561276f5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b50612778611335565b925061278383614a0d565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156128095760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b50600160a060020a038416151561285a5760405130319250600160a060020a0384169083156108fc029084906000818181858888f19350505050158015612854573d6000803e3d6000fd5b50612919565b5082612875600160a060020a0382163063ffffffff614a3316565b9150612891600160a060020a038216848463ffffffff614b4816565b60408051808201909152601d81527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c454400000060208201529015156129175760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b505b83600160a060020a031683600160a060020a03167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b600080612975610ff0565b15156129845760009150612aaf565b61298c612ec9565b9050600160a060020a03811615156129a75760009150612aaf565b80600160a060020a031663fdef91068630876129c288614bd3565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b83811015612a31578181015183820152602001612a19565b50505050905090810190601f168015612a5e5780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015612a8057600080fd5b505af1158015612a94573d6000803e3d6000fd5b505050506040513d6020811015612aaa57600080fd5b505191505b509392505050565b612ac082613058565b612ad7600080516020615d9283398151915261306a565b61192e8282614bdd565b600080612aec612ec9565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b15801561123f57600080fd5b60006111887fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e8613435565b61154a8383612bd1576000612bd4565b60015b60ff168361101a565b612be682613058565b612c237f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d794754612c1e8467ffffffffffffffff8516614cfe565b614d59565b612c2f611b7b8361154f565b612c45828267ffffffffffffffff166001614d67565b61192e613242565b600080600080600080600080612c61615cb1565b612c69615cb1565b612c728b613058565b612c7b8b6130ff565b9150612c868b613439565b9050612c9982600063ffffffff6134aa16565b9950612cac82600163ffffffff6134aa16565b9850612cbf81600063ffffffff6134aa16565b9750612cd281600163ffffffff6134aa16565b9650612ce581600263ffffffff6134aa16565b9550612cf08b614e80565b8095508196508297505050505050919395975091939597565b60608060006060612d1c86866001611441565b8051929650909450915081906000908110612d3357fe5b906020019060200201519150509250925092565b60ff81565b6000808080808080612d6b600080516020615d9283398151915261306a565b612d758a89614688565b9650612d7f612b96565b95506024600435019250602480350191505b86811015612644576008810283013560c01c94506010810282013560801c9350600101612dbf8686106130a8565b612dcb85856000614d67565b612d91565b60608060008180612dee600080516020615d9283398151915261306a565b871515612e14576040805160008082526020820190815281830190925295509350612e93565b612e1d88614ea0565b91945092509050878314612e7b576040805160e560020a62461bcd02815260206004820152601c60248201527f494e56414c49445f414c4c4f43415445445f4b4559535f434f554e5400000000604482015290519081900360640190fd5b612e86838383615199565b9095509350612e93613242565b505050935093915050565b60006111887fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e613435565b60006111887f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b613435565b60006111887ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d03537613435565b7f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d79475481565b6000612f4d615cb1565b612f5683613058565b612f5f836134f1565b9050611b3b81600263ffffffff6134aa16565b6000600019612f7f611f0a565b14905090565b6301e1338081565b612fa4600080516020615d9283398151915261306a565b611aaa600161411f565b60c881565b612fbc83613058565b612fd3600080516020615d9283398151915261306a565b612fdd83826148bd565b612fe983836001614702565b61154a613242565b7f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee81565b600061301f615cb1565b61302883613439565b905061303381613465565b158015611b3b575061304c81600263ffffffff6134aa16565b159392505050565b4390565b611a37613063612b96565b82106130a8565b611a376130a33383600060405190808252806020026020018201604052801561309d578160200160208202803883390190505b5061296a565b615375565b801515611a37576040805160e560020a62461bcd02815260206004820152600c60248201527f4f55545f4f465f52414e47450000000000000000000000000000000000000000604482015290519081900360640190fd5b613107615cb1565b50600090815260208181526040918290208251918201909252600490910154815290565b67ffffffffffffffff81111561318b576040805160e560020a62461bcd02815260206004820152600f60248201527f5041434b45445f4f564552464c4f570000000000000000000000000000000000604482015290519081900360640190fd5b825167ffffffffffffffff91821660409390930260ff1692831b9190921b19909116179052565b6000918252602082905260409091209051600490910155565b6000806131d6615cb1565b60006131e1856153cc565b93509350838314156131f257611c8b565b6131fa61466c565b915061320683856154c0565b905083831115613227576132228260008363ffffffff61464216565b613239565b6132398260008363ffffffff6154d716565b611c8b82614666565b600061326d7fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e613435565b60010190506132a27fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e8263ffffffff61402816565b6040805182815290517ffb992daec9d46d64898e3a9336d02811349df6cbea8b95d4deb2fa6c7b454f0d9181900360200190a16040805182815290517f7220970e1f1f12864ecccd8942690a837c7a8dd45d158cb891eb45a8a69134aa9181900360200190a150565b613313615cb1565b600061331d615cb1565b61332687613058565b61333033886154ea565b61334f861580159061334a575067ffffffffffffffff8711155b6130a8565b613358876134f1565b925061336b83600263ffffffff6134aa16565b915061338967ffffffffffffffff611489848963ffffffff61351d16565b6133ab600080516020615dd2833981519152888489898963ffffffff61555716565b60408051828152905191935088917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f09181900360200190a26133f58360028463ffffffff61312b16565b6133ff878461402c565b61340761466c565b905061341b8160028863ffffffff61464216565b61342481614666565b61342c613242565b50505050505050565b5490565b613441615cb1565b50600090815260208181526040918290208251918201909252600390910154815290565b6000613477828263ffffffff6134aa16565b61348883600163ffffffff6134aa16565b10806134a457506134a082600263ffffffff6134aa16565b4211155b92915050565b905167ffffffffffffffff604090920260ff161c1690565b6000918252602082905260409091209051600390910155565b60008183106134ea5781611b3b565b5090919050565b6134f9615cb1565b50600090815260208181526040918290208251918201909252600290910154815290565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f57000000000000000000000000000000602082015260009083830190848210156135ab5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b508091505b5092915050565b6060806135cb83603063ffffffff6138ed16565b6040519080825280601f01601f1916602001820160405280156135f8578160200160208202803883390190505b5061360a84606063ffffffff6138ed16565b6040519080825280601f01601f191660200182016040528015613637578160200160208202803883390190505b509092509050915091565b6000805b858110156136ae57613661898989840163ffffffff61580a16565b60018082015460801c85840160308181028a019081019290925283546020928301526002840154606091820289019283015260038401546040830152600484015491015290925001613646565b505050505050505050565b6136c1615cb1565b6000806136cc615cb1565b6136d587613058565b6136df33886154ea565b8415156136eb5761342c565b6136f4876134f1565b935061370784600263ffffffff6134aa16565b925061373861371d85600363ffffffff6134aa16565b871015801561334a575083611489888863ffffffff61351d16565b613759600080516020615dd28339815191528888888763ffffffff61589d16565b925061376d8460028563ffffffff61312b16565b60408051848152905188917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a26137b484600063ffffffff6134aa16565b9150818610156137f5576137d08460008863ffffffff61312b16565b6040805187815290518891600080516020615db2833981519152919081900360200190a25b6137ff878561402c565b61380761466c565b905061381b8160028763ffffffff6154d716565b61382481614666565b613424876131cb565b60008151118015613840575060ff815111155b1515611a37576040805160e560020a62461bcd02815260206004820152601160248201527f57524f4e475f4e414d455f4c454e475448000000000000000000000000000000604482015290519081900360640190fd5b801515611a37576040805160e560020a62461bcd02815260206004820152601160248201527f56414c55455f49535f5448455f53414d45000000000000000000000000000000604482015290519081900360640190fd5b60008083151561390057600091506135b0565b5082820282848281151561391057fe5b60408051808201909152601181527f4d4154485f4d554c5f4f564552464c4f57000000000000000000000000000000602082015292919004146135ab5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b6000806000806139a6615cb1565b60006139b0615cb1565b6139cd888a1115801561334a57506139c6612b96565b89106130a8565b8891505b878211613b05576139e1826134f1565b92506139f483600263ffffffff6134aa16565b9450613a0783600363ffffffff6134aa16565b935083851415613a1657613afa565b838511613a1f57fe5b838503965094860194613a3a8360028663ffffffff61312b16565b613a4c8360008663ffffffff61312b16565b613a56828461402c565b613a5f826131cb565b60408051858152905183917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a26040805185815290518391600080516020615db2833981519152919081900360200190a26040805167ffffffffffffffff89168152905183917f9824694569ba758f8872bb150515caaf8f1e2cc27e6805679c4ac8c3b9b83d87919081900360200190a25b8160010191506139d1565b60008611156136ae57613b1661466c565b9050613b2a8160028863ffffffff6154d716565b613b3381614666565b6136ae613242565b613b4483615aa6565b613b747ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d035378463ffffffff61402816565b613ba47fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d08363ffffffff61402816565b613bae6002615b06565b613bb781613e65565b613bbf612ef4565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613bf957600080fd5b505af1158015613c0d573d6000803e3d6000fd5b505050506040513d6020811015613c2357600080fd5b5051600160a060020a031663095ea7b3613c3b612ef4565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613c7557600080fd5b505af1158015613c89573d6000803e3d6000fd5b505050506040513d6020811015613c9f57600080fd5b50516040805163ffffffff841660e01b8152600160a060020a03909216600483015260001960248301525160448083019260209291908290030181600087803b158015613ceb57600080fd5b505af1158015613cff573d6000803e3d6000fd5b505050506040513d6020811015613d1557600080fd5b505060408051600160a060020a038516815290517fa44aa4b7320163340e971b1f22f153bbb8a0151d783bd58377018ea5bc96d0c99181900360200190a16040805183815290517fdb042010b15d1321c99552200b350bba0a95dfa3d0b43869983ce74b44d644ee9181900360200190a1505050565b613d956003615b06565b611aaa600261411f565b613da7611f0a565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015613e2c5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b50611aaa613e38613054565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61402816565b613e756301e133808211156130a8565b613ea57f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e8263ffffffff61402816565b6040805182815290517f4cccd9748bff0341d9852cc61d82652a3003dcebea088f05388c0be1f26b4c8a9181900360200190a150565b613ee3611edf565b8114611a37576040805160e560020a62461bcd02815260206004820152601b60248201527f554e45585045435445445f434f4e54524143545f56455253494f4e0000000000604482015290519081900360640190fd5b5490565b801515611a37576040805160e560020a62461bcd02815260206004820152601b60248201527f57524f4e475f4f50455241544f525f4143544956455f53544154450000000000604482015290519081900360640190fd5b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f57000000000000000000000000000060208201526000908190848411156140205760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b505050900390565b9055565b6000918252602082905260409091209051600290910155565b61404e81615aa6565b614056612ef4565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561409057600080fd5b505af11580156140a4573d6000803e3d6000fd5b505050506040513d60208110156140ba57600080fd5b5051600160a060020a0382811691161415611a37576040805160e560020a62461bcd02815260206004820152601360248201527f4c49444f5f5245574152445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b61415b81600281111561412e57fe5b7f4ddbb0dcdc5f7692e494c15a7fca1f9eb65f31da0b5ce1c3381f6a1a1fd579b69063ffffffff61402816565b7f7545d380f29a8ae65fafb1acdf2c7762ec02d5607fecbea9dd8d8245e1616d93816040518082600281111561418d57fe5b60ff16815260200191505060405180910390a150565b600080600060608060606000806141b8612ef4565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156141f257600080fd5b505af1158015614206573d6000803e3d6000fd5b505050506040513d602081101561421c57600080fd5b5051604080517ff5eb42dc0000000000000000000000000000000000000000000000000000000081523060048201529051919850600160a060020a0389169163f5eb42dc916024808201926020929091908290030181600087803b15801561428357600080fd5b505af1158015614297573d6000803e3d6000fd5b505050506040513d60208110156142ad57600080fd5b505195508515156142bd57614629565b6142c6866116dc565b9450945094505b845181101561453057600284828151811015156142e657fe5b9060200190602002015110156142fb57614528565b828181518110151561430957fe5b90602001906020020151156143d3576001848281518110151561432857fe5b602090810290910101805190911c905283516143619085908390811061434a57fe5b60209081029091010151839063ffffffff61351d16565b9150848181518110151561437157fe5b90602001906020020151600160a060020a03167fe915a473fc2ef8e0231da98380f853b2aeea117a4392c67e753c54186bfbbd1285838151811015156143b357fe5b906020019060200201516040518082815260200191505060405180910390a25b86600160a060020a0316638fcb4e5b86838151811015156143f057fe5b90602001906020020151868481518110151561440857fe5b906020019060200201516040518363ffffffff1660e01b81526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b15801561446157600080fd5b505af1158015614475573d6000803e3d6000fd5b505050506040513d602081101561448b57600080fd5b505083516144b69085908390811061449f57fe5b60209081029091010151899063ffffffff61351d16565b975084818151811015156144c657fe5b90602001906020020151600160a060020a03167fdf29796aad820e4bb192f3a8d631b76519bcd2cbe77cc85af20e9df53cece086858381518110151561450857fe5b906020019060200201516040518082815260200191505060405180910390a25b6001016142cd565b600082111561462957614541612ef4565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561457b57600080fd5b505af115801561458f573d6000803e3d6000fd5b505050506040513d60208110156145a557600080fd5b5051604080517f46114928000000000000000000000000000000000000000000000000000000008152306004820152602481018590529051600160a060020a039092169163461149289160448082019260009290919082900301818387803b15801561461057600080fd5b505af1158015614624573d6000803e3d6000fd5b505050505b5050505050505090565b60008183116134ea5781611b3b565b61154a83836146618461465588886134aa565b9063ffffffff61351d16565b61312b565b51600155565b614674615cb1565b506040805160208101909152600154815290565b60088204601082048114801561469f575060088306155b80156146ac575060108206155b15156134a4576040805160e560020a62461bcd02815260206004820152601360248201527f494e56414c49445f5245504f52545f4441544100000000000000000000000000604482015290519081900360640190fd5b61470a615cb1565b6000806000614717615cb1565b6000614722896134f1565b955061473586600163ffffffff6134aa16565b945084881415614744576136ae565b868061474f57508488115b15156147cb576040805160e560020a62461bcd02815260206004820152602160248201527f4558495445445f56414c494441544f52535f434f554e545f444543524541534560448201527f4400000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6147dc86600363ffffffff6134aa16565b93506147f860006147ec8b613439565b9063ffffffff6134aa16565b92508284101561480457fe5b6148128385038911156130a8565b6148248660018a63ffffffff61312b16565b61482e898761402c565b6040805189815290518a917f0f67960648751434ae86bf350db61194f387fda387e7f568b0ccd0ae0c220166919081900360200190a261486c61466c565b915061487888866154c0565b905084881115614899576148948260018363ffffffff61464216565b6148ab565b6148ab8260018363ffffffff6154d716565b6148b482614666565b6136ae896131cb565b6148c5615cb1565b60006148cf615cb1565b60008060006148dd88613439565b95506148f086600063ffffffff6134aa16565b9450848714156148ff57614a03565b614908886134f1565b935061491b84600163ffffffff6134aa16565b925061492e84600363ffffffff6134aa16565b91508282101561493a57fe5b6149488383038811156130a8565b61495986600163ffffffff6134aa16565b905080871115801561496a57508085115b1561498c5761498c600261497c611aac565b889190420163ffffffff61312b16565b61499e8660008963ffffffff61312b16565b6149a888876134c2565b877f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb88836149dd8a600263ffffffff6134aa16565b60408051938452602084019290925282820152519081900360600190a2614a03886131cb565b5050505050505050565b600080600160a060020a0383161515614a29576000915061132f565b50506000903b1190565b60408051600160a060020a0383166024808301919091528251808303909101815260449091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790526000908180614ab38684615b6c565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f52455645525445440000000060208201529193509150821515614b3e5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b5095945050505050565b60408051600160a060020a038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600090614bca8582615b9d565b95945050505050565b8051602002815290565b614be5615cb1565b6000614bef615cb1565b6000614bfa86613439565b9350614c0d84600163ffffffff6134aa16565b925082851415614c1c57611155565b614c25866134f1565b9150614c43614c3b83600363ffffffff6134aa16565b8611156130a8565b614c5484600063ffffffff6134aa16565b9050808510158015614c6557508083105b15614c8757614c876002614c77611aac565b869190420163ffffffff61312b16565b614c998460018763ffffffff61312b16565b614ca386856134c2565b857f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb8287614cd888600263ffffffff6134aa16565b60408051938452602084019290925282820152519081900360600190a2611155866131cb565b604080516002808252606080830184529260208301908038833901905050905082816000815181101515614d2e57fe5b602090810290910101528051829082906001908110614d4957fe5b6020908102909101015292915050565b61192e6130a333848461296a565b614d6f615cb1565b600080600080614d7e886134f1565b9450614d9185600063ffffffff6134aa16565b9350614da485600363ffffffff6134aa16565b9250614db785600263ffffffff6134aa16565b9150614dc78261246c8986614633565b905083811415614dd657614a03565b8580614de157508381105b1515614e37576040805160e560020a62461bcd02815260206004820152601b60248201527f5645545445445f4b4559535f434f554e545f494e435245415345440000000000604482015290519081900360640190fd5b614e498560008363ffffffff61312b16565b614e53888661402c565b6040805182815290518991600080516020615db2833981519152919081900360200190a2614a03886131cb565b600080600080614e8f85615beb565b919790965090869003945092505050565b600060608060006060600080600080600080614eba611cd5565b975087604051908082528060200260200182016040528015614ee6578160200160208202803883390190505b50995087604051908082528060200260200182016040528015614f13578160200160208202803883390190505b50985087604051908082528060200260200182016040528015614f40578160200160208202803883390190505b509650614f4b612b96565b94505b84811015614fd257614f5f81615beb565b95509350915082841415614f7257614fca565b808a87815181101515614f8157fe5b602090810290910101528851828403908a9088908110614f9d57fe5b60209081029091010152865182850390889088908110614fb957fe5b602090810290910101526001909501945b600101614f4e565b851515614ffa57604080516000808252602082018181528284019093529c509a50985061518a565b8786101561500c57858a528589528587525b73f95a8103e6d83b4437ad20454f86a75ecf1e32ef632529fbc98a898f6040518463ffffffff1660e01b8152600401808060200180602001848152602001838103835286818151815260200191508051906020019060200280838360005b8381101561508257818101518382015260200161506a565b50505050905001838103825285818151815260200191508051906020019060200280838360005b838110156150c15781810151838201526020016150a9565b505050509050019550505050505060006040518083038186803b1580156150e757600080fd5b505af41580156150fb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604090815281101561512457600080fd5b81516020830180519193928301929164010000000081111561514557600080fd5b8201602081018481111561515857600080fd5b815185602082028301116401000000008211171561517557600080fd5b50949f509c505050508b8d1015905061518a57fe5b50505050505050509193909250565b6060806000806000806151aa615cb1565b60006151b4615cb1565b6151bd8c6135b7565b9099509750600096505b8a51821015615338576151f08b838151811015156151e157fe5b906020019060200201516134f1565b925061520383600363ffffffff6134aa16565b9550898281518110151561521357fe5b6020908102909101015161522e84600163ffffffff6134aa16565b0194508585141561523e5761532d565b85851161524757fe5b85850393506152878b8381518110151561525d57fe5b60209081029091010151600080516020615dd28339815191529088878d8d8d63ffffffff61364216565b8a51968401968b908390811061529957fe5b906020019060200201517f24eb1c9e765ba41accf9437300ea91ece5ed3f897ec3cdee0e9debd7fe309b78866040518082815260200191505060405180910390a26152ec8360038763ffffffff61312b16565b61530d8b838151811015156152fd57fe5b906020019060200201518461402c565b61532d8b8381518110151561531e57fe5b906020019060200201516131cb565b8160010191506151c7565b868c1461534157fe5b61534961466c565b905061535d8160038963ffffffff61464216565b61536681614666565b50505050505050935093915050565b801515611a37576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b6000806153d7615cb1565b6153df615cb1565b60006153ea866134f1565b92506153f5866130ff565b915061540883600363ffffffff6134aa16565b905061541b83600063ffffffff6134aa16565b935061542686613015565b151561543457809350615482565b61544582600063ffffffff6134aa16565b156154825761547f8161547a8661546386600163ffffffff6134aa16565b61547488600163ffffffff6134aa16565b016134db565b614633565b93505b61549382600263ffffffff6134aa16565b94508385146154b8576154ae8260028663ffffffff61312b16565b6154b886836131b2565b505050915091565b60008183116154d157828203611b3b565b50900390565b61154a838361466184611f7888886134aa565b6000818152602081905260409020546101008104600160a060020a03908116908416149060ff166110e682801561551e5750815b806130a357506130a3857f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee61555287615c70565b61296a565b6000806000606060008088118015615586575067ffffffffffffffff6155838a8a63ffffffff61351d16565b11155b15156155dc576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b6155ed88603063ffffffff6138ed16565b875114801561560c575061560888606063ffffffff6138ed16565b8651145b1515615662576040805160e560020a62461bcd02815260206004820152600f60248201527f4c454e4754485f4d49534d415443480000000000000000000000000000000000604482015290519081900360640190fd5b604080516030808252606082019092529060208201610600803883390190505091505b878110156157fb5761569e8b8b8b63ffffffff61580a16565b60308281028901602081810151918301519286018390528501819052919550171592508215615717576040805160e560020a62461bcd02815260206004820152600960248201527f454d5054595f4b45590000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60208201518455603082015160801b600185015560608102602087010180516002860155602081015160038601556040810151600486015560018201915060018a01995050897fc77a17d6b857abe6d6e6c37301621bc72c4dd52fa8830fb54dfa715c04911a89836040518080602001828103825283818151815260200191508051906020019080838360005b838110156157bc5781810151838201526020016157a4565b50505050905090810190601f1680156157e95780820380516001836020036101000a031916815260200191505b509250505060405180910390a2615685565b50969998505050505050505050565b6040805160208082018690528183018590526060808301859052835180840390910181526080909201928390528151600093918291908401908083835b602083106158665780518252601f199092019160209182019101615847565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912060001c979650505050505050565b6000806000806060600080881180156158c55750866158c28a8a63ffffffff61351d16565b11155b80156158d9575067ffffffffffffffff8711155b151561592f576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b60408051603080825260608201909252906020820161060080388339019050509150508787015b88811115615a97576159738b8b600019840163ffffffff61580a16565b9450600185015460801c603083015284546020830152868110156159cd576159a68b8b6000198a0163ffffffff61580a16565b9350600092505b60058310156159c95782840154838601556001830192506159ad565b8394505b600092505b60058310156159ec576000838601556001830192506159d2565b600187039650600181039050897fea4b75aaf57196f73d338cadf79ecd0a437902e2dd0d2c4c2cf3ea71b8ab27b9836040518080602001828103825283818151815260200191508051906020019080838360005b83811015615a58578181015183820152602001615a40565b50505050905090810190601f168015615a855780820380516001836020036101000a031916815260200191505b509250505060405180910390a2615956565b50949998505050505050505050565b600160a060020a0381161515611a37576040805160e560020a62461bcd02815260206004820152600c60248201527f5a45524f5f414444524553530000000000000000000000000000000000000000604482015290519081900360640190fd5b615b367f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a68263ffffffff61402816565b6040805182815290517ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9181900360200190a150565b6000806000806040516020818751602089018a5afa92506000831115615b9157805191505b50909590945092505050565b6000806040516020818551602087016000895af16000811115615be1573d8015615bce5760208114615bd757615bdf565b60019350615bdf565b600183511493505b505b5090949350505050565b6000806000615bf8615cb1565b615c00615cb1565b615c09866134f1565b9150615c14866130ff565b9050615c2782600163ffffffff6134aa16565b9450615c3a82600363ffffffff6134aa16565b9350615c4d81600263ffffffff6134aa16565b9250838310158015615c5f5750848410155b1515615c6757fe5b50509193909250565b6040805160018082528183019092526060916020808301908038833901905050905081816000815181101515615ca257fe5b60209081029091010152919050565b60408051602081019091526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615d045782800160ff19823516178555615d31565b82800160010185558215615d31579182015b82811115615d31578235825591602001919060010190615d16565b506110169261118b9250905b808211156110165760008155600101615d3d560078523850fdd761612f46e844cf5a16bda6b3151d6ae961fd7e8e7b92bfbca7f86f5220989faafdc182d508d697678366f4e831f5f56166ad69bfc253fc548fb1bb75b874360e0bfd87f964eadd8276d8efb7c942134fc329b513032d0803e0c6947f955eec7e1f626bee3afd2aa47b5de04ddcdd3fe78dc8838213015ef58dfdeb2b7ad4d8ce5610cfb46470f03b14c197c2b751077c70209c5d0139f7c79ee9a165627a7a7230582056b92d7c3e0e09c29ea3f9bce7fe95586d6bce0361dab7e92936681de9c569480029ebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e
Deployed Bytecode
0x6080604052600436106103105760003560e01c63ffffffff1680630803fac01461031557806308a679ad1461033e578063096b7b351461035e57806315dae03e146103925780632914b9bd146103b957806330a90f011461042e57806332f0a3b5146104465780634febc81b1461045b57806359e25c12146104c65780635ddde810146106035780635e2fb908146106215780635e57d7421461063957806362dcfda11461065d57806365cc369a1461073a578063684560a2146107555780636ccc75621461077c5780636d395b7e146107945780636da7d0a7146107a95780636ef355f1146107be5780636f817294146107d95780637038b1411461060357806375049ad81461081257806375a080d51461082a5780637e7db6e11461084257806380231f1514610863578063805911ae1461035e57806380afdea8146108785780638469cbd31461088d57806385fa63d7146108a25780638aa10435146108d05780638b3dd749146108e55780638ca7c052146108fa5780638d7e4017146109125780638ece99951461092a5780638f73c5ae1461093f57806390c09bdb1461095457806391dcd6b214610969578063973e9328146109815780639a56983c146109a55780639a7c2ade14610a815780639abddf0914610aa85780639b00c14614610adb5780639b3d190014610b075780639d4941d814610b33578063a1658fad14610b54578063a2e080f114610bbb578063a479e50814610bd6578063a70c70e414610beb578063a9e7a84614610c00578063ae962acf14610c20578063b3076c3c14610c45578063b449402a14610c9e578063b497183314610da2578063b643189b14610db7578063bee41b5814610de3578063d07442f114610ee5578063d087d28814610ee5578063d4aae0c414610efa578063d8343dcb14610f0f578063d8e71cd114610f24578063db9887ea14610f39578063de4796ed14610f51578063e204d09b14610f66578063e864299e14610f7b578063ec5af3a414610f90578063ed5cfa41146107be578063f2e2ca6314610fa5578063f31bd9c114610fc3578063fbc77ef114610fd8575b600080fd5b34801561032157600080fd5b5061032a610ff0565b604080519115158252519081900360200190f35b34801561034a57600080fd5b5061035c60043560243560443561101a565b005b34801561036a57600080fd5b5061035c600480359060248035916044358083019290820135916064359182019101356110ec565b34801561039e57600080fd5b506103a761115d565b60408051918252519081900360200190f35b3480156103c557600080fd5b506040805160206004803580820135601f810184900484028501840190955284845261041294369492936024939284019190819084018382808284375094975061118e9650505050505050565b60408051600160a060020a039092168252519081900360200190f35b34801561043a57600080fd5b5061032a600435611271565b34801561045257600080fd5b50610412611335565b34801561046757600080fd5b506104766004356024356113aa565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104b257818101518382015260200161049a565b505050509050019250505060405180910390f35b3480156104d257600080fd5b506104e4600435602435604435611441565b60405180806020018060200180602001848103845287818151815260200191508051906020019080838360005b83811015610529578181015183820152602001610511565b50505050905090810190601f1680156105565780820380516001836020036101000a031916815260200191505b50848103835286518152865160209182019188019080838360005b83811015610589578181015183820152602001610571565b50505050905090810190601f1680156105b65780820380516001836020036101000a031916815260200191505b508481038252855181528551602091820191808801910280838360005b838110156105eb5781810151838201526020016105d3565b50505050905001965050505050505060405180910390f35b34801561060f57600080fd5b5061035c60043560243560443561153f565b34801561062d57600080fd5b5061032a60043561154f565b34801561064557600080fd5b5061035c600480359060248035908101910135611564565b34801561066957600080fd5b506106756004356116dc565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b838110156106bd5781810151838201526020016106a5565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156106fc5781810151838201526020016106e4565b5050505090500184810382528581815181526020019150805190602001906020028083836000838110156105eb5781810151838201526020016105d3565b34801561074657600080fd5b5061035c60043560243561190d565b34801561076157600080fd5b5061035c600160a060020a0360043516602435604435611932565b34801561078857600080fd5b5061035c600435611a17565b3480156107a057600080fd5b5061035c611a3a565b3480156107b557600080fd5b506103a7611aac565b3480156107ca57600080fd5b5061035c600435602435611ad7565b3480156107e557600080fd5b506107ee611ae3565b604051808260028111156107fe57fe5b60ff16815260200191505060405180910390f35b34801561081e57600080fd5b5061032a600435611b1d565b34801561083657600080fd5b5061035c600435611b42565b34801561084e57600080fd5b5061032a600160a060020a0360043516611c92565b34801561086f57600080fd5b506103a7611c98565b34801561088457600080fd5b506103a7611caa565b34801561089957600080fd5b506103a7611cd5565b3480156108ae57600080fd5b506103a76024600480358281019291013590600160a060020a03903516611cee565b3480156108dc57600080fd5b506103a7611edf565b3480156108f157600080fd5b506103a7611f0a565b34801561090657600080fd5b506103a7600435611f35565b34801561091e57600080fd5b5061035c600435611f84565b34801561093657600080fd5b506103a7611fa5565b34801561094b57600080fd5b5061035c611fb7565b34801561096057600080fd5b5061035c612033565b34801561097557600080fd5b5061035c60043561206d565b34801561098d57600080fd5b5061035c600435600160a060020a0360243516612120565b3480156109b157600080fd5b506109c260043560243515156121ec565b604080518815158152600160a060020a0387169181019190915267ffffffffffffffff8086166060830152848116608083015283811660a0830152821660c082015260e0602080830182815289519284019290925288516101008401918a019080838360005b83811015610a40578181015183820152602001610a28565b50505050905090810190601f168015610a6d5780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b348015610a8d57600080fd5b5061035c600160a060020a036004351660243560443561233f565b348015610ab457600080fd5b50610abd612566565b60408051938452602084019290925282820152519081900360600190f35b348015610ae757600080fd5b5061035c60246004803582810192908201359181359182019101356125c0565b348015610b1357600080fd5b5061035c6024600480358281019290820135918135918201910135612659565b348015610b3f57600080fd5b5061035c600160a060020a03600435166126db565b348015610b6057600080fd5b50604080516020600460443581810135838102808601850190965280855261032a958335600160a060020a031695602480359636969560649593949201929182918501908490808284375094975061296a9650505050505050565b348015610bc757600080fd5b5061035c600435602435612ab7565b348015610be257600080fd5b50610412612ae1565b348015610bf757600080fd5b506103a7612b96565b348015610c0c57600080fd5b5061035c6004356024351515604435612bc1565b348015610c2c57600080fd5b5061035c60043567ffffffffffffffff60243516612bdd565b348015610c5157600080fd5b50610c5d600435612c4d565b604080519889526020890197909752878701959095526060870193909352608086019190915260a085015260c084015260e083015251908190036101000190f35b348015610caa57600080fd5b50610cb9600435602435612d09565b60405180806020018060200184151515158152602001838103835286818151815260200191508051906020019080838360005b83811015610d04578181015183820152602001610cec565b50505050905090810190601f168015610d315780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b83811015610d64578181015183820152602001610d4c565b50505050905090810190601f168015610d915780820380516001836020036101000a031916815260200191505b509550505050505060405180910390f35b348015610dae57600080fd5b506103a7612d47565b348015610dc357600080fd5b5061035c6024600480358281019290820135918135918201910135612d4c565b348015610def57600080fd5b50610e07600480359060248035908101910135612dd0565b604051808060200180602001838103835285818151815260200191508051906020019080838360005b83811015610e48578181015183820152602001610e30565b50505050905090810190601f168015610e755780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015610ea8578181015183820152602001610e90565b50505050905090810190601f168015610ed55780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b348015610ef157600080fd5b506103a7612e9e565b348015610f0657600080fd5b50610412612ec9565b348015610f1b57600080fd5b50610412612ef4565b348015610f3057600080fd5b506103a7612f1f565b348015610f4557600080fd5b506103a7600435612f43565b348015610f5d57600080fd5b5061032a612f72565b348015610f7257600080fd5b506103a7612f85565b348015610f8757600080fd5b5061035c612f8d565b348015610f9c57600080fd5b506103a7612fae565b348015610fb157600080fd5b5061035c600435602435604435612fb3565b348015610fcf57600080fd5b506103a7612ff1565b348015610fe457600080fd5b5061032a600435613015565b600080610ffb611f0a565b90508015801590611013575080611010613054565b10155b91505b5090565b611022615cb1565b61102b84613058565b611042600080516020615d9283398151915261306a565b61105667ffffffffffffffff8311156130a8565b61105f846130ff565b90506110738160008563ffffffff61312b16565b82151561107f57600091505b6110918160018463ffffffff61312b16565b61109b84826131b2565b6040805183815260208101859052815186927ff92eb109ce5b449e9b121c352c6aeb4319538a90738cb95d84f08e41274e92d2928290030190a26110de846131cb565b6110e6613242565b50505050565b611155868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8c018190048102820181019092528a815294508a935089925082915084018382808284375061330b945050505050565b505050505050565b60006111887fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d0613435565b90505b90565b6000611198612ae1565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156111f35781810151838201526020016111db565b50505050905090810190601f1680156112205780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561123f57600080fd5b505af1158015611253573d6000803e3d6000fd5b505050506040513d602081101561126957600080fd5b505192915050565b600061127b615cb1565b61128483613439565b905061128f81613465565b1580156112ab57506112a881600263ffffffff6134aa16565b15155b1515611301576040805160e560020a62461bcd02815260206004820152601260248201527f43414e545f434c4541525f50454e414c54590000000000000000000000000000604482015290519081900360640190fd5b611314816002600063ffffffff61312b16565b61131e83826134c2565b611327836131cb565b61132f613242565b50919050565b600061133f612ec9565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561137957600080fd5b505af115801561138d573d6000803e3d6000fd5b505050506040513d60208110156113a357600080fd5b5051905090565b60606000806113b7612b96565b915081851015806113c6575083155b156113d057611439565b6113dc848684036134db565b604051908082528060200260200182016040528015611405578160200160208202803883390190505b509250600090505b825181101561143957808501838281518110151561142757fe5b6020908102909101015260010161140d565b505092915050565b606080606061144e615cb1565b60008061145a89613058565b611463896134f1565b925061149061147984600263ffffffff6134aa16565b6114898a8a63ffffffff61351d16565b11156130a8565b6114a183600363ffffffff6134aa16565b91506114ac876135b7565b604080518a81526020808c0282010190915291975095508780156114da578160200160208202803883390190505b509350611501600080516020615dd28339815191528a8a8a8a8a600063ffffffff61364216565b86811015611533578181890110848281518110151561151c57fe5b911515602092830290910190910152600101611501565b50505093509350939050565b61154a8383836136b9565b505050565b60009081526020819052604090205460ff1690565b61159d82828080601f0160208091040260200160405190810160405280939291908181526020018383808284375061382d945050505050565b6115a683613058565b6115bd600080516020615d5283398151915261306a565b61166982826040518083838082843782019150509250505060405180910390206000191660008086815260200190815260200160002060010160405180828054600181600116156101000203166002900480156116515780601f1061162f576101008083540402835291820191611651565b820191906000526020600020905b81548152906001019060200180831161163d575b50509150506040518091039020600019161415613896565b6000838152602081905260409020611685906001018383615cc3565b50827fcb16868f4831cc58a28d413f658752a2958bd1f50e94ed6391716b936c48093b83836040518080602001828103825284848281815260200192508082843760405192018290039550909350505050a2505050565b60608060606000806000806116ef615cb1565b6000806000806116fd612b96565b9850611707611cd5565b975087604051908082528060200260200182016040528015611733578160200160208202803883390190505b509b5087604051908082528060200260200182016040528015611760578160200160208202803883390190505b509a508760405190808252806020026020018201604052801561178d578160200160208202803883390190505b50995060009650600095505b8884101561188e576117aa8461154f565b15156117b557611883565b6117be846134f1565b94506117d185600163ffffffff6134aa16565b92506117e485600363ffffffff6134aa16565b9150828210156117f057fe5b506000838152602081905260409020548b5183830396870196916101009004600160a060020a0316908d908990811061182557fe5b600160a060020a039092166020928302909101909101528a5181908c908990811061184c57fe5b6020908102909101015261185f84611b1d565b8a8881518110151561186d57fe5b9115156020928302909101909101526001909601955b836001019350611799565b85151561189a576118fd565b600096505b878710156118fd57856118d08e8d8a8151811015156118ba57fe5b602090810290910101519063ffffffff6138ed16565b8115156118d957fe5b048b888151811015156118e857fe5b6020908102909101015260019096019561189f565b5050505050505050509193909250565b611924600080516020615d5283398151915261306a565b61192e8282613998565b5050565b61193a611f0a565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156119fb5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b838110156119c05781810151838201526020016119a8565b50505050905090810190601f1680156119ed5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50611a07838383613b3b565b611a0f613d8b565b61154a613d9f565b611a2e600080516020615d5283398151915261306a565b611a3781613e65565b50565b611a42610ff0565b1515611a98576040805160e560020a62461bcd02815260206004820152601860248201527f434f4e54524143545f4e4f545f494e495449414c495a45440000000000000000604482015290519081900360640190fd5b611aa26002613edb565b611aaa613d8b565b565b60006111887f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e613435565b61192e828260016136b9565b600080611b0f7f4ddbb0dcdc5f7692e494c15a7fca1f9eb65f31da0b5ce1c3381f6a1a1fd579b6613435565b905080600281111561101357fe5b6000611b27615cb1565b611b3083613439565b9050611b3b81613465565b9392505050565b6000611b4c615cb1565b600080611b5885613058565b611b6f600080516020615d5283398151915261306a565b611b80611b7b8661154f565b613f3d565b611b88611cd5565b9350611bb9611b9e85600163ffffffff613f9416565b600080516020615d728339815191529063ffffffff61402816565b600085815260208181526040808320805460ff1916905580519283525187927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a2611c0a856134f1565b9250611c1d83600063ffffffff6134aa16565b9150611c3083600363ffffffff6134aa16565b905080821115611c8357611c4c8360008363ffffffff61312b16565b611c56858461402c565b6040805182815290518691600080516020615db2833981519152919081900360200190a2611c83856131cb565b611c8b613242565b5050505050565b50600190565b600080516020615d9283398151915281565b60006111887fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b613435565b6000611188600080516020615d72833981519152613435565b6000806000611d2c86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375061382d945050505050565b611d3584614045565b611d4c600080516020615d5283398151915261306a565b611d54612b96565b925060c88310611dae576040805160e560020a62461bcd02815260206004820152601c60248201527f4d41585f4f50455241544f52535f434f554e545f455843454544454400000000604482015290519081900360640190fd5b611de17fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e86001850163ffffffff61402816565b60008381526020819052604090209150611df9611cd5565b9050611e1c600080516020615d728339815191526001830163ffffffff61402816565b815460ff191660019081178355611e369083018787615cc3565b50815474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a03861690810291909117835560408051858152908101919091526000606082018190526080602083018181529083018890527fc52ec0ad7872dae440d886040390c13677df7bf3cca136d8d81e5e5e7dd62ff19286928a928a928a929160a0820186868082843760405192018290039850909650505050505050a150509392505050565b60006111887f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6613435565b60006111887febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e613435565b6000611f3f615cb1565b611f4883613058565b611f51836134f1565b9050611b3b611f6782600363ffffffff6134aa16565b611f7883600263ffffffff6134aa16565b9063ffffffff613f9416565b611f9b600080516020615d9283398151915261306a565b611a37600061411f565b600080516020615d5283398151915281565b6001611fc1611ae3565b6002811115611fcc57fe5b14612021576040805160e560020a62461bcd02815260206004820152601660248201527f444953545249425554494f4e5f4e4f545f524541445900000000000000000000604482015290519081900360640190fd5b61202b600261411f565b611a376141a3565b600061204c600080516020615d9283398151915261306a565b612054612b96565b90506000811115611a3757611a37600060018303613998565b61207681613058565b61208d600080516020615d5283398151915261306a565b61209f6120998261154f565b15613f3d565b6120c86120aa611cd5565b600080516020615d728339815191529060010163ffffffff61402816565b60008181526020818152604091829020805460ff191660019081179091558251908152915183927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a2611a37613242565b61212981614045565b61213282613058565b612149600080516020615d5283398151915261306a565b60008281526020819052604090205461217590600160a060020a03838116610100909204161415613896565b60008281526020818152604091829020805474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a038616908102919091179091558251908152915184927f9a52205165d510fc1e428886d52108725dc01ed544da1702dc7bd3fdb3f243b292908290030190a25050565b60006060600080600080600080612201615cb1565b61220a8b613058565b60008b8152602081905260409020805460ff81169a506101009004600160a060020a0316975091508961224b576040805160208101909152600081526122d8565b60018281018054604080516020600295841615610100026000190190931694909404601f8101839004830285018301909152808452908301828280156122d25780601f106122a7576101008083540402835291602001916122d2565b820191906000526020600020905b8154815290600101906020018083116122b557829003601f168201915b50505050505b97506122e38b6134f1565b90506122f681600063ffffffff6134aa16565b955061230981600163ffffffff6134aa16565b945061231c81600263ffffffff6134aa16565b935061232f81600363ffffffff6134aa16565b9250505092959891949750929550565b6000612349615cb1565b612351615cb1565b612359615cb1565b6000806000806000612369610ff0565b15156123bf576040805160e560020a62461bcd02815260206004820152601860248201527f434f4e54524143545f4e4f545f494e495449414c495a45440000000000000000604482015290519081900360640190fd5b6123c96000613edb565b6123d48c8c8c613b3b565b6123dc612b96565b9850602060405190810160405280600081525095505b8882101561254757612403826134f1565b975061241688600063ffffffff6134aa16565b945061242988600263ffffffff6134aa16565b935061243c88600363ffffffff6134aa16565b60008381526020819052604090205490935060ff16151561245e575081612474565b6124718461246c8588614633565b6134db565b90505b8481146124bc5761248d8860008363ffffffff61312b16565b612497828961402c565b6040805182815290518391600080516020615db2833981519152919081900360200190a25b6124c5826130ff565b96506124d98760028363ffffffff61312b16565b6124e382886131b2565b6124f58660008363ffffffff61464216565b6125078660038563ffffffff61464216565b61252a600161251c8a8263ffffffff6134aa16565b88919063ffffffff61464216565b61253c8660028663ffffffff61464216565b8160010191506123f2565b61255086614666565b612558613242565b505050505050505050505050565b6000806000612573615cb1565b61257b61466c565b905061258e81600163ffffffff6134aa16565b93506125a181600363ffffffff6134aa16565b92506125b883611f7883600063ffffffff6134aa16565b915050909192565b60008080808080806125df600080516020615d9283398151915261306a565b6125e98a89614688565b96506125f3612b96565b95506024600435019250602480350191505b86811015612644576008810283013560c01c94506010810282013560801c93506001016126338686106130a8565b61263f85856000614702565b612605565b61264c613242565b5050505050505050505050565b6000808080808080612678600080516020615d9283398151915261306a565b6126828a89614688565b965061268c612b96565b95506024600435019250602480350191505b86811015612644576008810283013560c01c94506010810282013560801c93506001016126cc8686106130a8565b6126d685856148bd565b61269e565b60008060006126e984611c92565b60408051808201909152601281527f5245434f5645525f444953414c4c4f5745440000000000000000000000000000602082015290151561276f5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b50612778611335565b925061278383614a0d565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156128095760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b50600160a060020a038416151561285a5760405130319250600160a060020a0384169083156108fc029084906000818181858888f19350505050158015612854573d6000803e3d6000fd5b50612919565b5082612875600160a060020a0382163063ffffffff614a3316565b9150612891600160a060020a038216848463ffffffff614b4816565b60408051808201909152601d81527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c454400000060208201529015156129175760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b505b83600160a060020a031683600160a060020a03167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b600080612975610ff0565b15156129845760009150612aaf565b61298c612ec9565b9050600160a060020a03811615156129a75760009150612aaf565b80600160a060020a031663fdef91068630876129c288614bd3565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b83811015612a31578181015183820152602001612a19565b50505050905090810190601f168015612a5e5780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015612a8057600080fd5b505af1158015612a94573d6000803e3d6000fd5b505050506040513d6020811015612aaa57600080fd5b505191505b509392505050565b612ac082613058565b612ad7600080516020615d9283398151915261306a565b61192e8282614bdd565b600080612aec612ec9565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b15801561123f57600080fd5b60006111887fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e8613435565b61154a8383612bd1576000612bd4565b60015b60ff168361101a565b612be682613058565b612c237f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d794754612c1e8467ffffffffffffffff8516614cfe565b614d59565b612c2f611b7b8361154f565b612c45828267ffffffffffffffff166001614d67565b61192e613242565b600080600080600080600080612c61615cb1565b612c69615cb1565b612c728b613058565b612c7b8b6130ff565b9150612c868b613439565b9050612c9982600063ffffffff6134aa16565b9950612cac82600163ffffffff6134aa16565b9850612cbf81600063ffffffff6134aa16565b9750612cd281600163ffffffff6134aa16565b9650612ce581600263ffffffff6134aa16565b9550612cf08b614e80565b8095508196508297505050505050919395975091939597565b60608060006060612d1c86866001611441565b8051929650909450915081906000908110612d3357fe5b906020019060200201519150509250925092565b60ff81565b6000808080808080612d6b600080516020615d9283398151915261306a565b612d758a89614688565b9650612d7f612b96565b95506024600435019250602480350191505b86811015612644576008810283013560c01c94506010810282013560801c9350600101612dbf8686106130a8565b612dcb85856000614d67565b612d91565b60608060008180612dee600080516020615d9283398151915261306a565b871515612e14576040805160008082526020820190815281830190925295509350612e93565b612e1d88614ea0565b91945092509050878314612e7b576040805160e560020a62461bcd02815260206004820152601c60248201527f494e56414c49445f414c4c4f43415445445f4b4559535f434f554e5400000000604482015290519081900360640190fd5b612e86838383615199565b9095509350612e93613242565b505050935093915050565b60006111887fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e613435565b60006111887f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b613435565b60006111887ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d03537613435565b7f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d79475481565b6000612f4d615cb1565b612f5683613058565b612f5f836134f1565b9050611b3b81600263ffffffff6134aa16565b6000600019612f7f611f0a565b14905090565b6301e1338081565b612fa4600080516020615d9283398151915261306a565b611aaa600161411f565b60c881565b612fbc83613058565b612fd3600080516020615d9283398151915261306a565b612fdd83826148bd565b612fe983836001614702565b61154a613242565b7f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee81565b600061301f615cb1565b61302883613439565b905061303381613465565b158015611b3b575061304c81600263ffffffff6134aa16565b159392505050565b4390565b611a37613063612b96565b82106130a8565b611a376130a33383600060405190808252806020026020018201604052801561309d578160200160208202803883390190505b5061296a565b615375565b801515611a37576040805160e560020a62461bcd02815260206004820152600c60248201527f4f55545f4f465f52414e47450000000000000000000000000000000000000000604482015290519081900360640190fd5b613107615cb1565b50600090815260208181526040918290208251918201909252600490910154815290565b67ffffffffffffffff81111561318b576040805160e560020a62461bcd02815260206004820152600f60248201527f5041434b45445f4f564552464c4f570000000000000000000000000000000000604482015290519081900360640190fd5b825167ffffffffffffffff91821660409390930260ff1692831b9190921b19909116179052565b6000918252602082905260409091209051600490910155565b6000806131d6615cb1565b60006131e1856153cc565b93509350838314156131f257611c8b565b6131fa61466c565b915061320683856154c0565b905083831115613227576132228260008363ffffffff61464216565b613239565b6132398260008363ffffffff6154d716565b611c8b82614666565b600061326d7fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e613435565b60010190506132a27fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e8263ffffffff61402816565b6040805182815290517ffb992daec9d46d64898e3a9336d02811349df6cbea8b95d4deb2fa6c7b454f0d9181900360200190a16040805182815290517f7220970e1f1f12864ecccd8942690a837c7a8dd45d158cb891eb45a8a69134aa9181900360200190a150565b613313615cb1565b600061331d615cb1565b61332687613058565b61333033886154ea565b61334f861580159061334a575067ffffffffffffffff8711155b6130a8565b613358876134f1565b925061336b83600263ffffffff6134aa16565b915061338967ffffffffffffffff611489848963ffffffff61351d16565b6133ab600080516020615dd2833981519152888489898963ffffffff61555716565b60408051828152905191935088917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f09181900360200190a26133f58360028463ffffffff61312b16565b6133ff878461402c565b61340761466c565b905061341b8160028863ffffffff61464216565b61342481614666565b61342c613242565b50505050505050565b5490565b613441615cb1565b50600090815260208181526040918290208251918201909252600390910154815290565b6000613477828263ffffffff6134aa16565b61348883600163ffffffff6134aa16565b10806134a457506134a082600263ffffffff6134aa16565b4211155b92915050565b905167ffffffffffffffff604090920260ff161c1690565b6000918252602082905260409091209051600390910155565b60008183106134ea5781611b3b565b5090919050565b6134f9615cb1565b50600090815260208181526040918290208251918201909252600290910154815290565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f57000000000000000000000000000000602082015260009083830190848210156135ab5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b508091505b5092915050565b6060806135cb83603063ffffffff6138ed16565b6040519080825280601f01601f1916602001820160405280156135f8578160200160208202803883390190505b5061360a84606063ffffffff6138ed16565b6040519080825280601f01601f191660200182016040528015613637578160200160208202803883390190505b509092509050915091565b6000805b858110156136ae57613661898989840163ffffffff61580a16565b60018082015460801c85840160308181028a019081019290925283546020928301526002840154606091820289019283015260038401546040830152600484015491015290925001613646565b505050505050505050565b6136c1615cb1565b6000806136cc615cb1565b6136d587613058565b6136df33886154ea565b8415156136eb5761342c565b6136f4876134f1565b935061370784600263ffffffff6134aa16565b925061373861371d85600363ffffffff6134aa16565b871015801561334a575083611489888863ffffffff61351d16565b613759600080516020615dd28339815191528888888763ffffffff61589d16565b925061376d8460028563ffffffff61312b16565b60408051848152905188917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a26137b484600063ffffffff6134aa16565b9150818610156137f5576137d08460008863ffffffff61312b16565b6040805187815290518891600080516020615db2833981519152919081900360200190a25b6137ff878561402c565b61380761466c565b905061381b8160028763ffffffff6154d716565b61382481614666565b613424876131cb565b60008151118015613840575060ff815111155b1515611a37576040805160e560020a62461bcd02815260206004820152601160248201527f57524f4e475f4e414d455f4c454e475448000000000000000000000000000000604482015290519081900360640190fd5b801515611a37576040805160e560020a62461bcd02815260206004820152601160248201527f56414c55455f49535f5448455f53414d45000000000000000000000000000000604482015290519081900360640190fd5b60008083151561390057600091506135b0565b5082820282848281151561391057fe5b60408051808201909152601181527f4d4154485f4d554c5f4f564552464c4f57000000000000000000000000000000602082015292919004146135ab5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b6000806000806139a6615cb1565b60006139b0615cb1565b6139cd888a1115801561334a57506139c6612b96565b89106130a8565b8891505b878211613b05576139e1826134f1565b92506139f483600263ffffffff6134aa16565b9450613a0783600363ffffffff6134aa16565b935083851415613a1657613afa565b838511613a1f57fe5b838503965094860194613a3a8360028663ffffffff61312b16565b613a4c8360008663ffffffff61312b16565b613a56828461402c565b613a5f826131cb565b60408051858152905183917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a26040805185815290518391600080516020615db2833981519152919081900360200190a26040805167ffffffffffffffff89168152905183917f9824694569ba758f8872bb150515caaf8f1e2cc27e6805679c4ac8c3b9b83d87919081900360200190a25b8160010191506139d1565b60008611156136ae57613b1661466c565b9050613b2a8160028863ffffffff6154d716565b613b3381614666565b6136ae613242565b613b4483615aa6565b613b747ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d035378463ffffffff61402816565b613ba47fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d08363ffffffff61402816565b613bae6002615b06565b613bb781613e65565b613bbf612ef4565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613bf957600080fd5b505af1158015613c0d573d6000803e3d6000fd5b505050506040513d6020811015613c2357600080fd5b5051600160a060020a031663095ea7b3613c3b612ef4565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613c7557600080fd5b505af1158015613c89573d6000803e3d6000fd5b505050506040513d6020811015613c9f57600080fd5b50516040805163ffffffff841660e01b8152600160a060020a03909216600483015260001960248301525160448083019260209291908290030181600087803b158015613ceb57600080fd5b505af1158015613cff573d6000803e3d6000fd5b505050506040513d6020811015613d1557600080fd5b505060408051600160a060020a038516815290517fa44aa4b7320163340e971b1f22f153bbb8a0151d783bd58377018ea5bc96d0c99181900360200190a16040805183815290517fdb042010b15d1321c99552200b350bba0a95dfa3d0b43869983ce74b44d644ee9181900360200190a1505050565b613d956003615b06565b611aaa600261411f565b613da7611f0a565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015613e2c5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b50611aaa613e38613054565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61402816565b613e756301e133808211156130a8565b613ea57f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e8263ffffffff61402816565b6040805182815290517f4cccd9748bff0341d9852cc61d82652a3003dcebea088f05388c0be1f26b4c8a9181900360200190a150565b613ee3611edf565b8114611a37576040805160e560020a62461bcd02815260206004820152601b60248201527f554e45585045435445445f434f4e54524143545f56455253494f4e0000000000604482015290519081900360640190fd5b5490565b801515611a37576040805160e560020a62461bcd02815260206004820152601b60248201527f57524f4e475f4f50455241544f525f4143544956455f53544154450000000000604482015290519081900360640190fd5b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f57000000000000000000000000000060208201526000908190848411156140205760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b505050900390565b9055565b6000918252602082905260409091209051600290910155565b61404e81615aa6565b614056612ef4565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561409057600080fd5b505af11580156140a4573d6000803e3d6000fd5b505050506040513d60208110156140ba57600080fd5b5051600160a060020a0382811691161415611a37576040805160e560020a62461bcd02815260206004820152601360248201527f4c49444f5f5245574152445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b61415b81600281111561412e57fe5b7f4ddbb0dcdc5f7692e494c15a7fca1f9eb65f31da0b5ce1c3381f6a1a1fd579b69063ffffffff61402816565b7f7545d380f29a8ae65fafb1acdf2c7762ec02d5607fecbea9dd8d8245e1616d93816040518082600281111561418d57fe5b60ff16815260200191505060405180910390a150565b600080600060608060606000806141b8612ef4565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156141f257600080fd5b505af1158015614206573d6000803e3d6000fd5b505050506040513d602081101561421c57600080fd5b5051604080517ff5eb42dc0000000000000000000000000000000000000000000000000000000081523060048201529051919850600160a060020a0389169163f5eb42dc916024808201926020929091908290030181600087803b15801561428357600080fd5b505af1158015614297573d6000803e3d6000fd5b505050506040513d60208110156142ad57600080fd5b505195508515156142bd57614629565b6142c6866116dc565b9450945094505b845181101561453057600284828151811015156142e657fe5b9060200190602002015110156142fb57614528565b828181518110151561430957fe5b90602001906020020151156143d3576001848281518110151561432857fe5b602090810290910101805190911c905283516143619085908390811061434a57fe5b60209081029091010151839063ffffffff61351d16565b9150848181518110151561437157fe5b90602001906020020151600160a060020a03167fe915a473fc2ef8e0231da98380f853b2aeea117a4392c67e753c54186bfbbd1285838151811015156143b357fe5b906020019060200201516040518082815260200191505060405180910390a25b86600160a060020a0316638fcb4e5b86838151811015156143f057fe5b90602001906020020151868481518110151561440857fe5b906020019060200201516040518363ffffffff1660e01b81526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b15801561446157600080fd5b505af1158015614475573d6000803e3d6000fd5b505050506040513d602081101561448b57600080fd5b505083516144b69085908390811061449f57fe5b60209081029091010151899063ffffffff61351d16565b975084818151811015156144c657fe5b90602001906020020151600160a060020a03167fdf29796aad820e4bb192f3a8d631b76519bcd2cbe77cc85af20e9df53cece086858381518110151561450857fe5b906020019060200201516040518082815260200191505060405180910390a25b6001016142cd565b600082111561462957614541612ef4565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561457b57600080fd5b505af115801561458f573d6000803e3d6000fd5b505050506040513d60208110156145a557600080fd5b5051604080517f46114928000000000000000000000000000000000000000000000000000000008152306004820152602481018590529051600160a060020a039092169163461149289160448082019260009290919082900301818387803b15801561461057600080fd5b505af1158015614624573d6000803e3d6000fd5b505050505b5050505050505090565b60008183116134ea5781611b3b565b61154a83836146618461465588886134aa565b9063ffffffff61351d16565b61312b565b51600155565b614674615cb1565b506040805160208101909152600154815290565b60088204601082048114801561469f575060088306155b80156146ac575060108206155b15156134a4576040805160e560020a62461bcd02815260206004820152601360248201527f494e56414c49445f5245504f52545f4441544100000000000000000000000000604482015290519081900360640190fd5b61470a615cb1565b6000806000614717615cb1565b6000614722896134f1565b955061473586600163ffffffff6134aa16565b945084881415614744576136ae565b868061474f57508488115b15156147cb576040805160e560020a62461bcd02815260206004820152602160248201527f4558495445445f56414c494441544f52535f434f554e545f444543524541534560448201527f4400000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6147dc86600363ffffffff6134aa16565b93506147f860006147ec8b613439565b9063ffffffff6134aa16565b92508284101561480457fe5b6148128385038911156130a8565b6148248660018a63ffffffff61312b16565b61482e898761402c565b6040805189815290518a917f0f67960648751434ae86bf350db61194f387fda387e7f568b0ccd0ae0c220166919081900360200190a261486c61466c565b915061487888866154c0565b905084881115614899576148948260018363ffffffff61464216565b6148ab565b6148ab8260018363ffffffff6154d716565b6148b482614666565b6136ae896131cb565b6148c5615cb1565b60006148cf615cb1565b60008060006148dd88613439565b95506148f086600063ffffffff6134aa16565b9450848714156148ff57614a03565b614908886134f1565b935061491b84600163ffffffff6134aa16565b925061492e84600363ffffffff6134aa16565b91508282101561493a57fe5b6149488383038811156130a8565b61495986600163ffffffff6134aa16565b905080871115801561496a57508085115b1561498c5761498c600261497c611aac565b889190420163ffffffff61312b16565b61499e8660008963ffffffff61312b16565b6149a888876134c2565b877f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb88836149dd8a600263ffffffff6134aa16565b60408051938452602084019290925282820152519081900360600190a2614a03886131cb565b5050505050505050565b600080600160a060020a0383161515614a29576000915061132f565b50506000903b1190565b60408051600160a060020a0383166024808301919091528251808303909101815260449091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790526000908180614ab38684615b6c565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f52455645525445440000000060208201529193509150821515614b3e5760405160e560020a62461bcd028152600401808060200182810382528381815181526020019150805190602001908083836000838110156119c05781810151838201526020016119a8565b5095945050505050565b60408051600160a060020a038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600090614bca8582615b9d565b95945050505050565b8051602002815290565b614be5615cb1565b6000614bef615cb1565b6000614bfa86613439565b9350614c0d84600163ffffffff6134aa16565b925082851415614c1c57611155565b614c25866134f1565b9150614c43614c3b83600363ffffffff6134aa16565b8611156130a8565b614c5484600063ffffffff6134aa16565b9050808510158015614c6557508083105b15614c8757614c876002614c77611aac565b869190420163ffffffff61312b16565b614c998460018763ffffffff61312b16565b614ca386856134c2565b857f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb8287614cd888600263ffffffff6134aa16565b60408051938452602084019290925282820152519081900360600190a2611155866131cb565b604080516002808252606080830184529260208301908038833901905050905082816000815181101515614d2e57fe5b602090810290910101528051829082906001908110614d4957fe5b6020908102909101015292915050565b61192e6130a333848461296a565b614d6f615cb1565b600080600080614d7e886134f1565b9450614d9185600063ffffffff6134aa16565b9350614da485600363ffffffff6134aa16565b9250614db785600263ffffffff6134aa16565b9150614dc78261246c8986614633565b905083811415614dd657614a03565b8580614de157508381105b1515614e37576040805160e560020a62461bcd02815260206004820152601b60248201527f5645545445445f4b4559535f434f554e545f494e435245415345440000000000604482015290519081900360640190fd5b614e498560008363ffffffff61312b16565b614e53888661402c565b6040805182815290518991600080516020615db2833981519152919081900360200190a2614a03886131cb565b600080600080614e8f85615beb565b919790965090869003945092505050565b600060608060006060600080600080600080614eba611cd5565b975087604051908082528060200260200182016040528015614ee6578160200160208202803883390190505b50995087604051908082528060200260200182016040528015614f13578160200160208202803883390190505b50985087604051908082528060200260200182016040528015614f40578160200160208202803883390190505b509650614f4b612b96565b94505b84811015614fd257614f5f81615beb565b95509350915082841415614f7257614fca565b808a87815181101515614f8157fe5b602090810290910101528851828403908a9088908110614f9d57fe5b60209081029091010152865182850390889088908110614fb957fe5b602090810290910101526001909501945b600101614f4e565b851515614ffa57604080516000808252602082018181528284019093529c509a50985061518a565b8786101561500c57858a528589528587525b73f95a8103e6d83b4437ad20454f86a75ecf1e32ef632529fbc98a898f6040518463ffffffff1660e01b8152600401808060200180602001848152602001838103835286818151815260200191508051906020019060200280838360005b8381101561508257818101518382015260200161506a565b50505050905001838103825285818151815260200191508051906020019060200280838360005b838110156150c15781810151838201526020016150a9565b505050509050019550505050505060006040518083038186803b1580156150e757600080fd5b505af41580156150fb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604090815281101561512457600080fd5b81516020830180519193928301929164010000000081111561514557600080fd5b8201602081018481111561515857600080fd5b815185602082028301116401000000008211171561517557600080fd5b50949f509c505050508b8d1015905061518a57fe5b50505050505050509193909250565b6060806000806000806151aa615cb1565b60006151b4615cb1565b6151bd8c6135b7565b9099509750600096505b8a51821015615338576151f08b838151811015156151e157fe5b906020019060200201516134f1565b925061520383600363ffffffff6134aa16565b9550898281518110151561521357fe5b6020908102909101015161522e84600163ffffffff6134aa16565b0194508585141561523e5761532d565b85851161524757fe5b85850393506152878b8381518110151561525d57fe5b60209081029091010151600080516020615dd28339815191529088878d8d8d63ffffffff61364216565b8a51968401968b908390811061529957fe5b906020019060200201517f24eb1c9e765ba41accf9437300ea91ece5ed3f897ec3cdee0e9debd7fe309b78866040518082815260200191505060405180910390a26152ec8360038763ffffffff61312b16565b61530d8b838151811015156152fd57fe5b906020019060200201518461402c565b61532d8b8381518110151561531e57fe5b906020019060200201516131cb565b8160010191506151c7565b868c1461534157fe5b61534961466c565b905061535d8160038963ffffffff61464216565b61536681614666565b50505050505050935093915050565b801515611a37576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b6000806153d7615cb1565b6153df615cb1565b60006153ea866134f1565b92506153f5866130ff565b915061540883600363ffffffff6134aa16565b905061541b83600063ffffffff6134aa16565b935061542686613015565b151561543457809350615482565b61544582600063ffffffff6134aa16565b156154825761547f8161547a8661546386600163ffffffff6134aa16565b61547488600163ffffffff6134aa16565b016134db565b614633565b93505b61549382600263ffffffff6134aa16565b94508385146154b8576154ae8260028663ffffffff61312b16565b6154b886836131b2565b505050915091565b60008183116154d157828203611b3b565b50900390565b61154a838361466184611f7888886134aa565b6000818152602081905260409020546101008104600160a060020a03908116908416149060ff166110e682801561551e5750815b806130a357506130a3857f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee61555287615c70565b61296a565b6000806000606060008088118015615586575067ffffffffffffffff6155838a8a63ffffffff61351d16565b11155b15156155dc576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b6155ed88603063ffffffff6138ed16565b875114801561560c575061560888606063ffffffff6138ed16565b8651145b1515615662576040805160e560020a62461bcd02815260206004820152600f60248201527f4c454e4754485f4d49534d415443480000000000000000000000000000000000604482015290519081900360640190fd5b604080516030808252606082019092529060208201610600803883390190505091505b878110156157fb5761569e8b8b8b63ffffffff61580a16565b60308281028901602081810151918301519286018390528501819052919550171592508215615717576040805160e560020a62461bcd02815260206004820152600960248201527f454d5054595f4b45590000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60208201518455603082015160801b600185015560608102602087010180516002860155602081015160038601556040810151600486015560018201915060018a01995050897fc77a17d6b857abe6d6e6c37301621bc72c4dd52fa8830fb54dfa715c04911a89836040518080602001828103825283818151815260200191508051906020019080838360005b838110156157bc5781810151838201526020016157a4565b50505050905090810190601f1680156157e95780820380516001836020036101000a031916815260200191505b509250505060405180910390a2615685565b50969998505050505050505050565b6040805160208082018690528183018590526060808301859052835180840390910181526080909201928390528151600093918291908401908083835b602083106158665780518252601f199092019160209182019101615847565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912060001c979650505050505050565b6000806000806060600080881180156158c55750866158c28a8a63ffffffff61351d16565b11155b80156158d9575067ffffffffffffffff8711155b151561592f576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b60408051603080825260608201909252906020820161060080388339019050509150508787015b88811115615a97576159738b8b600019840163ffffffff61580a16565b9450600185015460801c603083015284546020830152868110156159cd576159a68b8b6000198a0163ffffffff61580a16565b9350600092505b60058310156159c95782840154838601556001830192506159ad565b8394505b600092505b60058310156159ec576000838601556001830192506159d2565b600187039650600181039050897fea4b75aaf57196f73d338cadf79ecd0a437902e2dd0d2c4c2cf3ea71b8ab27b9836040518080602001828103825283818151815260200191508051906020019080838360005b83811015615a58578181015183820152602001615a40565b50505050905090810190601f168015615a855780820380516001836020036101000a031916815260200191505b509250505060405180910390a2615956565b50949998505050505050505050565b600160a060020a0381161515611a37576040805160e560020a62461bcd02815260206004820152600c60248201527f5a45524f5f414444524553530000000000000000000000000000000000000000604482015290519081900360640190fd5b615b367f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a68263ffffffff61402816565b6040805182815290517ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9181900360200190a150565b6000806000806040516020818751602089018a5afa92506000831115615b9157805191505b50909590945092505050565b6000806040516020818551602087016000895af16000811115615be1573d8015615bce5760208114615bd757615bdf565b60019350615bdf565b600183511493505b505b5090949350505050565b6000806000615bf8615cb1565b615c00615cb1565b615c09866134f1565b9150615c14866130ff565b9050615c2782600163ffffffff6134aa16565b9450615c3a82600363ffffffff6134aa16565b9350615c4d81600263ffffffff6134aa16565b9250838310158015615c5f5750848410155b1515615c6757fe5b50509193909250565b6040805160018082528183019092526060916020808301908038833901905050905081816000815181101515615ca257fe5b60209081029091010152919050565b60408051602081019091526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615d045782800160ff19823516178555615d31565b82800160010185558215615d31579182015b82811115615d31578235825591602001919060010190615d16565b506110169261118b9250905b808211156110165760008155600101615d3d560078523850fdd761612f46e844cf5a16bda6b3151d6ae961fd7e8e7b92bfbca7f86f5220989faafdc182d508d697678366f4e831f5f56166ad69bfc253fc548fb1bb75b874360e0bfd87f964eadd8276d8efb7c942134fc329b513032d0803e0c6947f955eec7e1f626bee3afd2aa47b5de04ddcdd3fe78dc8838213015ef58dfdeb2b7ad4d8ce5610cfb46470f03b14c197c2b751077c70209c5d0139f7c79ee9a165627a7a7230582056b92d7c3e0e09c29ea3f9bce7fe95586d6bce0361dab7e92936681de9c569480029
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.