Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- NodeOperatorsRegistry
- Optimization enabled
- true
- Compiler version
- v0.4.24+commit.e67f0147
- Optimization runs
- 200
- EVM Version
- constantinople
- Verified at
- 2024-11-06T09:29:37.640498Z
contracts/0.4.24/nos/NodeOperatorsRegistry.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// 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 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);
event NodeOperatorPenalized(address indexed recipientAddress, uint256 sharesPenalizedAmount);
//
// 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 Flag enable/disable limiting target active validators count for operator
uint8 internal constant IS_TARGET_LIMIT_ACTIVE_OFFSET = 0;
/// @dev relative target active validators limit for operator, set by DAO
/// @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;
//
// 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);
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);
}
/// @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));
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;
}
signingKeysStats.set(TOTAL_VETTED_KEYS_COUNT_OFFSET, vettedSigningKeysCountAfter);
_saveOperatorSigningKeysStats(_nodeOperatorId, signingKeysStats);
emit VettedSigningKeysCountChanged(_nodeOperatorId, vettedSigningKeysCountAfter);
_updateSummaryMaxValidatorsCount(_nodeOperatorId);
_increaseValidatorsKeysNonce();
}
/// @notice Called by StakingRouter to signal that stETH rewards were minted for this module.
function onRewardsMinted(uint256 /* _totalShares */) external view {
_auth(STAKING_ROUTER_ROLE);
// since we're pushing rewards to operators after exited validators counts are
// updated (as opposed to pulling by node ops), we don't need any handling here
// see `onExitedAndStuckValidatorsCountsUpdated()`
}
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 Called by StakingRouter after it finishes updating exited and stuck validators
/// counts for this module's node operators.
///
/// Guaranteed to be called after an oracle report is applied, regardless of whether any node
/// operator in this module has actually received any updated counts as a result of the report
/// but given that the total number of exited validators returned from getStakingModuleSummary
/// is the same as StakingRouter expects based on the total count received from the oracle.
function onExitedAndStuckValidatorsCountsUpdated() external {
_auth(STAKING_ROUTER_ROLE);
// for the permissioned module, we're distributing rewards within oracle operation
// since the number of node ops won't be high and thus gas costs are limited
_distributeRewards();
}
/// @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 _targetLimit Target limit of the node operator
/// @param _isTargetLimitActive active flag
function updateTargetValidatorsLimits(uint256 _nodeOperatorId, bool _isTargetLimitActive, uint256 _targetLimit) external {
_onlyExistedNodeOperator(_nodeOperatorId);
_auth(STAKING_ROUTER_ROLE);
_requireValidRange(_targetLimit <= UINT64_MAX);
Packed64x4.Packed memory operatorTargetStats = _loadOperatorTargetValidatorsStats(_nodeOperatorId);
operatorTargetStats.set(IS_TARGET_LIMIT_ACTIVE_OFFSET, _isTargetLimitActive ? 1 : 0);
operatorTargetStats.set(TARGET_VALIDATORS_COUNT_OFFSET, _isTargetLimitActive ? _targetLimit : 0);
_saveOperatorTargetValidatorsStats(_nodeOperatorId, operatorTargetStats);
emit TargetValidatorsCountChanged(_nodeOperatorId, _targetLimit);
_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(IS_TARGET_LIMIT_ACTIVE_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 =
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 (
bool isTargetLimitActive,
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);
isTargetLimitActive = operatorTargetStats.get(IS_TARGET_LIMIT_ACTIVE_OFFSET) != 0;
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 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");
}
}
@aragon/os/contracts/common/IVaultRecoverable.sol
/*
* 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);
}
@aragon/os/contracts/acl/ACLSyntaxSugar.sol
/*
* 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));
}
}
contracts/common/lib/MinFirstAllocationStrategy.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// 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
) internal pure returns (uint256 allocated) {
uint256 allocatedToBestCandidate = 0;
while (allocated < allocationSize) {
allocatedToBestCandidate = allocateToBestCandidate(buckets, capacities, allocationSize - allocated);
if (allocatedToBestCandidate == 0) {
break;
}
allocated += allocatedToBestCandidate;
}
}
/// @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;
}
}
@aragon/os/contracts/common/ConversionHelpers.sol
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)
}
}
}
@aragon/os/contracts/kernel/IKernel.sol
/*
* 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);
}
contracts/0.4.24/lib/Packed64x4.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// 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));
}
}
@aragon/os/contracts/acl/IACL.sol
/*
* 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);
}
@aragon/os/contracts/evmscript/IEVMScriptExecutor.sol
/*
* 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);
}
@aragon/os/contracts/apps/AragonApp.sol
/*
* 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
}
}
@aragon/os/contracts/apps/AppStorage.sol
/*
* 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);
}
}
@aragon/os/contracts/lib/math/SafeMath64.sol
// 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;
}
}
contracts/common/interfaces/ILidoLocator.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// 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
);
}
@aragon/os/contracts/common/Uint256Helpers.sol
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);
}
}
contracts/0.4.24/utils/Versioned.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// 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);
}
}
contracts/common/interfaces/IBurner.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// 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);
}
@aragon/os/contracts/common/ReentrancyGuard.sol
/*
* 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);
}
}
@aragon/os/contracts/common/TimeHelpers.sol
/*
* 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();
}
}
@aragon/os/contracts/evmscript/IEVMScriptRegistry.sol
/*
* 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);
}
@aragon/os/contracts/common/VaultRecoverable.sol
/*
* 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);
}
contracts/0.4.24/lib/SigningKeys.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// 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)));
}
}
contracts/common/lib/Math256.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// 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;
}
}
@aragon/os/contracts/lib/token/ERC20.sol
// 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
);
}
@aragon/os/contracts/common/SafeERC20.sol
// 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;
}
}
@aragon/os/contracts/common/UnstructuredStorage.sol
/*
* 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) }
}
}
@aragon/os/contracts/kernel/KernelConstants.sol
/*
* 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;
}
@aragon/os/contracts/common/IsContract.sol
/*
* 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;
}
}
@aragon/os/contracts/evmscript/EVMScriptRunner.sol
/*
* 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);
}
}
@aragon/os/contracts/common/EtherTokenConstant.sol
/*
* 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);
}
@aragon/os/contracts/common/Petrifiable.sol
/*
* 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);
}
}
@aragon/os/contracts/lib/math/SafeMath.sol
// 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;
}
}
@aragon/os/contracts/common/Initializable.sol
/*
* 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);
}
}
@aragon/os/contracts/common/Autopetrified.sol
/*
* 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();
}
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"constantinople"}
Contract ABI
[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"hasInitialized","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addSigningKeys","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint256","name":"_keysCount"},{"type":"bytes","name":"_publicKeys"},{"type":"bytes","name":"_signatures"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"getType","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getEVMScriptExecutor","inputs":[{"type":"bytes","name":"_script"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"clearNodeOperatorPenalty","inputs":[{"type":"uint256","name":"_nodeOperatorId"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getRecoveryVault","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":"nodeOperatorIds"}],"name":"getNodeOperatorIds","inputs":[{"type":"uint256","name":"_offset"},{"type":"uint256","name":"_limit"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":"pubkeys"},{"type":"bytes","name":"signatures"},{"type":"bool[]","name":"used"}],"name":"getSigningKeys","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint256","name":"_offset"},{"type":"uint256","name":"_limit"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeSigningKeysOperatorBH","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint256","name":"_fromIndex"},{"type":"uint256","name":"_keysCount"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"getNodeOperatorIsActive","inputs":[{"type":"uint256","name":"_nodeOperatorId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setNodeOperatorName","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"string","name":"_name"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":"recipients"},{"type":"uint256[]","name":"shares"},{"type":"bool[]","name":"penalized"}],"name":"getRewardsDistribution","inputs":[{"type":"uint256","name":"_totalRewardShares"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"invalidateReadyToDepositKeysRange","inputs":[{"type":"uint256","name":"_indexFrom"},{"type":"uint256","name":"_indexTo"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_locator"},{"type":"bytes32","name":"_type"},{"type":"uint256","name":"_stuckPenaltyDelay"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setStuckPenaltyDelay","inputs":[{"type":"uint256","name":"_delay"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getStuckPenaltyDelay","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeSigningKey","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint256","name":"_index"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeSigningKeys","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint256","name":"_fromIndex"},{"type":"uint256","name":"_keysCount"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isOperatorPenalized","inputs":[{"type":"uint256","name":"_nodeOperatorId"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"deactivateNodeOperator","inputs":[{"type":"uint256","name":"_nodeOperatorId"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"allowRecoverability","inputs":[{"type":"address","name":"token"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"STAKING_ROUTER_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addSigningKeysOperatorBH","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint256","name":"_keysCount"},{"type":"bytes","name":"_publicKeys"},{"type":"bytes","name":"_signatures"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"appId","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getActiveNodeOperatorsCount","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":"id"}],"name":"addNodeOperator","inputs":[{"type":"string","name":"_name"},{"type":"address","name":"_rewardAddress"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getContractVersion","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getInitializationBlock","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getUnusedSigningKeyCount","inputs":[{"type":"uint256","name":"_nodeOperatorId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[],"name":"onRewardsMinted","inputs":[{"type":"uint256","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"MANAGE_NODE_OPERATOR_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"onWithdrawalCredentialsChanged","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"activateNodeOperator","inputs":[{"type":"uint256","name":"_nodeOperatorId"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setNodeOperatorRewardAddress","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"address","name":"_rewardAddress"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"active"},{"type":"string","name":"name"},{"type":"address","name":"rewardAddress"},{"type":"uint64","name":"totalVettedValidators"},{"type":"uint64","name":"totalExitedValidators"},{"type":"uint64","name":"totalAddedValidators"},{"type":"uint64","name":"totalDepositedValidators"}],"name":"getNodeOperator","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"bool","name":"_fullInfo"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"finalizeUpgrade_v2","inputs":[{"type":"address","name":"_locator"},{"type":"bytes32","name":"_type"},{"type":"uint256","name":"_stuckPenaltyDelay"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"totalExitedValidators"},{"type":"uint256","name":"totalDepositedValidators"},{"type":"uint256","name":"depositableValidatorsCount"}],"name":"getStakingModuleSummary","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateExitedValidatorsCount","inputs":[{"type":"bytes","name":"_nodeOperatorIds"},{"type":"bytes","name":"_exitedValidatorsCounts"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateStuckValidatorsCount","inputs":[{"type":"bytes","name":"_nodeOperatorIds"},{"type":"bytes","name":"_stuckValidatorsCounts"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferToVault","inputs":[{"type":"address","name":"_token"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"canPerform","inputs":[{"type":"address","name":"_sender"},{"type":"bytes32","name":"_role"},{"type":"uint256[]","name":"_params"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateRefundedValidatorsCount","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint256","name":"_refundedValidatorsCount"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getEVMScriptRegistry","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getNodeOperatorsCount","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateTargetValidatorsLimits","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"bool","name":"_isTargetLimitActive"},{"type":"uint256","name":"_targetLimit"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setNodeOperatorStakingLimit","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint64","name":"_vettedSigningKeysCount"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"isTargetLimitActive"},{"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"}],"name":"getNodeOperatorSummary","inputs":[{"type":"uint256","name":"_nodeOperatorId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":"key"},{"type":"bytes","name":"depositSignature"},{"type":"bool","name":"used"}],"name":"getSigningKey","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint256","name":"_index"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"MAX_NODE_OPERATOR_NAME_LENGTH","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bytes","name":"publicKeys"},{"type":"bytes","name":"signatures"}],"name":"obtainDepositData","inputs":[{"type":"uint256","name":"_depositsCount"},{"type":"bytes","name":""}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getKeysOpIndex","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getNonce","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"kernel","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getLocator","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"SET_NODE_OPERATOR_LIMIT_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getTotalSigningKeyCount","inputs":[{"type":"uint256","name":"_nodeOperatorId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isPetrified","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"MAX_STUCK_PENALTY_DELAY","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"onExitedAndStuckValidatorsCountsUpdated","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"MAX_NODE_OPERATORS_COUNT","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeSigningKeyOperatorBH","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint256","name":"_index"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"unsafeUpdateValidatorsCount","inputs":[{"type":"uint256","name":"_nodeOperatorId"},{"type":"uint256","name":"_exitedValidatorsCount"},{"type":"uint256","name":"_stuckValidatorsCount"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"MANAGE_SIGNING_KEYS","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isOperatorPenaltyCleared","inputs":[{"type":"uint256","name":"_nodeOperatorId"}],"constant":true},{"type":"event","name":"NodeOperatorAdded","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":false},{"type":"string","name":"name","indexed":false},{"type":"address","name":"rewardAddress","indexed":false},{"type":"uint64","name":"stakingLimit","indexed":false}],"anonymous":false},{"type":"event","name":"NodeOperatorActiveSet","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":true},{"type":"bool","name":"active","indexed":false}],"anonymous":false},{"type":"event","name":"NodeOperatorNameSet","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":true},{"type":"string","name":"name","indexed":false}],"anonymous":false},{"type":"event","name":"NodeOperatorRewardAddressSet","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":true},{"type":"address","name":"rewardAddress","indexed":false}],"anonymous":false},{"type":"event","name":"NodeOperatorTotalKeysTrimmed","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":true},{"type":"uint64","name":"totalKeysTrimmed","indexed":false}],"anonymous":false},{"type":"event","name":"KeysOpIndexSet","inputs":[{"type":"uint256","name":"keysOpIndex","indexed":false}],"anonymous":false},{"type":"event","name":"StakingModuleTypeSet","inputs":[{"type":"bytes32","name":"moduleType","indexed":false}],"anonymous":false},{"type":"event","name":"RewardsDistributed","inputs":[{"type":"address","name":"rewardAddress","indexed":true},{"type":"uint256","name":"sharesAmount","indexed":false}],"anonymous":false},{"type":"event","name":"LocatorContractSet","inputs":[{"type":"address","name":"locatorAddress","indexed":false}],"anonymous":false},{"type":"event","name":"VettedSigningKeysCountChanged","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":true},{"type":"uint256","name":"approvedValidatorsCount","indexed":false}],"anonymous":false},{"type":"event","name":"DepositedSigningKeysCountChanged","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":true},{"type":"uint256","name":"depositedValidatorsCount","indexed":false}],"anonymous":false},{"type":"event","name":"ExitedSigningKeysCountChanged","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":true},{"type":"uint256","name":"exitedValidatorsCount","indexed":false}],"anonymous":false},{"type":"event","name":"TotalSigningKeysCountChanged","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":true},{"type":"uint256","name":"totalValidatorsCount","indexed":false}],"anonymous":false},{"type":"event","name":"NonceChanged","inputs":[{"type":"uint256","name":"nonce","indexed":false}],"anonymous":false},{"type":"event","name":"StuckPenaltyDelayChanged","inputs":[{"type":"uint256","name":"stuckPenaltyDelay","indexed":false}],"anonymous":false},{"type":"event","name":"StuckPenaltyStateChanged","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":true},{"type":"uint256","name":"stuckValidatorsCount","indexed":false},{"type":"uint256","name":"refundedValidatorsCount","indexed":false},{"type":"uint256","name":"stuckPenaltyEndTimestamp","indexed":false}],"anonymous":false},{"type":"event","name":"TargetValidatorsCountChanged","inputs":[{"type":"uint256","name":"nodeOperatorId","indexed":true},{"type":"uint256","name":"targetValidatorsCount","indexed":false}],"anonymous":false},{"type":"event","name":"NodeOperatorPenalized","inputs":[{"type":"address","name":"recipientAddress","indexed":true},{"type":"uint256","name":"sharesPenalizedAmount","indexed":false}],"anonymous":false},{"type":"event","name":"ContractVersionSet","inputs":[{"type":"uint256","name":"version","indexed":false}],"anonymous":false},{"type":"event","name":"ScriptResult","inputs":[{"type":"address","name":"executor","indexed":true},{"type":"bytes","name":"script","indexed":false},{"type":"bytes","name":"input","indexed":false},{"type":"bytes","name":"returnData","indexed":false}],"anonymous":false},{"type":"event","name":"RecoverToVault","inputs":[{"type":"address","name":"vault","indexed":true},{"type":"address","name":"token","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false}]
Contract Creation Code
0x6080604052620000146200005460201b60201c565b6200004e7f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a660001962000156602090811b62003d5617901c565b6200026b565b620000646200015a60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a454400000000000000006020820152901562000140576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101562000104578181015183820152602001620000ea565b50505050905090810190601f168015620001325780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50620001546000196200018d60201b60201c565b565b9055565b60006200018860008051602062005dc983398151915260001b600019166200026760201b62002f651760201c565b905090565b6200019d6200015a60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156200023c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101562000104578181015183820152602001620000ea565b506200026460008051602062005dc98339815191528262000156602090811b62003d5617901c565b50565b5490565b615b4e806200027b6000396000f3006080604052600436106102d95760003560e01c63ffffffff1680630803fac0146102de578063096b7b351461030757806315dae03e1461033d5780632914b9bd1461036457806330a90f01146103d957806332f0a3b5146103f15780634febc81b1461040657806359e25c12146104715780635ddde810146105ae5780635e2fb908146105cc5780635e57d742146105e457806362dcfda11461060857806365cc369a146106e5578063684560a2146107005780636ccc7562146107275780636da7d0a71461073f5780636ef355f1146107545780637038b141146105ae57806375049ad81461076f57806375a080d5146107875780637e7db6e11461079f57806380231f15146107c0578063805911ae1461030757806380afdea8146107d55780638469cbd3146107ea57806385fa63d7146107ff5780638aa104351461082d5780638b3dd749146108425780638ca7c052146108575780638d7e40171461086f5780638ece99951461088757806390c09bdb1461089c57806391dcd6b2146108b1578063973e9328146108c95780639a56983c146108ed5780639a7c2ade146109c95780639abddf09146109f05780639b00c14614610a235780639b3d190014610a4f5780639d4941d814610a7b578063a1658fad14610a9c578063a2e080f114610b03578063a479e50814610b1e578063a70c70e414610b33578063a9e7a84614610b48578063ae962acf14610b68578063b3076c3c14610b8d578063b449402a14610be8578063b497183314610cec578063bee41b5814610d01578063d07442f114610e03578063d087d28814610e03578063d4aae0c414610e18578063d8343dcb14610e2d578063d8e71cd114610e42578063db9887ea14610e57578063de4796ed14610e6f578063e204d09b14610e84578063e864299e14610e99578063ec5af3a414610eae578063ed5cfa4114610754578063f2e2ca6314610ec3578063f31bd9c114610ee1578063fbc77ef114610ef6575b600080fd5b3480156102ea57600080fd5b506102f3610f0e565b604080519115158252519081900360200190f35b34801561031357600080fd5b5061033b60048035906024803591604435808301929082013591606435918201910135610f38565b005b34801561034957600080fd5b50610352610fa9565b60408051918252519081900360200190f35b34801561037057600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526103bd943694929360249392840191908190840183828082843750949750610fda9650505050505050565b60408051600160a060020a039092168252519081900360200190f35b3480156103e557600080fd5b506102f36004356110bd565b3480156103fd57600080fd5b506103bd611181565b34801561041257600080fd5b506104216004356024356111f6565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561045d578181015183820152602001610445565b505050509050019250505060405180910390f35b34801561047d57600080fd5b5061048f60043560243560443561128d565b60405180806020018060200180602001848103845287818151815260200191508051906020019080838360005b838110156104d45781810151838201526020016104bc565b50505050905090810190601f1680156105015780820380516001836020036101000a031916815260200191505b50848103835286518152865160209182019188019080838360005b8381101561053457818101518382015260200161051c565b50505050905090810190601f1680156105615780820380516001836020036101000a031916815260200191505b508481038252855181528551602091820191808801910280838360005b8381101561059657818101518382015260200161057e565b50505050905001965050505050505060405180910390f35b3480156105ba57600080fd5b5061033b60043560243560443561138b565b3480156105d857600080fd5b506102f360043561139b565b3480156105f057600080fd5b5061033b6004803590602480359081019101356113b0565b34801561061457600080fd5b50610620600435611528565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b83811015610668578181015183820152602001610650565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156106a757818101518382015260200161068f565b50505050905001848103825285818151815260200191508051906020019060200280838360008381101561059657818101518382015260200161057e565b3480156106f157600080fd5b5061033b600435602435611759565b34801561070c57600080fd5b5061033b600160a060020a036004351660243560443561177e565b34801561073357600080fd5b5061033b60043561185b565b34801561074b57600080fd5b5061035261187e565b34801561076057600080fd5b5061033b6004356024356118a9565b34801561077b57600080fd5b506102f36004356118b5565b34801561079357600080fd5b5061033b6004356118da565b3480156107ab57600080fd5b506102f3600160a060020a0360043516611a2a565b3480156107cc57600080fd5b50610352611a30565b3480156107e157600080fd5b50610352611a42565b3480156107f657600080fd5b50610352611a6d565b34801561080b57600080fd5b506103526024600480358281019291013590600160a060020a03903516611a86565b34801561083957600080fd5b50610352611c60565b34801561084e57600080fd5b50610352611c8b565b34801561086357600080fd5b50610352600435611cb6565b34801561087b57600080fd5b5061033b600435611d05565b34801561089357600080fd5b50610352611d1c565b3480156108a857600080fd5b5061033b611d2e565b3480156108bd57600080fd5b5061033b600435611d68565b3480156108d557600080fd5b5061033b600435600160a060020a0360243516611e1b565b3480156108f957600080fd5b5061090a6004356024351515611ee7565b604080518815158152600160a060020a0387169181019190915267ffffffffffffffff8086166060830152848116608083015283811660a0830152821660c082015260e0602080830182815289519284019290925288516101008401918a019080838360005b83811015610988578181015183820152602001610970565b50505050905090810190601f1680156109b55780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b3480156109d557600080fd5b5061033b600160a060020a036004351660243560443561203a565b3480156109fc57600080fd5b50610a05612261565b60408051938452602084019290925282820152519081900360600190f35b348015610a2f57600080fd5b5061033b60246004803582810192908201359181359182019101356122bb565b348015610a5b57600080fd5b5061033b6024600480358281019290820135918135918201910135612354565b348015610a8757600080fd5b5061033b600160a060020a03600435166123d6565b348015610aa857600080fd5b5060408051602060046044358181013583810280860185019096528085526102f3958335600160a060020a03169560248035963696956064959394920192918291850190849080828437509497506126659650505050505050565b348015610b0f57600080fd5b5061033b6004356024356127b2565b348015610b2a57600080fd5b506103bd6127dc565b348015610b3f57600080fd5b50610352612891565b348015610b5457600080fd5b5061033b60043560243515156044356128bc565b348015610b7457600080fd5b5061033b60043567ffffffffffffffff602435166129a0565b348015610b9957600080fd5b50610ba5600435612ac5565b6040805198151589526020890197909752878701959095526060870193909352608086019190915260a085015260c084015260e083015251908190036101000190f35b348015610bf457600080fd5b50610c03600435602435612b83565b60405180806020018060200184151515158152602001838103835286818151815260200191508051906020019080838360005b83811015610c4e578181015183820152602001610c36565b50505050905090810190601f168015610c7b5780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b83811015610cae578181015183820152602001610c96565b50505050905090810190601f168015610cdb5780820380516001836020036101000a031916815260200191505b509550505050505060405180910390f35b348015610cf857600080fd5b50610352612bc1565b348015610d0d57600080fd5b50610d25600480359060248035908101910135612bc6565b604051808060200180602001838103835285818151815260200191508051906020019080838360005b83811015610d66578181015183820152602001610d4e565b50505050905090810190601f168015610d935780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015610dc6578181015183820152602001610dae565b50505050905090810190601f168015610df35780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b348015610e0f57600080fd5b50610352612c94565b348015610e2457600080fd5b506103bd612cbf565b348015610e3957600080fd5b506103bd612cea565b348015610e4e57600080fd5b50610352612d15565b348015610e6357600080fd5b50610352600435612d39565b348015610e7b57600080fd5b506102f3612d68565b348015610e9057600080fd5b50610352612d7b565b348015610ea557600080fd5b5061033b612d83565b348015610eba57600080fd5b50610352612da2565b348015610ecf57600080fd5b5061033b600435602435604435612da7565b348015610eed57600080fd5b50610352612de5565b348015610f0257600080fd5b506102f3600435612e09565b600080610f19611c8b565b90508015801590610f31575080610f2e612e48565b10155b91505b5090565b610fa1868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8c018190048102820181019092528a815294508a9350899250829150840183828082843750612e4c945050505050565b505050505050565b6000610fd47fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d0612f65565b90505b90565b6000610fe46127dc565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561103f578181015183820152602001611027565b50505050905090810190601f16801561106c5780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561108b57600080fd5b505af115801561109f573d6000803e3d6000fd5b505050506040513d60208110156110b557600080fd5b505192915050565b60006110c76159e2565b6110d083612f69565b90506110db81612f95565b1580156110f757506110f481600263ffffffff612fda16565b15155b151561114d576040805160e560020a62461bcd02815260206004820152601260248201527f43414e545f434c4541525f50454e414c54590000000000000000000000000000604482015290519081900360640190fd5b611160816002600063ffffffff612ff216565b61116a8382613079565b61117383613092565b61117b613109565b50919050565b600061118b612cbf565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156111c557600080fd5b505af11580156111d9573d6000803e3d6000fd5b505050506040513d60208110156111ef57600080fd5b5051905090565b6060600080611203612891565b91508185101580611212575083155b1561121c57611285565b611228848684036131d2565b604051908082528060200260200182016040528015611251578160200160208202803883390190505b509250600090505b825181101561128557808501838281518110151561127357fe5b60209081029091010152600101611259565b505092915050565b606080606061129a6159e2565b6000806112a6896131e8565b6112af896131fa565b92506112dc6112c584600263ffffffff612fda16565b6112d58a8a63ffffffff61322616565b11156132c0565b6112ed83600363ffffffff612fda16565b91506112f887613317565b604080518a81526020808c028201019091529197509550878015611326578160200160208202803883390190505b50935061134d600080516020615b038339815191528a8a8a8a8a600063ffffffff6133a216565b8681101561137f578181890110848281518110151561136857fe5b91151560209283029091019091015260010161134d565b50505093509350939050565b611396838383613419565b505050565b60009081526020819052604090205460ff1690565b6113e982828080601f0160208091040260200160405190810160405280939291908181526020018383808284375061358d945050505050565b6113f2836131e8565b611409600080516020615a838339815191526135f6565b6114b5828260405180838380828437820191505092505050604051809103902060001916600080868152602001908152602001600020600101604051808280546001816001161561010002031660029004801561149d5780601f1061147b57610100808354040283529182019161149d565b820191906000526020600020905b815481529060010190602001808311611489575b50509150506040518091039020600019161415613634565b60008381526020819052604090206114d19060010183836159f4565b50827fcb16868f4831cc58a28d413f658752a2958bd1f50e94ed6391716b936c48093b83836040518080602001828103825284848281815260200192508082843760405192018290039550909350505050a2505050565b606080606060008060008061153b6159e2565b600080600080611549612891565b9850611553611a6d565b97508760405190808252806020026020018201604052801561157f578160200160208202803883390190505b509b50876040519080825280602002602001820160405280156115ac578160200160208202803883390190505b509a50876040519080825280602002602001820160405280156115d9578160200160208202803883390190505b50995060009650600095505b888410156116da576115f68461139b565b1515611601576116cf565b61160a846131fa565b945061161d85600163ffffffff612fda16565b925061163085600363ffffffff612fda16565b91508282101561163c57fe5b506000838152602081905260409020548b5183830396870196916101009004600160a060020a0316908d908990811061167157fe5b600160a060020a039092166020928302909101909101528a5181908c908990811061169857fe5b602090810290910101526116ab846118b5565b8a888151811015156116b957fe5b9115156020928302909101909101526001909601955b8360010193506115e5565b8515156116e657611749565b600096505b87871015611749578561171c8e8d8a81518110151561170657fe5b602090810290910101519063ffffffff61368b16565b81151561172557fe5b048b8881518110151561173457fe5b602090810290910101526001909601956116eb565b5050505050505050509193909250565b611770600080516020615a838339815191526135f6565b61177a8282613736565b5050565b611786611c8b565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156118475760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561180c5781810151838201526020016117f4565b50505050905090810190601f1680156118395780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506118538383836138d9565b611396613b29565b611872600080516020615a838339815191526135f6565b61187b81613bf1565b50565b6000610fd47f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e612f65565b61177a82826001613419565b60006118bf6159e2565b6118c883612f69565b90506118d381612f95565b9392505050565b60006118e46159e2565b6000806118f0856131e8565b611907600080516020615a838339815191526135f6565b6119186119138661139b565b613c6b565b611920611a6d565b935061195161193685600163ffffffff613cc216565b600080516020615aa38339815191529063ffffffff613d5616565b600085815260208181526040808320805460ff1916905580519283525187927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a26119a2856131fa565b92506119b583600063ffffffff612fda16565b91506119c883600363ffffffff612fda16565b905080821115611a1b576119e48360008363ffffffff612ff216565b6119ee8584613d5a565b6040805182815290518691600080516020615ae3833981519152919081900360200190a2611a1b85613092565b611a23613109565b5050505050565b50600190565b600080516020615ac383398151915281565b6000610fd47fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b612f65565b6000610fd4600080516020615aa3833981519152612f65565b6000806000611ac486868080601f0160208091040260200160405190810160405280939291908181526020018383808284375061358d945050505050565b611acd84613d73565b611ad5612891565b925060c88310611b2f576040805160e560020a62461bcd02815260206004820152601c60248201527f4d41585f4f50455241544f52535f434f554e545f455843454544454400000000604482015290519081900360640190fd5b611b627fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e86001850163ffffffff613d5616565b60008381526020819052604090209150611b7a611a6d565b9050611b9d600080516020615aa38339815191526001830163ffffffff613d5616565b815460ff191660019081178355611bb790830187876159f4565b50815474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a03861690810291909117835560408051858152908101919091526000606082018190526080602083018181529083018890527fc52ec0ad7872dae440d886040390c13677df7bf3cca136d8d81e5e5e7dd62ff19286928a928a928a929160a0820186868082843760405192018290039850909650505050505050a150509392505050565b6000610fd47f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6612f65565b6000610fd47febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e612f65565b6000611cc06159e2565b611cc9836131e8565b611cd2836131fa565b90506118d3611ce882600363ffffffff612fda16565b611cf983600263ffffffff612fda16565b9063ffffffff613cc216565b61187b600080516020615ac38339815191526135f6565b600080516020615a8383398151915281565b6000611d47600080516020615ac38339815191526135f6565b611d4f612891565b9050600081111561187b5761187b600060018303613736565b611d71816131e8565b611d88600080516020615a838339815191526135f6565b611d9a611d948261139b565b15613c6b565b611dc3611da5611a6d565b600080516020615aa38339815191529060010163ffffffff613d5616565b60008181526020818152604091829020805460ff191660019081179091558251908152915183927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a261187b613109565b611e2481613d73565b611e2d826131e8565b611e44600080516020615a838339815191526135f6565b600082815260208190526040902054611e7090600160a060020a03838116610100909204161415613634565b60008281526020818152604091829020805474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a038616908102919091179091558251908152915184927f9a52205165d510fc1e428886d52108725dc01ed544da1702dc7bd3fdb3f243b292908290030190a25050565b60006060600080600080600080611efc6159e2565b611f058b6131e8565b60008b8152602081905260409020805460ff81169a506101009004600160a060020a03169750915089611f4657604080516020810190915260008152611fd3565b60018281018054604080516020600295841615610100026000190190931694909404601f810183900483028501830190915280845290830182828015611fcd5780601f10611fa257610100808354040283529160200191611fcd565b820191906000526020600020905b815481529060010190602001808311611fb057829003601f168201915b50505050505b9750611fde8b6131fa565b9050611ff181600063ffffffff612fda16565b955061200481600163ffffffff612fda16565b945061201781600263ffffffff612fda16565b935061202a81600363ffffffff612fda16565b9250505092959891949750929550565b60006120446159e2565b61204c6159e2565b6120546159e2565b6000806000806000612064610f0e565b15156120ba576040805160e560020a62461bcd02815260206004820152601860248201527f434f4e54524143545f4e4f545f494e495449414c495a45440000000000000000604482015290519081900360640190fd5b6120c46000613e4d565b6120cf8c8c8c6138d9565b6120d7612891565b9850602060405190810160405280600081525095505b88821015612242576120fe826131fa565b975061211188600063ffffffff612fda16565b945061212488600263ffffffff612fda16565b935061213788600363ffffffff612fda16565b60008381526020819052604090205490935060ff16151561215957508161216f565b61216c846121678588613eab565b6131d2565b90505b8481146121b7576121888860008363ffffffff612ff216565b6121928289613d5a565b6040805182815290518391600080516020615ae3833981519152919081900360200190a25b6121c082613eba565b96506121d48760028363ffffffff612ff216565b6121de8288613ee6565b6121f08660008363ffffffff613eff16565b6122028660038563ffffffff613eff16565b61222560016122178a8263ffffffff612fda16565b88919063ffffffff613eff16565b6122378660028663ffffffff613eff16565b8160010191506120ed565b61224b86613f23565b612253613109565b505050505050505050505050565b600080600061226e6159e2565b612276613f29565b905061228981600163ffffffff612fda16565b935061229c81600363ffffffff612fda16565b92506122b383611cf983600063ffffffff612fda16565b915050909192565b60008080808080806122da600080516020615ac38339815191526135f6565b6122e48a89613f45565b96506122ee612891565b95506024600435019250602480350191505b8681101561233f576008810283013560c01c94506010810282013560801c935060010161232e8686106132c0565b61233a85856000613fbf565b612300565b612347613109565b5050505050505050505050565b6000808080808080612373600080516020615ac38339815191526135f6565b61237d8a89613f45565b9650612387612891565b95506024600435019250602480350191505b8681101561233f576008810283013560c01c94506010810282013560801c93506001016123c78686106132c0565b6123d1858561417a565b612399565b60008060006123e484611a2a565b60408051808201909152601281527f5245434f5645525f444953414c4c4f5745440000000000000000000000000000602082015290151561246a5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b50612473611181565b925061247e836142ca565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156125045760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b50600160a060020a03841615156125555760405130319250600160a060020a0384169083156108fc029084906000818181858888f1935050505015801561254f573d6000803e3d6000fd5b50612614565b5082612570600160a060020a0382163063ffffffff6142f016565b915061258c600160a060020a038216848463ffffffff61440516565b60408051808201909152601d81527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c454400000060208201529015156126125760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b505b83600160a060020a031683600160a060020a03167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b600080612670610f0e565b151561267f57600091506127aa565b612687612cbf565b9050600160a060020a03811615156126a257600091506127aa565b80600160a060020a031663fdef91068630876126bd88614490565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b8381101561272c578181015183820152602001612714565b50505050905090810190601f1680156127595780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561277b57600080fd5b505af115801561278f573d6000803e3d6000fd5b505050506040513d60208110156127a557600080fd5b505191505b509392505050565b6127bb826131e8565b6127d2600080516020615ac38339815191526135f6565b61177a828261449a565b6000806127e7612cbf565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b15801561108b57600080fd5b6000610fd47fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e8612f65565b6128c46159e2565b6128cd846131e8565b6128e4600080516020615ac38339815191526135f6565b6128f867ffffffffffffffff8311156132c0565b61290184613eba565b9050612928600084612914576000612917565b60015b83919060ff1663ffffffff612ff216565b61294960018461293957600061293b565b835b83919063ffffffff612ff216565b6129538482613ee6565b60408051838152905185917fd50ea115db6f0b433ef9cc4b71110dbd9202364a00488be90718990be5bf16a6919081900360200190a261299284613092565b61299a613109565b50505050565b6129a86159e2565b6000806000806129b7876131e8565b6129f47f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d7947546129ef8967ffffffffffffffff8a166145bb565b614616565b612a006119138861139b565b612a09876131fa565b9450612a1c85600063ffffffff612fda16565b9350612a2f85600363ffffffff612fda16565b9250612a4285600263ffffffff612fda16565b9150612a5c826121678867ffffffffffffffff1686613eab565b905083811415612a6b57612abc565b612a7d8560008363ffffffff612ff216565b612a878786613d5a565b6040805182815290518891600080516020615ae3833981519152919081900360200190a2612ab487613092565b612abc613109565b50505050505050565b600080600080600080600080612ad96159e2565b612ae16159e2565b612aea8b6131e8565b612af38b613eba565b9150612afe8b612f69565b9050612b1182600063ffffffff612fda16565b15159950612b2682600163ffffffff612fda16565b9850612b3981600063ffffffff612fda16565b9750612b4c81600163ffffffff612fda16565b9650612b5f81600263ffffffff612fda16565b9550612b6a8b614624565b8095508196508297505050505050919395975091939597565b60608060006060612b968686600161128d565b8051929650909450915081906000908110612bad57fe5b906020019060200201519150509250925092565b60ff81565b60608060008180612be4600080516020615ac38339815191526135f6565b871515612c0a576040805160008082526020820190815281830190925295509350612c89565b612c1388614644565b91945092509050878314612c71576040805160e560020a62461bcd02815260206004820152601c60248201527f494e56414c49445f414c4c4f43415445445f4b4559535f434f554e5400000000604482015290519081900360640190fd5b612c7c8383836147d6565b9095509350612c89613109565b505050935093915050565b6000610fd47fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e612f65565b6000610fd47f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b612f65565b6000610fd47ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d03537612f65565b7f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d79475481565b6000612d436159e2565b612d4c836131e8565b612d55836131fa565b90506118d381600263ffffffff612fda16565b6000600019612d75611c8b565b14905090565b6301e1338081565b612d9a600080516020615ac38339815191526135f6565b61187b6149b2565b60c881565b612db0836131e8565b612dc7600080516020615ac38339815191526135f6565b612dd1838261417a565b612ddd83836001613fbf565b611396613109565b7f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee81565b6000612e136159e2565b612e1c83612f69565b9050612e2781612f95565b1580156118d35750612e4081600263ffffffff612fda16565b159392505050565b4390565b612e546159e2565b6000612e5e6159e2565b612e67876131e8565b612e713388614e42565b612e908615801590612e8b575067ffffffffffffffff8711155b6132c0565b612e99876131fa565b9250612eac83600263ffffffff612fda16565b9150612eca67ffffffffffffffff6112d5848963ffffffff61322616565b612eec600080516020615b03833981519152888489898963ffffffff614eaf16565b60408051828152905191935088917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f09181900360200190a2612f368360028463ffffffff612ff216565b612f408784613d5a565b612f48613f29565b9050612f5c8160028863ffffffff613eff16565b612ab481613f23565b5490565b612f716159e2565b50600090815260208181526040918290208251918201909252600390910154815290565b6000612fa7828263ffffffff612fda16565b612fb883600163ffffffff612fda16565b1080612fd45750612fd082600263ffffffff612fda16565b4211155b92915050565b905167ffffffffffffffff604090920260ff161c1690565b67ffffffffffffffff811115613052576040805160e560020a62461bcd02815260206004820152600f60248201527f5041434b45445f4f564552464c4f570000000000000000000000000000000000604482015290519081900360640190fd5b825167ffffffffffffffff91821660409390930260ff1692831b9190921b19909116179052565b6000918252602082905260409091209051600390910155565b60008061309d6159e2565b60006130a885615162565b93509350838314156130b957611a23565b6130c1613f29565b91506130cd8385615256565b9050838311156130ee576130e98260008363ffffffff613eff16565b613100565b6131008260008363ffffffff61526d16565b611a2382613f23565b60006131347fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e612f65565b60010190506131697fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e8263ffffffff613d5616565b6040805182815290517ffb992daec9d46d64898e3a9336d02811349df6cbea8b95d4deb2fa6c7b454f0d9181900360200190a16040805182815290517f7220970e1f1f12864ecccd8942690a837c7a8dd45d158cb891eb45a8a69134aa9181900360200190a150565b60008183106131e157816118d3565b5090919050565b61187b6131f3612891565b82106132c0565b6132026159e2565b50600090815260208181526040918290208251918201909252600290910154815290565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f57000000000000000000000000000000602082015260009083830190848210156132b45760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b508091505b5092915050565b80151561187b576040805160e560020a62461bcd02815260206004820152600c60248201527f4f55545f4f465f52414e47450000000000000000000000000000000000000000604482015290519081900360640190fd5b60608061332b83603063ffffffff61368b16565b6040519080825280601f01601f191660200182016040528015613358578160200160208202803883390190505b5061336a84606063ffffffff61368b16565b6040519080825280601f01601f191660200182016040528015613397578160200160208202803883390190505b509092509050915091565b6000805b8581101561340e576133c1898989840163ffffffff61528016565b60018082015460801c85840160308181028a0190810192909252835460209283015260028401546060918202890192830152600384015460408301526004840154910152909250016133a6565b505050505050505050565b6134216159e2565b60008061342c6159e2565b613435876131e8565b61343f3388614e42565b84151561344b57612abc565b613454876131fa565b935061346784600263ffffffff612fda16565b925061349861347d85600363ffffffff612fda16565b8710158015612e8b5750836112d5888863ffffffff61322616565b6134b9600080516020615b038339815191528888888763ffffffff61531316565b92506134cd8460028563ffffffff612ff216565b60408051848152905188917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a261351484600063ffffffff612fda16565b915081861015613555576135308460008863ffffffff612ff216565b6040805187815290518891600080516020615ae3833981519152919081900360200190a25b61355f8785613d5a565b613567613f29565b905061357b8160028763ffffffff61526d16565b61358481613f23565b612ab487613092565b600081511180156135a0575060ff815111155b151561187b576040805160e560020a62461bcd02815260206004820152601160248201527f57524f4e475f4e414d455f4c454e475448000000000000000000000000000000604482015290519081900360640190fd5b61187b61362f33836000604051908082528060200260200182016040528015613629578160200160208202803883390190505b50612665565b61551c565b80151561187b576040805160e560020a62461bcd02815260206004820152601160248201527f56414c55455f49535f5448455f53414d45000000000000000000000000000000604482015290519081900360640190fd5b60008083151561369e57600091506132b9565b508282028284828115156136ae57fe5b60408051808201909152601181527f4d4154485f4d554c5f4f564552464c4f57000000000000000000000000000000602082015292919004146132b45760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b6000806000806137446159e2565b600061374e6159e2565b61376b888a11158015612e8b5750613764612891565b89106132c0565b8891505b8782116138a35761377f826131fa565b925061379283600263ffffffff612fda16565b94506137a583600363ffffffff612fda16565b9350838514156137b457613898565b8385116137bd57fe5b8385039650948601946137d88360028663ffffffff612ff216565b6137ea8360008663ffffffff612ff216565b6137f48284613d5a565b6137fd82613092565b60408051858152905183917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a26040805185815290518391600080516020615ae3833981519152919081900360200190a26040805167ffffffffffffffff89168152905183917f9824694569ba758f8872bb150515caaf8f1e2cc27e6805679c4ac8c3b9b83d87919081900360200190a25b81600101915061376f565b600086111561340e576138b4613f29565b90506138c88160028863ffffffff61526d16565b6138d181613f23565b61340e613109565b6138e283615573565b6139127ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d035378463ffffffff613d5616565b6139427fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d08363ffffffff613d5616565b61394c60026155d3565b61395581613bf1565b61395d612cea565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561399757600080fd5b505af11580156139ab573d6000803e3d6000fd5b505050506040513d60208110156139c157600080fd5b5051600160a060020a031663095ea7b36139d9612cea565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613a1357600080fd5b505af1158015613a27573d6000803e3d6000fd5b505050506040513d6020811015613a3d57600080fd5b50516040805163ffffffff841660e01b8152600160a060020a03909216600483015260001960248301525160448083019260209291908290030181600087803b158015613a8957600080fd5b505af1158015613a9d573d6000803e3d6000fd5b505050506040513d6020811015613ab357600080fd5b505060408051600160a060020a038516815290517fa44aa4b7320163340e971b1f22f153bbb8a0151d783bd58377018ea5bc96d0c99181900360200190a16040805183815290517fdb042010b15d1321c99552200b350bba0a95dfa3d0b43869983ce74b44d644ee9181900360200190a1505050565b613b31611c8b565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015613bb65760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b50613bef613bc2612e48565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff613d5616565b565b613c016301e133808211156132c0565b613c317f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e8263ffffffff613d5616565b6040805182815290517f4cccd9748bff0341d9852cc61d82652a3003dcebea088f05388c0be1f26b4c8a9181900360200190a150565b5490565b80151561187b576040805160e560020a62461bcd02815260206004820152601b60248201527f57524f4e475f4f50455241544f525f4143544956455f53544154450000000000604482015290519081900360640190fd5b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f5700000000000000000000000000006020820152600090819084841115613d4e5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b505050900390565b9055565b6000918252602082905260409091209051600290910155565b613d7c81615573565b613d84612cea565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613dbe57600080fd5b505af1158015613dd2573d6000803e3d6000fd5b505050506040513d6020811015613de857600080fd5b5051600160a060020a038281169116141561187b576040805160e560020a62461bcd02815260206004820152601360248201527f4c49444f5f5245574152445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b613e55611c60565b811461187b576040805160e560020a62461bcd02815260206004820152601b60248201527f554e45585045435445445f434f4e54524143545f56455253494f4e0000000000604482015290519081900360640190fd5b60008183116131e157816118d3565b613ec26159e2565b50600090815260208181526040918290208251918201909252600490910154815290565b6000918252602082905260409091209051600490910155565b6113968383613f1e84613f128888612fda565b9063ffffffff61322616565b612ff2565b51600155565b613f316159e2565b506040805160208101909152600154815290565b600882046010820481148015613f5c575060088306155b8015613f69575060108206155b1515612fd4576040805160e560020a62461bcd02815260206004820152601360248201527f494e56414c49445f5245504f52545f4441544100000000000000000000000000604482015290519081900360640190fd5b613fc76159e2565b6000806000613fd46159e2565b6000613fdf896131fa565b9550613ff286600163ffffffff612fda16565b9450848814156140015761340e565b868061400c57508488115b1515614088576040805160e560020a62461bcd02815260206004820152602160248201527f4558495445445f56414c494441544f52535f434f554e545f444543524541534560448201527f4400000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b61409986600363ffffffff612fda16565b93506140b560006140a98b612f69565b9063ffffffff612fda16565b9250828410156140c157fe5b6140cf8385038911156132c0565b6140e18660018a63ffffffff612ff216565b6140eb8987613d5a565b6040805189815290518a917f0f67960648751434ae86bf350db61194f387fda387e7f568b0ccd0ae0c220166919081900360200190a2614129613f29565b91506141358886615256565b905084881115614156576141518260018363ffffffff613eff16565b614168565b6141688260018363ffffffff61526d16565b61417182613f23565b61340e89613092565b6141826159e2565b600061418c6159e2565b600080600061419a88612f69565b95506141ad86600063ffffffff612fda16565b9450848714156141bc576142c0565b6141c5886131fa565b93506141d884600163ffffffff612fda16565b92506141eb84600363ffffffff612fda16565b9150828210156141f757fe5b6142058383038811156132c0565b61421686600163ffffffff612fda16565b905080871115801561422757508085115b1561424957614249600261423961187e565b889190420163ffffffff612ff216565b61425b8660008963ffffffff612ff216565b6142658887613079565b877f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb888361429a8a600263ffffffff612fda16565b60408051938452602084019290925282820152519081900360600190a26142c088613092565b5050505050505050565b600080600160a060020a03831615156142e6576000915061117b565b50506000903b1190565b60408051600160a060020a0383166024808301919091528251808303909101815260449091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a082310000000000000000000000000000000000000000000000000000000017905260009081806143708684615639565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f524556455254454400000000602082015291935091508215156143fb5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b5095945050505050565b60408051600160a060020a038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600090614487858261566a565b95945050505050565b8051602002815290565b6144a26159e2565b60006144ac6159e2565b60006144b786612f69565b93506144ca84600163ffffffff612fda16565b9250828514156144d957610fa1565b6144e2866131fa565b91506145006144f883600363ffffffff612fda16565b8611156132c0565b61451184600063ffffffff612fda16565b905080851015801561452257508083105b1561454457614544600261453461187e565b869190420163ffffffff612ff216565b6145568460018763ffffffff612ff216565b6145608685613079565b857f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb828761459588600263ffffffff612fda16565b60408051938452602084019290925282820152519081900360600190a2610fa186613092565b6040805160028082526060808301845292602083019080388339019050509050828160008151811015156145eb57fe5b60209081029091010152805182908290600190811061460657fe5b6020908102909101015292915050565b61177a61362f338484612665565b600080600080614633856156b8565b919790965090869003945092505050565b60006060806000606060008060008060008061465e611a6d565b97508760405190808252806020026020018201604052801561468a578160200160208202803883390190505b509950876040519080825280602002602001820160405280156146b7578160200160208202803883390190505b509850876040519080825280602002602001820160405280156146e4578160200160208202803883390190505b5096506146ef612891565b94505b8481101561477657614703816156b8565b955093509150828414156147165761476e565b808a8781518110151561472557fe5b602090810290910101528851828403908a908890811061474157fe5b6020908102909101015286518285039088908890811061475d57fe5b602090810290910101526001909501945b6001016146f2565b85151561479e57604080516000808252602082018181528284019093529c509a5098506147c7565b878610156147b057858a528589528587525b6147bb89888e61573d565b9a508a8c10156147c757fe5b50505050505050509193909250565b6060806000806000806147e76159e2565b60006147f16159e2565b6147fa8c613317565b9099509750600096505b8a518210156149755761482d8b8381518110151561481e57fe5b906020019060200201516131fa565b925061484083600363ffffffff612fda16565b9550898281518110151561485057fe5b6020908102909101015161486b84600163ffffffff612fda16565b0194508585141561487b5761496a565b85851161488457fe5b85850393506148c48b8381518110151561489a57fe5b60209081029091010151600080516020615b038339815191529088878d8d8d63ffffffff6133a216565b8a51968401968b90839081106148d657fe5b906020019060200201517f24eb1c9e765ba41accf9437300ea91ece5ed3f897ec3cdee0e9debd7fe309b78866040518082815260200191505060405180910390a26149298360038763ffffffff612ff216565b61494a8b8381518110151561493a57fe5b9060200190602002015184613d5a565b61496a8b8381518110151561495b57fe5b90602001906020020151613092565b816001019150614804565b868c1461497e57fe5b614986613f29565b905061499a8160038963ffffffff613eff16565b6149a381613f23565b50505050505050935093915050565b600080600060608060606000806149c7612cea565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614a0157600080fd5b505af1158015614a15573d6000803e3d6000fd5b505050506040513d6020811015614a2b57600080fd5b5051604080517ff5eb42dc0000000000000000000000000000000000000000000000000000000081523060048201529051919850600160a060020a0389169163f5eb42dc916024808201926020929091908290030181600087803b158015614a9257600080fd5b505af1158015614aa6573d6000803e3d6000fd5b505050506040513d6020811015614abc57600080fd5b50519550851515614acc57614e38565b614ad586611528565b9450945094505b8451811015614d3f5760028482815181101515614af557fe5b906020019060200201511015614b0a57614d37565b8281815181101515614b1857fe5b9060200190602002015115614be25760018482815181101515614b3757fe5b602090810290910101805190911c90528351614b7090859083908110614b5957fe5b60209081029091010151839063ffffffff61322616565b91508481815181101515614b8057fe5b90602001906020020151600160a060020a03167fe915a473fc2ef8e0231da98380f853b2aeea117a4392c67e753c54186bfbbd128583815181101515614bc257fe5b906020019060200201516040518082815260200191505060405180910390a25b86600160a060020a0316638fcb4e5b8683815181101515614bff57fe5b906020019060200201518684815181101515614c1757fe5b906020019060200201516040518363ffffffff1660e01b81526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015614c7057600080fd5b505af1158015614c84573d6000803e3d6000fd5b505050506040513d6020811015614c9a57600080fd5b50508351614cc590859083908110614cae57fe5b60209081029091010151899063ffffffff61322616565b97508481815181101515614cd557fe5b90602001906020020151600160a060020a03167fdf29796aad820e4bb192f3a8d631b76519bcd2cbe77cc85af20e9df53cece0868583815181101515614d1757fe5b906020019060200201516040518082815260200191505060405180910390a25b600101614adc565b6000821115614e3857614d50612cea565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614d8a57600080fd5b505af1158015614d9e573d6000803e3d6000fd5b505050506040513d6020811015614db457600080fd5b5051604080517f46114928000000000000000000000000000000000000000000000000000000008152306004820152602481018590529051600160a060020a039092169163461149289160448082019260009290919082900301818387803b158015614e1f57600080fd5b505af1158015614e33573d6000803e3d6000fd5b505050505b5050505050505090565b6000818152602081905260409020546101008104600160a060020a03908116908416149060ff1661299a828015614e765750815b8061362f575061362f857f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee614eaa8761576d565b612665565b6000806000606060008088118015614ede575067ffffffffffffffff614edb8a8a63ffffffff61322616565b11155b1515614f34576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b614f4588603063ffffffff61368b16565b8751148015614f645750614f6088606063ffffffff61368b16565b8651145b1515614fba576040805160e560020a62461bcd02815260206004820152600f60248201527f4c454e4754485f4d49534d415443480000000000000000000000000000000000604482015290519081900360640190fd5b604080516030808252606082019092529060208201610600803883390190505091505b8781101561515357614ff68b8b8b63ffffffff61528016565b6030828102890160208181015191830151928601839052850181905291955017159250821561506f576040805160e560020a62461bcd02815260206004820152600960248201527f454d5054595f4b45590000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60208201518455603082015160801b600185015560608102602087010180516002860155602081015160038601556040810151600486015560018201915060018a01995050897fc77a17d6b857abe6d6e6c37301621bc72c4dd52fa8830fb54dfa715c04911a89836040518080602001828103825283818151815260200191508051906020019080838360005b838110156151145781810151838201526020016150fc565b50505050905090810190601f1680156151415780820380516001836020036101000a031916815260200191505b509250505060405180910390a2614fdd565b50969998505050505050505050565b60008061516d6159e2565b6151756159e2565b6000615180866131fa565b925061518b86613eba565b915061519e83600363ffffffff612fda16565b90506151b183600063ffffffff612fda16565b93506151bc86612e09565b15156151ca57809350615218565b6151db82600063ffffffff612fda16565b156152185761521581615210866151f986600163ffffffff612fda16565b61520a88600163ffffffff612fda16565b016131d2565b613eab565b93505b61522982600263ffffffff612fda16565b945083851461524e576152448260028663ffffffff612ff216565b61524e8683613ee6565b505050915091565b6000818311615267578282036118d3565b50900390565b6113968383613f1e84611cf98888612fda565b6040805160208082018690528183018590526060808301859052835180840390910181526080909201928390528151600093918291908401908083835b602083106152dc5780518252601f1990920191602091820191016152bd565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912060001c979650505050505050565b60008060008060606000808811801561533b5750866153388a8a63ffffffff61322616565b11155b801561534f575067ffffffffffffffff8711155b15156153a5576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b60408051603080825260608201909252906020820161060080388339019050509150508787015b8881111561550d576153e98b8b600019840163ffffffff61528016565b9450600185015460801c603083015284546020830152868110156154435761541c8b8b6000198a0163ffffffff61528016565b9350600092505b600583101561543f578284015483860155600183019250615423565b8394505b600092505b600583101561546257600083860155600183019250615448565b600187039650600181039050897fea4b75aaf57196f73d338cadf79ecd0a437902e2dd0d2c4c2cf3ea71b8ab27b9836040518080602001828103825283818151815260200191508051906020019080838360005b838110156154ce5781810151838201526020016154b6565b50505050905090810190601f1680156154fb5780820380516001836020036101000a031916815260200191505b509250505060405180910390a26153cc565b50949998505050505050505050565b80151561187b576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a038116151561187b576040805160e560020a62461bcd02815260206004820152600c60248201527f5a45524f5f414444524553530000000000000000000000000000000000000000604482015290519081900360640190fd5b6156037f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a68263ffffffff613d5616565b6040805182815290517ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9181900360200190a150565b6000806000806040516020818751602089018a5afa9250600083111561565e57805191505b50909590945092505050565b6000806040516020818551602087016000895af160008111156156ae573d801561569b57602081146156a4576156ac565b600193506156ac565b600183511493505b505b5090949350505050565b60008060006156c56159e2565b6156cd6159e2565b6156d6866131fa565b91506156e186613eba565b90506156f482600163ffffffff612fda16565b945061570782600363ffffffff612fda16565b935061571a81600263ffffffff612fda16565b925083831015801561572c5750848410155b151561573457fe5b50509193909250565b6000805b828210156127aa5761575685858486036157ae565b9050801515615764576127aa565b90810190615741565b604080516001808252818301909252606091602080830190803883390190505090508181600081518110151561579f57fe5b60209081029091010152919050565b8251600090600019828080808715156157ca57600096506159ad565b600092505b89518310156158885788838151811015156157e657fe5b906020019060200201518a848151811015156157fe57fe5b60209081029091010151106158125761587d565b898381518110151561582057fe5b906020019060200201518511156158575782955060019350898381518110151561584657fe5b90602001906020020151945061587d565b898381518110151561586557fe5b9060200190602002015185141561587d576001840193505b8260010192506157cf565b83151561589857600096506159ad565b50600019905060005b89518110156159485788818151811015156158b857fe5b906020019060200201518a828151811015156158d057fe5b60209081029091010151106158e457615940565b848a828151811015156158f357fe5b906020019060200201511180156159205750818a8281518110151561591457fe5b90602001906020020151105b1561594057898181518110151561593357fe5b9060200190602002015191505b6001016158a1565b61598b600185116159595788615963565b61596389866159ba565b86615985858d8b81518110151561597657fe5b906020019060200201516131d2565b036131d2565b9650868a8781518110151561599c57fe5b602090810290910101805190910190525b5050505050509392505050565b600082156159d95781600184038115156159d057fe5b046001016118d3565b50600092915050565b60408051602081019091526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615a355782800160ff19823516178555615a62565b82800160010185558215615a62579182015b82811115615a62578235825591602001919060010190615a47565b50610f3492610fd79250905b80821115610f345760008155600101615a6e560078523850fdd761612f46e844cf5a16bda6b3151d6ae961fd7e8e7b92bfbca7f86f5220989faafdc182d508d697678366f4e831f5f56166ad69bfc253fc548fb1bb75b874360e0bfd87f964eadd8276d8efb7c942134fc329b513032d0803e0c6947f955eec7e1f626bee3afd2aa47b5de04ddcdd3fe78dc8838213015ef58dfdeb2b7ad4d8ce5610cfb46470f03b14c197c2b751077c70209c5d0139f7c79ee9a165627a7a723058204284954a78ab82fb9b5f5ba2ae9a69bdbe628d3406e5d98203acbe5ded2040b30029ebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e
Deployed ByteCode
0x6080604052600436106102d95760003560e01c63ffffffff1680630803fac0146102de578063096b7b351461030757806315dae03e1461033d5780632914b9bd1461036457806330a90f01146103d957806332f0a3b5146103f15780634febc81b1461040657806359e25c12146104715780635ddde810146105ae5780635e2fb908146105cc5780635e57d742146105e457806362dcfda11461060857806365cc369a146106e5578063684560a2146107005780636ccc7562146107275780636da7d0a71461073f5780636ef355f1146107545780637038b141146105ae57806375049ad81461076f57806375a080d5146107875780637e7db6e11461079f57806380231f15146107c0578063805911ae1461030757806380afdea8146107d55780638469cbd3146107ea57806385fa63d7146107ff5780638aa104351461082d5780638b3dd749146108425780638ca7c052146108575780638d7e40171461086f5780638ece99951461088757806390c09bdb1461089c57806391dcd6b2146108b1578063973e9328146108c95780639a56983c146108ed5780639a7c2ade146109c95780639abddf09146109f05780639b00c14614610a235780639b3d190014610a4f5780639d4941d814610a7b578063a1658fad14610a9c578063a2e080f114610b03578063a479e50814610b1e578063a70c70e414610b33578063a9e7a84614610b48578063ae962acf14610b68578063b3076c3c14610b8d578063b449402a14610be8578063b497183314610cec578063bee41b5814610d01578063d07442f114610e03578063d087d28814610e03578063d4aae0c414610e18578063d8343dcb14610e2d578063d8e71cd114610e42578063db9887ea14610e57578063de4796ed14610e6f578063e204d09b14610e84578063e864299e14610e99578063ec5af3a414610eae578063ed5cfa4114610754578063f2e2ca6314610ec3578063f31bd9c114610ee1578063fbc77ef114610ef6575b600080fd5b3480156102ea57600080fd5b506102f3610f0e565b604080519115158252519081900360200190f35b34801561031357600080fd5b5061033b60048035906024803591604435808301929082013591606435918201910135610f38565b005b34801561034957600080fd5b50610352610fa9565b60408051918252519081900360200190f35b34801561037057600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526103bd943694929360249392840191908190840183828082843750949750610fda9650505050505050565b60408051600160a060020a039092168252519081900360200190f35b3480156103e557600080fd5b506102f36004356110bd565b3480156103fd57600080fd5b506103bd611181565b34801561041257600080fd5b506104216004356024356111f6565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561045d578181015183820152602001610445565b505050509050019250505060405180910390f35b34801561047d57600080fd5b5061048f60043560243560443561128d565b60405180806020018060200180602001848103845287818151815260200191508051906020019080838360005b838110156104d45781810151838201526020016104bc565b50505050905090810190601f1680156105015780820380516001836020036101000a031916815260200191505b50848103835286518152865160209182019188019080838360005b8381101561053457818101518382015260200161051c565b50505050905090810190601f1680156105615780820380516001836020036101000a031916815260200191505b508481038252855181528551602091820191808801910280838360005b8381101561059657818101518382015260200161057e565b50505050905001965050505050505060405180910390f35b3480156105ba57600080fd5b5061033b60043560243560443561138b565b3480156105d857600080fd5b506102f360043561139b565b3480156105f057600080fd5b5061033b6004803590602480359081019101356113b0565b34801561061457600080fd5b50610620600435611528565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b83811015610668578181015183820152602001610650565b50505050905001848103835286818151815260200191508051906020019060200280838360005b838110156106a757818101518382015260200161068f565b50505050905001848103825285818151815260200191508051906020019060200280838360008381101561059657818101518382015260200161057e565b3480156106f157600080fd5b5061033b600435602435611759565b34801561070c57600080fd5b5061033b600160a060020a036004351660243560443561177e565b34801561073357600080fd5b5061033b60043561185b565b34801561074b57600080fd5b5061035261187e565b34801561076057600080fd5b5061033b6004356024356118a9565b34801561077b57600080fd5b506102f36004356118b5565b34801561079357600080fd5b5061033b6004356118da565b3480156107ab57600080fd5b506102f3600160a060020a0360043516611a2a565b3480156107cc57600080fd5b50610352611a30565b3480156107e157600080fd5b50610352611a42565b3480156107f657600080fd5b50610352611a6d565b34801561080b57600080fd5b506103526024600480358281019291013590600160a060020a03903516611a86565b34801561083957600080fd5b50610352611c60565b34801561084e57600080fd5b50610352611c8b565b34801561086357600080fd5b50610352600435611cb6565b34801561087b57600080fd5b5061033b600435611d05565b34801561089357600080fd5b50610352611d1c565b3480156108a857600080fd5b5061033b611d2e565b3480156108bd57600080fd5b5061033b600435611d68565b3480156108d557600080fd5b5061033b600435600160a060020a0360243516611e1b565b3480156108f957600080fd5b5061090a6004356024351515611ee7565b604080518815158152600160a060020a0387169181019190915267ffffffffffffffff8086166060830152848116608083015283811660a0830152821660c082015260e0602080830182815289519284019290925288516101008401918a019080838360005b83811015610988578181015183820152602001610970565b50505050905090810190601f1680156109b55780820380516001836020036101000a031916815260200191505b509850505050505050505060405180910390f35b3480156109d557600080fd5b5061033b600160a060020a036004351660243560443561203a565b3480156109fc57600080fd5b50610a05612261565b60408051938452602084019290925282820152519081900360600190f35b348015610a2f57600080fd5b5061033b60246004803582810192908201359181359182019101356122bb565b348015610a5b57600080fd5b5061033b6024600480358281019290820135918135918201910135612354565b348015610a8757600080fd5b5061033b600160a060020a03600435166123d6565b348015610aa857600080fd5b5060408051602060046044358181013583810280860185019096528085526102f3958335600160a060020a03169560248035963696956064959394920192918291850190849080828437509497506126659650505050505050565b348015610b0f57600080fd5b5061033b6004356024356127b2565b348015610b2a57600080fd5b506103bd6127dc565b348015610b3f57600080fd5b50610352612891565b348015610b5457600080fd5b5061033b60043560243515156044356128bc565b348015610b7457600080fd5b5061033b60043567ffffffffffffffff602435166129a0565b348015610b9957600080fd5b50610ba5600435612ac5565b6040805198151589526020890197909752878701959095526060870193909352608086019190915260a085015260c084015260e083015251908190036101000190f35b348015610bf457600080fd5b50610c03600435602435612b83565b60405180806020018060200184151515158152602001838103835286818151815260200191508051906020019080838360005b83811015610c4e578181015183820152602001610c36565b50505050905090810190601f168015610c7b5780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b83811015610cae578181015183820152602001610c96565b50505050905090810190601f168015610cdb5780820380516001836020036101000a031916815260200191505b509550505050505060405180910390f35b348015610cf857600080fd5b50610352612bc1565b348015610d0d57600080fd5b50610d25600480359060248035908101910135612bc6565b604051808060200180602001838103835285818151815260200191508051906020019080838360005b83811015610d66578181015183820152602001610d4e565b50505050905090810190601f168015610d935780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015610dc6578181015183820152602001610dae565b50505050905090810190601f168015610df35780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b348015610e0f57600080fd5b50610352612c94565b348015610e2457600080fd5b506103bd612cbf565b348015610e3957600080fd5b506103bd612cea565b348015610e4e57600080fd5b50610352612d15565b348015610e6357600080fd5b50610352600435612d39565b348015610e7b57600080fd5b506102f3612d68565b348015610e9057600080fd5b50610352612d7b565b348015610ea557600080fd5b5061033b612d83565b348015610eba57600080fd5b50610352612da2565b348015610ecf57600080fd5b5061033b600435602435604435612da7565b348015610eed57600080fd5b50610352612de5565b348015610f0257600080fd5b506102f3600435612e09565b600080610f19611c8b565b90508015801590610f31575080610f2e612e48565b10155b91505b5090565b610fa1868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f8c018190048102820181019092528a815294508a9350899250829150840183828082843750612e4c945050505050565b505050505050565b6000610fd47fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d0612f65565b90505b90565b6000610fe46127dc565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561103f578181015183820152602001611027565b50505050905090810190601f16801561106c5780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561108b57600080fd5b505af115801561109f573d6000803e3d6000fd5b505050506040513d60208110156110b557600080fd5b505192915050565b60006110c76159e2565b6110d083612f69565b90506110db81612f95565b1580156110f757506110f481600263ffffffff612fda16565b15155b151561114d576040805160e560020a62461bcd02815260206004820152601260248201527f43414e545f434c4541525f50454e414c54590000000000000000000000000000604482015290519081900360640190fd5b611160816002600063ffffffff612ff216565b61116a8382613079565b61117383613092565b61117b613109565b50919050565b600061118b612cbf565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156111c557600080fd5b505af11580156111d9573d6000803e3d6000fd5b505050506040513d60208110156111ef57600080fd5b5051905090565b6060600080611203612891565b91508185101580611212575083155b1561121c57611285565b611228848684036131d2565b604051908082528060200260200182016040528015611251578160200160208202803883390190505b509250600090505b825181101561128557808501838281518110151561127357fe5b60209081029091010152600101611259565b505092915050565b606080606061129a6159e2565b6000806112a6896131e8565b6112af896131fa565b92506112dc6112c584600263ffffffff612fda16565b6112d58a8a63ffffffff61322616565b11156132c0565b6112ed83600363ffffffff612fda16565b91506112f887613317565b604080518a81526020808c028201019091529197509550878015611326578160200160208202803883390190505b50935061134d600080516020615b038339815191528a8a8a8a8a600063ffffffff6133a216565b8681101561137f578181890110848281518110151561136857fe5b91151560209283029091019091015260010161134d565b50505093509350939050565b611396838383613419565b505050565b60009081526020819052604090205460ff1690565b6113e982828080601f0160208091040260200160405190810160405280939291908181526020018383808284375061358d945050505050565b6113f2836131e8565b611409600080516020615a838339815191526135f6565b6114b5828260405180838380828437820191505092505050604051809103902060001916600080868152602001908152602001600020600101604051808280546001816001161561010002031660029004801561149d5780601f1061147b57610100808354040283529182019161149d565b820191906000526020600020905b815481529060010190602001808311611489575b50509150506040518091039020600019161415613634565b60008381526020819052604090206114d19060010183836159f4565b50827fcb16868f4831cc58a28d413f658752a2958bd1f50e94ed6391716b936c48093b83836040518080602001828103825284848281815260200192508082843760405192018290039550909350505050a2505050565b606080606060008060008061153b6159e2565b600080600080611549612891565b9850611553611a6d565b97508760405190808252806020026020018201604052801561157f578160200160208202803883390190505b509b50876040519080825280602002602001820160405280156115ac578160200160208202803883390190505b509a50876040519080825280602002602001820160405280156115d9578160200160208202803883390190505b50995060009650600095505b888410156116da576115f68461139b565b1515611601576116cf565b61160a846131fa565b945061161d85600163ffffffff612fda16565b925061163085600363ffffffff612fda16565b91508282101561163c57fe5b506000838152602081905260409020548b5183830396870196916101009004600160a060020a0316908d908990811061167157fe5b600160a060020a039092166020928302909101909101528a5181908c908990811061169857fe5b602090810290910101526116ab846118b5565b8a888151811015156116b957fe5b9115156020928302909101909101526001909601955b8360010193506115e5565b8515156116e657611749565b600096505b87871015611749578561171c8e8d8a81518110151561170657fe5b602090810290910101519063ffffffff61368b16565b81151561172557fe5b048b8881518110151561173457fe5b602090810290910101526001909601956116eb565b5050505050505050509193909250565b611770600080516020615a838339815191526135f6565b61177a8282613736565b5050565b611786611c8b565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156118475760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561180c5781810151838201526020016117f4565b50505050905090810190601f1680156118395780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506118538383836138d9565b611396613b29565b611872600080516020615a838339815191526135f6565b61187b81613bf1565b50565b6000610fd47f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e612f65565b61177a82826001613419565b60006118bf6159e2565b6118c883612f69565b90506118d381612f95565b9392505050565b60006118e46159e2565b6000806118f0856131e8565b611907600080516020615a838339815191526135f6565b6119186119138661139b565b613c6b565b611920611a6d565b935061195161193685600163ffffffff613cc216565b600080516020615aa38339815191529063ffffffff613d5616565b600085815260208181526040808320805460ff1916905580519283525187927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a26119a2856131fa565b92506119b583600063ffffffff612fda16565b91506119c883600363ffffffff612fda16565b905080821115611a1b576119e48360008363ffffffff612ff216565b6119ee8584613d5a565b6040805182815290518691600080516020615ae3833981519152919081900360200190a2611a1b85613092565b611a23613109565b5050505050565b50600190565b600080516020615ac383398151915281565b6000610fd47fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b612f65565b6000610fd4600080516020615aa3833981519152612f65565b6000806000611ac486868080601f0160208091040260200160405190810160405280939291908181526020018383808284375061358d945050505050565b611acd84613d73565b611ad5612891565b925060c88310611b2f576040805160e560020a62461bcd02815260206004820152601c60248201527f4d41585f4f50455241544f52535f434f554e545f455843454544454400000000604482015290519081900360640190fd5b611b627fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e86001850163ffffffff613d5616565b60008381526020819052604090209150611b7a611a6d565b9050611b9d600080516020615aa38339815191526001830163ffffffff613d5616565b815460ff191660019081178355611bb790830187876159f4565b50815474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a03861690810291909117835560408051858152908101919091526000606082018190526080602083018181529083018890527fc52ec0ad7872dae440d886040390c13677df7bf3cca136d8d81e5e5e7dd62ff19286928a928a928a929160a0820186868082843760405192018290039850909650505050505050a150509392505050565b6000610fd47f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6612f65565b6000610fd47febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e612f65565b6000611cc06159e2565b611cc9836131e8565b611cd2836131fa565b90506118d3611ce882600363ffffffff612fda16565b611cf983600263ffffffff612fda16565b9063ffffffff613cc216565b61187b600080516020615ac38339815191526135f6565b600080516020615a8383398151915281565b6000611d47600080516020615ac38339815191526135f6565b611d4f612891565b9050600081111561187b5761187b600060018303613736565b611d71816131e8565b611d88600080516020615a838339815191526135f6565b611d9a611d948261139b565b15613c6b565b611dc3611da5611a6d565b600080516020615aa38339815191529060010163ffffffff613d5616565b60008181526020818152604091829020805460ff191660019081179091558251908152915183927fecdf08e8a6c4493efb460f6abc7d14532074fa339c3a6410623a1d3ee0fb2cac92908290030190a261187b613109565b611e2481613d73565b611e2d826131e8565b611e44600080516020615a838339815191526135f6565b600082815260208190526040902054611e7090600160a060020a03838116610100909204161415613634565b60008281526020818152604091829020805474ffffffffffffffffffffffffffffffffffffffff001916610100600160a060020a038616908102919091179091558251908152915184927f9a52205165d510fc1e428886d52108725dc01ed544da1702dc7bd3fdb3f243b292908290030190a25050565b60006060600080600080600080611efc6159e2565b611f058b6131e8565b60008b8152602081905260409020805460ff81169a506101009004600160a060020a03169750915089611f4657604080516020810190915260008152611fd3565b60018281018054604080516020600295841615610100026000190190931694909404601f810183900483028501830190915280845290830182828015611fcd5780601f10611fa257610100808354040283529160200191611fcd565b820191906000526020600020905b815481529060010190602001808311611fb057829003601f168201915b50505050505b9750611fde8b6131fa565b9050611ff181600063ffffffff612fda16565b955061200481600163ffffffff612fda16565b945061201781600263ffffffff612fda16565b935061202a81600363ffffffff612fda16565b9250505092959891949750929550565b60006120446159e2565b61204c6159e2565b6120546159e2565b6000806000806000612064610f0e565b15156120ba576040805160e560020a62461bcd02815260206004820152601860248201527f434f4e54524143545f4e4f545f494e495449414c495a45440000000000000000604482015290519081900360640190fd5b6120c46000613e4d565b6120cf8c8c8c6138d9565b6120d7612891565b9850602060405190810160405280600081525095505b88821015612242576120fe826131fa565b975061211188600063ffffffff612fda16565b945061212488600263ffffffff612fda16565b935061213788600363ffffffff612fda16565b60008381526020819052604090205490935060ff16151561215957508161216f565b61216c846121678588613eab565b6131d2565b90505b8481146121b7576121888860008363ffffffff612ff216565b6121928289613d5a565b6040805182815290518391600080516020615ae3833981519152919081900360200190a25b6121c082613eba565b96506121d48760028363ffffffff612ff216565b6121de8288613ee6565b6121f08660008363ffffffff613eff16565b6122028660038563ffffffff613eff16565b61222560016122178a8263ffffffff612fda16565b88919063ffffffff613eff16565b6122378660028663ffffffff613eff16565b8160010191506120ed565b61224b86613f23565b612253613109565b505050505050505050505050565b600080600061226e6159e2565b612276613f29565b905061228981600163ffffffff612fda16565b935061229c81600363ffffffff612fda16565b92506122b383611cf983600063ffffffff612fda16565b915050909192565b60008080808080806122da600080516020615ac38339815191526135f6565b6122e48a89613f45565b96506122ee612891565b95506024600435019250602480350191505b8681101561233f576008810283013560c01c94506010810282013560801c935060010161232e8686106132c0565b61233a85856000613fbf565b612300565b612347613109565b5050505050505050505050565b6000808080808080612373600080516020615ac38339815191526135f6565b61237d8a89613f45565b9650612387612891565b95506024600435019250602480350191505b8681101561233f576008810283013560c01c94506010810282013560801c93506001016123c78686106132c0565b6123d1858561417a565b612399565b60008060006123e484611a2a565b60408051808201909152601281527f5245434f5645525f444953414c4c4f5745440000000000000000000000000000602082015290151561246a5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b50612473611181565b925061247e836142ca565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156125045760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b50600160a060020a03841615156125555760405130319250600160a060020a0384169083156108fc029084906000818181858888f1935050505015801561254f573d6000803e3d6000fd5b50612614565b5082612570600160a060020a0382163063ffffffff6142f016565b915061258c600160a060020a038216848463ffffffff61440516565b60408051808201909152601d81527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c454400000060208201529015156126125760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b505b83600160a060020a031683600160a060020a03167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b600080612670610f0e565b151561267f57600091506127aa565b612687612cbf565b9050600160a060020a03811615156126a257600091506127aa565b80600160a060020a031663fdef91068630876126bd88614490565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b8381101561272c578181015183820152602001612714565b50505050905090810190601f1680156127595780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b15801561277b57600080fd5b505af115801561278f573d6000803e3d6000fd5b505050506040513d60208110156127a557600080fd5b505191505b509392505050565b6127bb826131e8565b6127d2600080516020615ac38339815191526135f6565b61177a828261449a565b6000806127e7612cbf565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b15801561108b57600080fd5b6000610fd47fe2a589ae0816b289a9d29b7c085f8eba4b5525accca9fa8ff4dba3f5a41287e8612f65565b6128c46159e2565b6128cd846131e8565b6128e4600080516020615ac38339815191526135f6565b6128f867ffffffffffffffff8311156132c0565b61290184613eba565b9050612928600084612914576000612917565b60015b83919060ff1663ffffffff612ff216565b61294960018461293957600061293b565b835b83919063ffffffff612ff216565b6129538482613ee6565b60408051838152905185917fd50ea115db6f0b433ef9cc4b71110dbd9202364a00488be90718990be5bf16a6919081900360200190a261299284613092565b61299a613109565b50505050565b6129a86159e2565b6000806000806129b7876131e8565b6129f47f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d7947546129ef8967ffffffffffffffff8a166145bb565b614616565b612a006119138861139b565b612a09876131fa565b9450612a1c85600063ffffffff612fda16565b9350612a2f85600363ffffffff612fda16565b9250612a4285600263ffffffff612fda16565b9150612a5c826121678867ffffffffffffffff1686613eab565b905083811415612a6b57612abc565b612a7d8560008363ffffffff612ff216565b612a878786613d5a565b6040805182815290518891600080516020615ae3833981519152919081900360200190a2612ab487613092565b612abc613109565b50505050505050565b600080600080600080600080612ad96159e2565b612ae16159e2565b612aea8b6131e8565b612af38b613eba565b9150612afe8b612f69565b9050612b1182600063ffffffff612fda16565b15159950612b2682600163ffffffff612fda16565b9850612b3981600063ffffffff612fda16565b9750612b4c81600163ffffffff612fda16565b9650612b5f81600263ffffffff612fda16565b9550612b6a8b614624565b8095508196508297505050505050919395975091939597565b60608060006060612b968686600161128d565b8051929650909450915081906000908110612bad57fe5b906020019060200201519150509250925092565b60ff81565b60608060008180612be4600080516020615ac38339815191526135f6565b871515612c0a576040805160008082526020820190815281830190925295509350612c89565b612c1388614644565b91945092509050878314612c71576040805160e560020a62461bcd02815260206004820152601c60248201527f494e56414c49445f414c4c4f43415445445f4b4559535f434f554e5400000000604482015290519081900360640190fd5b612c7c8383836147d6565b9095509350612c89613109565b505050935093915050565b6000610fd47fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e612f65565b6000610fd47f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b612f65565b6000610fd47ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d03537612f65565b7f07b39e0faf2521001ae4e58cb9ffd3840a63e205d288dc9c93c3774f0d79475481565b6000612d436159e2565b612d4c836131e8565b612d55836131fa565b90506118d381600263ffffffff612fda16565b6000600019612d75611c8b565b14905090565b6301e1338081565b612d9a600080516020615ac38339815191526135f6565b61187b6149b2565b60c881565b612db0836131e8565b612dc7600080516020615ac38339815191526135f6565b612dd1838261417a565b612ddd83836001613fbf565b611396613109565b7f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee81565b6000612e136159e2565b612e1c83612f69565b9050612e2781612f95565b1580156118d35750612e4081600263ffffffff612fda16565b159392505050565b4390565b612e546159e2565b6000612e5e6159e2565b612e67876131e8565b612e713388614e42565b612e908615801590612e8b575067ffffffffffffffff8711155b6132c0565b612e99876131fa565b9250612eac83600263ffffffff612fda16565b9150612eca67ffffffffffffffff6112d5848963ffffffff61322616565b612eec600080516020615b03833981519152888489898963ffffffff614eaf16565b60408051828152905191935088917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f09181900360200190a2612f368360028463ffffffff612ff216565b612f408784613d5a565b612f48613f29565b9050612f5c8160028863ffffffff613eff16565b612ab481613f23565b5490565b612f716159e2565b50600090815260208181526040918290208251918201909252600390910154815290565b6000612fa7828263ffffffff612fda16565b612fb883600163ffffffff612fda16565b1080612fd45750612fd082600263ffffffff612fda16565b4211155b92915050565b905167ffffffffffffffff604090920260ff161c1690565b67ffffffffffffffff811115613052576040805160e560020a62461bcd02815260206004820152600f60248201527f5041434b45445f4f564552464c4f570000000000000000000000000000000000604482015290519081900360640190fd5b825167ffffffffffffffff91821660409390930260ff1692831b9190921b19909116179052565b6000918252602082905260409091209051600390910155565b60008061309d6159e2565b60006130a885615162565b93509350838314156130b957611a23565b6130c1613f29565b91506130cd8385615256565b9050838311156130ee576130e98260008363ffffffff613eff16565b613100565b6131008260008363ffffffff61526d16565b611a2382613f23565b60006131347fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e612f65565b60010190506131697fcd91478ac3f2620f0776eacb9c24123a214bcb23c32ae7d28278aa846c8c380e8263ffffffff613d5616565b6040805182815290517ffb992daec9d46d64898e3a9336d02811349df6cbea8b95d4deb2fa6c7b454f0d9181900360200190a16040805182815290517f7220970e1f1f12864ecccd8942690a837c7a8dd45d158cb891eb45a8a69134aa9181900360200190a150565b60008183106131e157816118d3565b5090919050565b61187b6131f3612891565b82106132c0565b6132026159e2565b50600090815260208181526040918290208251918201909252600290910154815290565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f57000000000000000000000000000000602082015260009083830190848210156132b45760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b508091505b5092915050565b80151561187b576040805160e560020a62461bcd02815260206004820152600c60248201527f4f55545f4f465f52414e47450000000000000000000000000000000000000000604482015290519081900360640190fd5b60608061332b83603063ffffffff61368b16565b6040519080825280601f01601f191660200182016040528015613358578160200160208202803883390190505b5061336a84606063ffffffff61368b16565b6040519080825280601f01601f191660200182016040528015613397578160200160208202803883390190505b509092509050915091565b6000805b8581101561340e576133c1898989840163ffffffff61528016565b60018082015460801c85840160308181028a0190810192909252835460209283015260028401546060918202890192830152600384015460408301526004840154910152909250016133a6565b505050505050505050565b6134216159e2565b60008061342c6159e2565b613435876131e8565b61343f3388614e42565b84151561344b57612abc565b613454876131fa565b935061346784600263ffffffff612fda16565b925061349861347d85600363ffffffff612fda16565b8710158015612e8b5750836112d5888863ffffffff61322616565b6134b9600080516020615b038339815191528888888763ffffffff61531316565b92506134cd8460028563ffffffff612ff216565b60408051848152905188917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a261351484600063ffffffff612fda16565b915081861015613555576135308460008863ffffffff612ff216565b6040805187815290518891600080516020615ae3833981519152919081900360200190a25b61355f8785613d5a565b613567613f29565b905061357b8160028763ffffffff61526d16565b61358481613f23565b612ab487613092565b600081511180156135a0575060ff815111155b151561187b576040805160e560020a62461bcd02815260206004820152601160248201527f57524f4e475f4e414d455f4c454e475448000000000000000000000000000000604482015290519081900360640190fd5b61187b61362f33836000604051908082528060200260200182016040528015613629578160200160208202803883390190505b50612665565b61551c565b80151561187b576040805160e560020a62461bcd02815260206004820152601160248201527f56414c55455f49535f5448455f53414d45000000000000000000000000000000604482015290519081900360640190fd5b60008083151561369e57600091506132b9565b508282028284828115156136ae57fe5b60408051808201909152601181527f4d4154485f4d554c5f4f564552464c4f57000000000000000000000000000000602082015292919004146132b45760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b6000806000806137446159e2565b600061374e6159e2565b61376b888a11158015612e8b5750613764612891565b89106132c0565b8891505b8782116138a35761377f826131fa565b925061379283600263ffffffff612fda16565b94506137a583600363ffffffff612fda16565b9350838514156137b457613898565b8385116137bd57fe5b8385039650948601946137d88360028663ffffffff612ff216565b6137ea8360008663ffffffff612ff216565b6137f48284613d5a565b6137fd82613092565b60408051858152905183917fdd01838a366ae4dc9a86e1922512c0716abebc9a440baae0e22d2dec578223f0919081900360200190a26040805185815290518391600080516020615ae3833981519152919081900360200190a26040805167ffffffffffffffff89168152905183917f9824694569ba758f8872bb150515caaf8f1e2cc27e6805679c4ac8c3b9b83d87919081900360200190a25b81600101915061376f565b600086111561340e576138b4613f29565b90506138c88160028863ffffffff61526d16565b6138d181613f23565b61340e613109565b6138e283615573565b6139127ffb2059fd4b64256b64068a0f57046c6d40b9f0e592ba8bcfdf5b941910d035378463ffffffff613d5616565b6139427fbacf4236659a602d72c631ba0b0d67ec320aaf523f3ae3590d7faee4f42351d08363ffffffff613d5616565b61394c60026155d3565b61395581613bf1565b61395d612cea565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561399757600080fd5b505af11580156139ab573d6000803e3d6000fd5b505050506040513d60208110156139c157600080fd5b5051600160a060020a031663095ea7b36139d9612cea565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613a1357600080fd5b505af1158015613a27573d6000803e3d6000fd5b505050506040513d6020811015613a3d57600080fd5b50516040805163ffffffff841660e01b8152600160a060020a03909216600483015260001960248301525160448083019260209291908290030181600087803b158015613a8957600080fd5b505af1158015613a9d573d6000803e3d6000fd5b505050506040513d6020811015613ab357600080fd5b505060408051600160a060020a038516815290517fa44aa4b7320163340e971b1f22f153bbb8a0151d783bd58377018ea5bc96d0c99181900360200190a16040805183815290517fdb042010b15d1321c99552200b350bba0a95dfa3d0b43869983ce74b44d644ee9181900360200190a1505050565b613b31611c8b565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015613bb65760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b50613bef613bc2612e48565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff613d5616565b565b613c016301e133808211156132c0565b613c317f8e3a1f3826a82c1116044b334cae49f3c3d12c3866a1c4b18af461e12e58a18e8263ffffffff613d5616565b6040805182815290517f4cccd9748bff0341d9852cc61d82652a3003dcebea088f05388c0be1f26b4c8a9181900360200190a150565b5490565b80151561187b576040805160e560020a62461bcd02815260206004820152601b60248201527f57524f4e475f4f50455241544f525f4143544956455f53544154450000000000604482015290519081900360640190fd5b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f5700000000000000000000000000006020820152600090819084841115613d4e5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b505050900390565b9055565b6000918252602082905260409091209051600290910155565b613d7c81615573565b613d84612cea565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015613dbe57600080fd5b505af1158015613dd2573d6000803e3d6000fd5b505050506040513d6020811015613de857600080fd5b5051600160a060020a038281169116141561187b576040805160e560020a62461bcd02815260206004820152601360248201527f4c49444f5f5245574152445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b613e55611c60565b811461187b576040805160e560020a62461bcd02815260206004820152601b60248201527f554e45585045435445445f434f4e54524143545f56455253494f4e0000000000604482015290519081900360640190fd5b60008183116131e157816118d3565b613ec26159e2565b50600090815260208181526040918290208251918201909252600490910154815290565b6000918252602082905260409091209051600490910155565b6113968383613f1e84613f128888612fda565b9063ffffffff61322616565b612ff2565b51600155565b613f316159e2565b506040805160208101909152600154815290565b600882046010820481148015613f5c575060088306155b8015613f69575060108206155b1515612fd4576040805160e560020a62461bcd02815260206004820152601360248201527f494e56414c49445f5245504f52545f4441544100000000000000000000000000604482015290519081900360640190fd5b613fc76159e2565b6000806000613fd46159e2565b6000613fdf896131fa565b9550613ff286600163ffffffff612fda16565b9450848814156140015761340e565b868061400c57508488115b1515614088576040805160e560020a62461bcd02815260206004820152602160248201527f4558495445445f56414c494441544f52535f434f554e545f444543524541534560448201527f4400000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b61409986600363ffffffff612fda16565b93506140b560006140a98b612f69565b9063ffffffff612fda16565b9250828410156140c157fe5b6140cf8385038911156132c0565b6140e18660018a63ffffffff612ff216565b6140eb8987613d5a565b6040805189815290518a917f0f67960648751434ae86bf350db61194f387fda387e7f568b0ccd0ae0c220166919081900360200190a2614129613f29565b91506141358886615256565b905084881115614156576141518260018363ffffffff613eff16565b614168565b6141688260018363ffffffff61526d16565b61417182613f23565b61340e89613092565b6141826159e2565b600061418c6159e2565b600080600061419a88612f69565b95506141ad86600063ffffffff612fda16565b9450848714156141bc576142c0565b6141c5886131fa565b93506141d884600163ffffffff612fda16565b92506141eb84600363ffffffff612fda16565b9150828210156141f757fe5b6142058383038811156132c0565b61421686600163ffffffff612fda16565b905080871115801561422757508085115b1561424957614249600261423961187e565b889190420163ffffffff612ff216565b61425b8660008963ffffffff612ff216565b6142658887613079565b877f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb888361429a8a600263ffffffff612fda16565b60408051938452602084019290925282820152519081900360600190a26142c088613092565b5050505050505050565b600080600160a060020a03831615156142e6576000915061117b565b50506000903b1190565b60408051600160a060020a0383166024808301919091528251808303909101815260449091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a082310000000000000000000000000000000000000000000000000000000017905260009081806143708684615639565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f524556455254454400000000602082015291935091508215156143fb5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561180c5781810151838201526020016117f4565b5095945050505050565b60408051600160a060020a038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600090614487858261566a565b95945050505050565b8051602002815290565b6144a26159e2565b60006144ac6159e2565b60006144b786612f69565b93506144ca84600163ffffffff612fda16565b9250828514156144d957610fa1565b6144e2866131fa565b91506145006144f883600363ffffffff612fda16565b8611156132c0565b61451184600063ffffffff612fda16565b905080851015801561452257508083105b1561454457614544600261453461187e565b869190420163ffffffff612ff216565b6145568460018763ffffffff612ff216565b6145608685613079565b857f0ee42dd52dd2b8feb0fc9cc054a08162a23e022c177319db981cf339e5b8ffdb828761459588600263ffffffff612fda16565b60408051938452602084019290925282820152519081900360600190a2610fa186613092565b6040805160028082526060808301845292602083019080388339019050509050828160008151811015156145eb57fe5b60209081029091010152805182908290600190811061460657fe5b6020908102909101015292915050565b61177a61362f338484612665565b600080600080614633856156b8565b919790965090869003945092505050565b60006060806000606060008060008060008061465e611a6d565b97508760405190808252806020026020018201604052801561468a578160200160208202803883390190505b509950876040519080825280602002602001820160405280156146b7578160200160208202803883390190505b509850876040519080825280602002602001820160405280156146e4578160200160208202803883390190505b5096506146ef612891565b94505b8481101561477657614703816156b8565b955093509150828414156147165761476e565b808a8781518110151561472557fe5b602090810290910101528851828403908a908890811061474157fe5b6020908102909101015286518285039088908890811061475d57fe5b602090810290910101526001909501945b6001016146f2565b85151561479e57604080516000808252602082018181528284019093529c509a5098506147c7565b878610156147b057858a528589528587525b6147bb89888e61573d565b9a508a8c10156147c757fe5b50505050505050509193909250565b6060806000806000806147e76159e2565b60006147f16159e2565b6147fa8c613317565b9099509750600096505b8a518210156149755761482d8b8381518110151561481e57fe5b906020019060200201516131fa565b925061484083600363ffffffff612fda16565b9550898281518110151561485057fe5b6020908102909101015161486b84600163ffffffff612fda16565b0194508585141561487b5761496a565b85851161488457fe5b85850393506148c48b8381518110151561489a57fe5b60209081029091010151600080516020615b038339815191529088878d8d8d63ffffffff6133a216565b8a51968401968b90839081106148d657fe5b906020019060200201517f24eb1c9e765ba41accf9437300ea91ece5ed3f897ec3cdee0e9debd7fe309b78866040518082815260200191505060405180910390a26149298360038763ffffffff612ff216565b61494a8b8381518110151561493a57fe5b9060200190602002015184613d5a565b61496a8b8381518110151561495b57fe5b90602001906020020151613092565b816001019150614804565b868c1461497e57fe5b614986613f29565b905061499a8160038963ffffffff613eff16565b6149a381613f23565b50505050505050935093915050565b600080600060608060606000806149c7612cea565b600160a060020a03166323509a2d6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614a0157600080fd5b505af1158015614a15573d6000803e3d6000fd5b505050506040513d6020811015614a2b57600080fd5b5051604080517ff5eb42dc0000000000000000000000000000000000000000000000000000000081523060048201529051919850600160a060020a0389169163f5eb42dc916024808201926020929091908290030181600087803b158015614a9257600080fd5b505af1158015614aa6573d6000803e3d6000fd5b505050506040513d6020811015614abc57600080fd5b50519550851515614acc57614e38565b614ad586611528565b9450945094505b8451811015614d3f5760028482815181101515614af557fe5b906020019060200201511015614b0a57614d37565b8281815181101515614b1857fe5b9060200190602002015115614be25760018482815181101515614b3757fe5b602090810290910101805190911c90528351614b7090859083908110614b5957fe5b60209081029091010151839063ffffffff61322616565b91508481815181101515614b8057fe5b90602001906020020151600160a060020a03167fe915a473fc2ef8e0231da98380f853b2aeea117a4392c67e753c54186bfbbd128583815181101515614bc257fe5b906020019060200201516040518082815260200191505060405180910390a25b86600160a060020a0316638fcb4e5b8683815181101515614bff57fe5b906020019060200201518684815181101515614c1757fe5b906020019060200201516040518363ffffffff1660e01b81526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015614c7057600080fd5b505af1158015614c84573d6000803e3d6000fd5b505050506040513d6020811015614c9a57600080fd5b50508351614cc590859083908110614cae57fe5b60209081029091010151899063ffffffff61322616565b97508481815181101515614cd557fe5b90602001906020020151600160a060020a03167fdf29796aad820e4bb192f3a8d631b76519bcd2cbe77cc85af20e9df53cece0868583815181101515614d1757fe5b906020019060200201516040518082815260200191505060405180910390a25b600101614adc565b6000821115614e3857614d50612cea565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614d8a57600080fd5b505af1158015614d9e573d6000803e3d6000fd5b505050506040513d6020811015614db457600080fd5b5051604080517f46114928000000000000000000000000000000000000000000000000000000008152306004820152602481018590529051600160a060020a039092169163461149289160448082019260009290919082900301818387803b158015614e1f57600080fd5b505af1158015614e33573d6000803e3d6000fd5b505050505b5050505050505090565b6000818152602081905260409020546101008104600160a060020a03908116908416149060ff1661299a828015614e765750815b8061362f575061362f857f75abc64490e17b40ea1e66691c3eb493647b24430b358bd87ec3e5127f1621ee614eaa8761576d565b612665565b6000806000606060008088118015614ede575067ffffffffffffffff614edb8a8a63ffffffff61322616565b11155b1515614f34576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b614f4588603063ffffffff61368b16565b8751148015614f645750614f6088606063ffffffff61368b16565b8651145b1515614fba576040805160e560020a62461bcd02815260206004820152600f60248201527f4c454e4754485f4d49534d415443480000000000000000000000000000000000604482015290519081900360640190fd5b604080516030808252606082019092529060208201610600803883390190505091505b8781101561515357614ff68b8b8b63ffffffff61528016565b6030828102890160208181015191830151928601839052850181905291955017159250821561506f576040805160e560020a62461bcd02815260206004820152600960248201527f454d5054595f4b45590000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60208201518455603082015160801b600185015560608102602087010180516002860155602081015160038601556040810151600486015560018201915060018a01995050897fc77a17d6b857abe6d6e6c37301621bc72c4dd52fa8830fb54dfa715c04911a89836040518080602001828103825283818151815260200191508051906020019080838360005b838110156151145781810151838201526020016150fc565b50505050905090810190601f1680156151415780820380516001836020036101000a031916815260200191505b509250505060405180910390a2614fdd565b50969998505050505050505050565b60008061516d6159e2565b6151756159e2565b6000615180866131fa565b925061518b86613eba565b915061519e83600363ffffffff612fda16565b90506151b183600063ffffffff612fda16565b93506151bc86612e09565b15156151ca57809350615218565b6151db82600063ffffffff612fda16565b156152185761521581615210866151f986600163ffffffff612fda16565b61520a88600163ffffffff612fda16565b016131d2565b613eab565b93505b61522982600263ffffffff612fda16565b945083851461524e576152448260028663ffffffff612ff216565b61524e8683613ee6565b505050915091565b6000818311615267578282036118d3565b50900390565b6113968383613f1e84611cf98888612fda565b6040805160208082018690528183018590526060808301859052835180840390910181526080909201928390528151600093918291908401908083835b602083106152dc5780518252601f1990920191602091820191016152bd565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912060001c979650505050505050565b60008060008060606000808811801561533b5750866153388a8a63ffffffff61322616565b11155b801561534f575067ffffffffffffffff8711155b15156153a5576040805160e560020a62461bcd02815260206004820152601260248201527f494e56414c49445f4b4559535f434f554e540000000000000000000000000000604482015290519081900360640190fd5b60408051603080825260608201909252906020820161060080388339019050509150508787015b8881111561550d576153e98b8b600019840163ffffffff61528016565b9450600185015460801c603083015284546020830152868110156154435761541c8b8b6000198a0163ffffffff61528016565b9350600092505b600583101561543f578284015483860155600183019250615423565b8394505b600092505b600583101561546257600083860155600183019250615448565b600187039650600181039050897fea4b75aaf57196f73d338cadf79ecd0a437902e2dd0d2c4c2cf3ea71b8ab27b9836040518080602001828103825283818151815260200191508051906020019080838360005b838110156154ce5781810151838201526020016154b6565b50505050905090810190601f1680156154fb5780820380516001836020036101000a031916815260200191505b509250505060405180910390a26153cc565b50949998505050505050505050565b80151561187b576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a038116151561187b576040805160e560020a62461bcd02815260206004820152600c60248201527f5a45524f5f414444524553530000000000000000000000000000000000000000604482015290519081900360640190fd5b6156037f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a68263ffffffff613d5616565b6040805182815290517ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9181900360200190a150565b6000806000806040516020818751602089018a5afa9250600083111561565e57805191505b50909590945092505050565b6000806040516020818551602087016000895af160008111156156ae573d801561569b57602081146156a4576156ac565b600193506156ac565b600183511493505b505b5090949350505050565b60008060006156c56159e2565b6156cd6159e2565b6156d6866131fa565b91506156e186613eba565b90506156f482600163ffffffff612fda16565b945061570782600363ffffffff612fda16565b935061571a81600263ffffffff612fda16565b925083831015801561572c5750848410155b151561573457fe5b50509193909250565b6000805b828210156127aa5761575685858486036157ae565b9050801515615764576127aa565b90810190615741565b604080516001808252818301909252606091602080830190803883390190505090508181600081518110151561579f57fe5b60209081029091010152919050565b8251600090600019828080808715156157ca57600096506159ad565b600092505b89518310156158885788838151811015156157e657fe5b906020019060200201518a848151811015156157fe57fe5b60209081029091010151106158125761587d565b898381518110151561582057fe5b906020019060200201518511156158575782955060019350898381518110151561584657fe5b90602001906020020151945061587d565b898381518110151561586557fe5b9060200190602002015185141561587d576001840193505b8260010192506157cf565b83151561589857600096506159ad565b50600019905060005b89518110156159485788818151811015156158b857fe5b906020019060200201518a828151811015156158d057fe5b60209081029091010151106158e457615940565b848a828151811015156158f357fe5b906020019060200201511180156159205750818a8281518110151561591457fe5b90602001906020020151105b1561594057898181518110151561593357fe5b9060200190602002015191505b6001016158a1565b61598b600185116159595788615963565b61596389866159ba565b86615985858d8b81518110151561597657fe5b906020019060200201516131d2565b036131d2565b9650868a8781518110151561599c57fe5b602090810290910101805190910190525b5050505050509392505050565b600082156159d95781600184038115156159d057fe5b046001016118d3565b50600092915050565b60408051602081019091526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615a355782800160ff19823516178555615a62565b82800160010185558215615a62579182015b82811115615a62578235825591602001919060010190615a47565b50610f3492610fd79250905b80821115610f345760008155600101615a6e560078523850fdd761612f46e844cf5a16bda6b3151d6ae961fd7e8e7b92bfbca7f86f5220989faafdc182d508d697678366f4e831f5f56166ad69bfc253fc548fb1bb75b874360e0bfd87f964eadd8276d8efb7c942134fc329b513032d0803e0c6947f955eec7e1f626bee3afd2aa47b5de04ddcdd3fe78dc8838213015ef58dfdeb2b7ad4d8ce5610cfb46470f03b14c197c2b751077c70209c5d0139f7c79ee9a165627a7a723058204284954a78ab82fb9b5f5ba2ae9a69bdbe628d3406e5d98203acbe5ded2040b30029