- Contract name:
- StakingHbbft
- Optimization enabled
- true
- Compiler version
- v0.8.25+commit.b61c2a91
- Optimization runs
- 800
- Verified at
- 2025-02-04 01:31:33.698058Z
contracts/StakingHbbft.sol
// SPDX-License-Identifier: Apache 2.0pragma solidity =0.8.25;import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";import { IBlockRewardHbbft } from "./interfaces/IBlockRewardHbbft.sol";import { IStakingHbbft } from "./interfaces/IStakingHbbft.sol";import { IValidatorSetHbbft } from "./interfaces/IValidatorSetHbbft.sol";import { IBonusScoreSystem } from "./interfaces/IBonusScoreSystem.sol";import { Unauthorized, ZeroAddress, ZeroGasPrice } from "./lib/Errors.sol";import { TransferUtils } from "./utils/TransferUtils.sol";import { ValueGuards } from "./lib/ValueGuards.sol";/// @dev Implements staking and withdrawal logic.// slither-disable-start unused-returncontract StakingHbbft is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable, IStakingHbbft, ValueGuards { using EnumerableSet for EnumerableSet.AddressSet; EnumerableSet.AddressSet private _pools; EnumerableSet.AddressSet private _poolsInactive; EnumerableSet.AddressSet private _poolsToBeRemoved; address[] private _poolsToBeElected; uint256[] private _poolsLikelihood; uint256 private _poolsLikelihoodSum; mapping(address => EnumerableSet.AddressSet) private _poolDelegators; mapping(address => EnumerableSet.AddressSet) private _poolDelegatorsInactive; mapping(address => mapping(address => mapping(uint256 => uint256))) private _stakeAmountByEpoch; /// @dev The limit of the minimum candidate stake (CANDIDATE_MIN_STAKE). uint256 public candidateMinStake; /// @dev The limit of the minimum delegator stake (DELEGATOR_MIN_STAKE). uint256 public delegatorMinStake; /// @dev current limit of how many funds can /// be staked on a single validator. uint256 public maxStakeAmount; /// @dev The current amount of staking coins ordered for withdrawal from the specified /// pool by the specified staker. Used by the `orderWithdraw`, `claimOrderedWithdraw` and other functions. /// The first parameter is the pool staking address, the second one is the staker address. mapping(address => mapping(address => uint256)) public orderedWithdrawAmount; /// @dev The current total amount of staking coins ordered for withdrawal from /// the specified pool by all of its stakers. Pool staking address is accepted as a parameter. mapping(address => uint256) public orderedWithdrawAmountTotal; /// @dev The number of the staking epoch during which the specified staker ordered /// the latest withdraw from the specified pool. Used by the `claimOrderedWithdraw` function /// to allow the ordered amount to be claimed only in future staking epochs. The first parameter /// is the pool staking address, the second one is the staker address. mapping(address => mapping(address => uint256)) public orderWithdrawEpoch; /// @dev The pool's index in the array returned by the `getPoolsToBeElected` getter. /// Used by the `_deletePoolToBeElected` and `_isPoolToBeElected` internal functions. /// The pool staking address is accepted as a parameter. /// If the value is zero, it may mean the array doesn't contain the address. /// Check the address is in the array using the `getPoolsToBeElected` getter. mapping(address => uint256) public poolToBeElectedIndex; /// @dev The amount of coins currently staked into the specified pool by the specified /// staker. Doesn't include the amount ordered for withdrawal. /// The first parameter is the pool staking address, the second one is the staker address. mapping(address => mapping(address => uint256)) public stakeAmount; /// @dev The duration period (in blocks) at the end of staking epoch during which /// participants are not allowed to stake/withdraw/order/claim their staking coins. uint256 public stakingWithdrawDisallowPeriod; /// @dev The serial number of the current staking epoch. uint256 public stakingEpoch; /// @dev The fixed duration of each staking epoch before KeyGen starts i.e. /// before the upcoming ("pending") validators are selected. uint256 public stakingFixedEpochDuration; /// @dev Length of the timeframe in seconds for the transition to the new validator set. uint256 public stakingTransitionTimeframeLength; /// @dev The timestamp of the last block of the the previous epoch. /// The timestamp of the current epoch must be '>=' than this. uint256 public stakingEpochStartTime; /// @dev the blocknumber of the first block in this epoch. /// this is mainly used for a historic lookup in the key gen history to read out the /// ACKS and PARTS so a client is able to verify an epoch, even in the case that /// the transition to the next epoch has already started, /// and the information of the old keys is not available anymore. uint256 public stakingEpochStartBlock; /// @dev the extra time window pending validators have to write /// to write their honey badger key shares. /// this value is increased in response to a failed key generation event, /// if one or more validators miss out writing their key shares. uint256 public currentKeyGenExtraTimeWindow; /// @dev Returns the total amount of staking coins currently staked into the specified pool. /// Doesn't include the amount ordered for withdrawal. /// The pool staking address is accepted as a parameter. mapping(address => uint256) public stakeAmountTotal; /// @dev Returns the total amount of staking coins currently staked on all pools. /// Doesn't include the amount ordered for withdrawal. uint256 public totalStakedAmount; /// @dev The address of the `ValidatorSetHbbft` contract. IValidatorSetHbbft public validatorSetContract; struct PoolInfo { bytes publicKey; bytes16 internetAddress; bytes2 port; } mapping(address => PoolInfo) public poolInfo; mapping(address => bool) public abandonedAndRemoved; /// @dev The total amount staked into the specified pool (staking address) /// before the specified staking epoch. Filled by the `_snapshotPoolStakeAmounts` function. mapping(uint256 => mapping(address => uint256)) public snapshotPoolTotalStakeAmount; /// @dev The validator's amount staked into the specified pool (staking address) /// before the specified staking epoch. Filled by the `_snapshotPoolStakeAmounts` function. mapping(uint256 => mapping(address => uint256)) public snapshotPoolValidatorStakeAmount; /// @dev The delegator's staked amount snapshot for specified epoch /// pool => delegator => epoch => stake amount mapping(address => mapping(address => mapping(uint256 => uint256))) internal _delegatorStakeSnapshot; /// @dev Number of last epoch when stake snapshot was taken. pool => delegator => epoch mapping(address => mapping(address => uint256)) internal _stakeSnapshotLastEpoch; IBonusScoreSystem public bonusScoreContract; /// @dev Address of node operator for specified pool. mapping(address => address) public poolNodeOperator; /// @dev Node operator share percent of total pool rewards. mapping(address => uint256) public poolNodeOperatorShare; /// @dev The epoch number in which the operator's address can be changed. mapping(address => uint256) public poolNodeOperatorLastChangeEpoch; // ============================================== Constants ======================================================= /// @dev The max number of candidates (including validators). This limit was determined through stress testing. uint256 public constant MAX_CANDIDATES = 3000; uint256 public constant MAX_NODE_OPERATOR_SHARE_PERCENT = 2000; uint256 public constant PERCENT_DENOMINATOR = 10000; // ================================================ Events ======================================================== /// @dev Emitted by the `claimOrderedWithdraw` function to signal the staker withdrew the specified /// amount of requested coins from the specified pool during the specified staking epoch. /// @param fromPoolStakingAddress The pool from which the `staker` withdrew the `amount`. /// @param staker The address of the staker that withdrew the `amount`. /// @param stakingEpoch The serial number of the staking epoch during which the claim was made. /// @param amount The withdrawal amount. event ClaimedOrderedWithdrawal( address indexed fromPoolStakingAddress, address indexed staker, uint256 indexed stakingEpoch, uint256 amount ); /// @dev Emitted by the `moveStake` function to signal the staker moved the specified /// amount of stake from one pool to another during the specified staking epoch. /// @param fromPoolStakingAddress The pool from which the `staker` moved the stake. /// @param toPoolStakingAddress The destination pool where the `staker` moved the stake. /// @param staker The address of the staker who moved the `amount`. /// @param stakingEpoch The serial number of the staking epoch during which the `amount` was moved. /// @param amount The stake amount which was moved. event MovedStake( address fromPoolStakingAddress, address indexed toPoolStakingAddress, address indexed staker, uint256 indexed stakingEpoch, uint256 amount ); /// @dev Emitted by the `orderWithdraw` function to signal the staker ordered the withdrawal of the /// specified amount of their stake from the specified pool during the specified staking epoch. /// @param fromPoolStakingAddress The pool from which the `staker` ordered a withdrawal of the `amount`. /// @param staker The address of the staker that ordered the withdrawal of the `amount`. /// @param stakingEpoch The serial number of the staking epoch during which the order was made. /// @param amount The ordered withdrawal amount. Can be either positive or negative. /// See the `orderWithdraw` function. event OrderedWithdrawal( address indexed fromPoolStakingAddress, address indexed staker, uint256 indexed stakingEpoch, int256 amount ); /// @dev Emitted by the `stake` function to signal the staker placed a stake of the specified /// amount for the specified pool during the specified staking epoch. /// @param toPoolStakingAddress The pool in which the `staker` placed the stake. /// @param staker The address of the staker that placed the stake. /// @param stakingEpoch The serial number of the staking epoch during which the stake was made. /// @param amount The stake amount. event PlacedStake( address indexed toPoolStakingAddress, address indexed staker, uint256 indexed stakingEpoch, uint256 amount ); /// @dev Emitted by the `withdraw` function to signal the staker withdrew the specified /// amount of a stake from the specified pool during the specified staking epoch. /// @param fromPoolStakingAddress The pool from which the `staker` withdrew the `amount`. /// @param staker The address of staker that withdrew the `amount`. /// @param stakingEpoch The serial number of the staking epoch during which the withdrawal was made. /// @param amount The withdrawal amount. event WithdrewStake( address indexed fromPoolStakingAddress, address indexed staker, uint256 indexed stakingEpoch, uint256 amount ); event GatherAbandonedStakes(address indexed caller, address indexed stakingAddress, uint256 gatheredFunds); event RecoverAbandonedStakes(address indexed caller, uint256 reinsertShare, uint256 governanceShare); /// @dev Emitted by the `restake` function to signal the epoch reward was restaked to the pool. /// @param poolStakingAddress The pool for which the restake will be performed. /// @param stakingEpoch The serial number of the staking epoch during which the restake was made. /// @param validatorReward The amount of tokens restaked for the validator. /// @param delegatorsReward The total amount of tokens restaked for the `poolStakingAddress` delegators. event RestakeReward( address indexed poolStakingAddress, uint256 indexed stakingEpoch, uint256 validatorReward, uint256 delegatorsReward ); /// @dev Emitted by the `_setNodeOperator` function. /// @param poolStakingAddress The pool for which node operator was configured. /// @param nodeOperatorAddress Address of node operator address related to `poolStakingAddress`. /// @param operatorShare Node operator share percent. event SetNodeOperator( address indexed poolStakingAddress, address indexed nodeOperatorAddress, uint256 operatorShare ); /** * @dev Emitted when the minimum stake for a delegator is updated. * @param minStake The new minimum stake value. */ event SetDelegatorMinStake(uint256 minStake); // ============================================== Errors ======================================================= error CannotClaimWithdrawOrderYet(address pool, address staker); error OnlyOncePerEpoch(uint256 _epoch); error MaxPoolsCountExceeded(); error MaxAllowedWithdrawExceeded(uint256 allowed, uint256 desired); error NoStakesToRecover(); error NotPayable(); error PoolAbandoned(address pool); error PoolCannotBeRemoved(address pool); error PoolEmpty(address pool); error PoolNotExist(address pool); error PoolStakeLimitExceeded(address pool, address delegator); error InitialStakingPoolsListEmpty(); error InsufficientStakeAmount(address pool, address delegator); error InvalidFixedEpochDuration(); error InvalidInitialStakeAmount(uint256 candidateStake, uint256 delegatorStake); error InvalidIpAddressesCount(); error InvalidMaxStakeAmount(); error InvalidMoveStakePoolsAddress(); error InvalidOrderWithdrawAmount(address pool, address delegator, int256 amount); error InvalidPublicKeysCount(); error InvalidStakingTransitionTimeframe(); error InvalidStakingFixedEpochDuration(); error InvalidTransitionTimeFrame(); error InvalidWithdrawAmount(address pool, address delegator, uint256 amount); error InvalidNodeOperatorConfiguration(address _operator, uint256 _share); error InvalidNodeOperatorShare(uint256 _share); error WithdrawNotAllowed(); error ZeroWidthrawAmount(); error ZeroWidthrawDisallowPeriod(); // ============================================== Modifiers ======================================================= /// @dev Ensures the transaction gas price is not zero. modifier gasPriceIsValid() { if (tx.gasprice == 0) { revert ZeroGasPrice(); } _; } /// @dev Ensures the caller is the ValidatorSetHbbft contract address. modifier onlyValidatorSetContract() virtual { if (msg.sender != address(validatorSetContract)) { revert Unauthorized(); } _; } modifier onlyBlockRewardContract() { if (msg.sender != validatorSetContract.blockRewardContract()) { revert Unauthorized(); } _; } modifier onlyBonusScoreContract() { if (msg.sender != address(bonusScoreContract)) { revert Unauthorized(); } _; } // =============================================== Setters ======================================================== /// @custom:oz-upgrades-unsafe-allow constructor constructor() { // Prevents initialization of implementation contract _disableInitializers(); } /// @dev Fallback function. Prevents direct sending native coins to this contract. receive() external payable { revert NotPayable(); } /// @dev Initializes the network parameters. /// Can only be called by the constructor of the `InitializerHbbft` contract or owner. /// @param _contractOwner The address of the contract owner /// @param stakingParams stores other parameters due to stack too deep issue /// _validatorSetContract The address of the `ValidatorSetHbbft` contract. /// _initialStakingAddresses The array of initial validators' staking addresses. /// _delegatorMinStake The minimum allowed amount of delegator stake in Wei. /// _candidateMinStake The minimum allowed amount of candidate/validator stake in Wei. /// _stakingFixedEpochDuration The fixed duration of each epoch before keyGen starts. /// _stakingTransitionTimeframeLength Length of the timeframe in seconds for the transition /// to the new validator set. /// _stakingWithdrawDisallowPeriod The duration period at the end of a staking epoch /// during which participants cannot stake/withdraw/order/claim their staking coins function initialize( address _contractOwner, StakingParams calldata stakingParams, bytes32[] calldata _publicKeys, bytes16[] calldata _internetAddresses ) external initializer { if (_contractOwner == address(0)) { revert ZeroAddress(); } _validateStakingParams(stakingParams); if (stakingParams._initialStakingAddresses.length * 2 != _publicKeys.length) { revert InvalidPublicKeysCount(); } if (stakingParams._initialStakingAddresses.length != _internetAddresses.length) { revert InvalidIpAddressesCount(); } __Ownable_init(_contractOwner); __ReentrancyGuard_init(); validatorSetContract = IValidatorSetHbbft(stakingParams._validatorSetContract); bonusScoreContract = IBonusScoreSystem(stakingParams._bonusScoreContract); address[] calldata initStakingAddresses = stakingParams._initialStakingAddresses; for (uint256 i = 0; i < initStakingAddresses.length; ++i) { if (initStakingAddresses[i] == address(0)) { revert ZeroAddress(); } _addPoolActive(initStakingAddresses[i], false); _addPoolToBeRemoved(initStakingAddresses[i]); poolInfo[initStakingAddresses[i]].publicKey = abi.encodePacked(_publicKeys[i * 2], _publicKeys[i * 2 + 1]); poolInfo[initStakingAddresses[i]].internetAddress = _internetAddresses[i]; } uint256[] memory delegatorMinStakeAllowedParams = new uint256[](5); delegatorMinStakeAllowedParams[0] = 50 ether; delegatorMinStakeAllowedParams[1] = 100 ether; delegatorMinStakeAllowedParams[2] = 150 ether; delegatorMinStakeAllowedParams[3] = 200 ether; delegatorMinStakeAllowedParams[4] = 250 ether; __initAllowedChangeableParameter( this.setDelegatorMinStake.selector, this.delegatorMinStake.selector, delegatorMinStakeAllowedParams ); delegatorMinStake = stakingParams._delegatorMinStake; candidateMinStake = stakingParams._candidateMinStake; maxStakeAmount = stakingParams._maxStake; stakingFixedEpochDuration = stakingParams._stakingFixedEpochDuration; stakingWithdrawDisallowPeriod = stakingParams._stakingWithdrawDisallowPeriod; // note: this might be still 0 when created in the genesis block. stakingEpochStartTime = block.timestamp; stakingTransitionTimeframeLength = stakingParams._stakingTransitionTimeframeLength; } /** * @dev Sets the minimum stake required for delegators. * @param _minStake The new minimum stake amount. * Requirements: * - Only the contract owner can call this function. * - The stake amount must be within the allowed range. * * Emits a {SetDelegatorMinStake} event. */ function setDelegatorMinStake(uint256 _minStake) external onlyOwner withinAllowedRange(_minStake) { delegatorMinStake = _minStake; emit SetDelegatorMinStake(_minStake); } /// @dev Sets the timetamp of the current epoch's last block as the start time of the upcoming staking epoch. /// Called by the `ValidatorSetHbbft.newValidatorSet` function at the last block of a staking epoch. /// @param _timestamp The starting time of the very first block in the upcoming staking epoch. function setStakingEpochStartTime(uint256 _timestamp) external onlyValidatorSetContract { stakingEpochStartTime = _timestamp; stakingEpochStartBlock = block.number; } /// @dev set's the validators ip address. /// this function can only be called by the validator Set contract. /// @param _validatorAddress address if the validator. (mining address) /// @param _ip IPV4 address of a running Node Software or Proxy. function setValidatorInternetAddress( address _validatorAddress, bytes16 _ip, bytes2 _port ) external onlyValidatorSetContract { poolInfo[_validatorAddress].internetAddress = _ip; poolInfo[_validatorAddress].port = _port; } /// @dev Increments the serial number of the current staking epoch. /// Called by the `ValidatorSetHbbft.newValidatorSet` at the last block of the finished staking epoch. function incrementStakingEpoch() external onlyValidatorSetContract { stakingEpoch++; currentKeyGenExtraTimeWindow = 0; } /// @dev Notifies hbbft staking contract that the /// key generation has failed, and a new round /// of keygeneration starts. function notifyKeyGenFailed() public onlyValidatorSetContract { // we allow a extra time window for the current key generation // equal in the size of the usual transition timeframe. currentKeyGenExtraTimeWindow += stakingTransitionTimeframeLength; } /// @dev Notifies hbbft staking contract about a detected /// network offline time. /// if there is no handling for this, /// validators got chosen outside the transition timewindow /// and get banned immediatly, since they never got their chance /// to write their keys. /// more about: https://github.com/DMDcoin/hbbft-posdao-contracts/issues/96 function notifyNetworkOfftimeDetected(uint256 detectedOfflineTime) public onlyValidatorSetContract { currentKeyGenExtraTimeWindow = currentKeyGenExtraTimeWindow + detectedOfflineTime + stakingTransitionTimeframeLength; } /// @dev Notifies hbbft staking contract that a validator /// asociated with the given `_stakingAddress` became /// available again and can be put on to the list /// of available nodes again. function notifyAvailability(address _stakingAddress) public onlyValidatorSetContract { if (stakeAmount[_stakingAddress][_stakingAddress] >= candidateMinStake) { _addPoolActive(_stakingAddress, true); _setLikelihood(_stakingAddress); } } /// @dev Adds a new candidate's pool to the list of active pools (see the `getPools` getter) and /// moves the specified amount of staking coins from the candidate's staking address /// to the candidate's pool. A participant calls this function using their staking address when /// they want to create a pool. This is a wrapper for the `stake` function. /// @param _miningAddress The mining address of the candidate. The mining address is bound to the staking address /// (msg.sender). This address cannot be equal to `msg.sender`. /// @param _nodeOperatorAddress Address of node operator, will receive `_operatorShare` of epoch rewards. /// @param _operatorShare Percent of epoch rewards to send to `_nodeOperatorAddress`. /// Integer value with 2 decimal places, e.g. 1% = 100, 10.25% = 1025. function addPool( address _miningAddress, address _nodeOperatorAddress, uint256 _operatorShare, bytes calldata _publicKey, bytes16 _ip ) external payable gasPriceIsValid { address stakingAddress = msg.sender; uint256 amount = msg.value; validatorSetContract.setStakingAddress(_miningAddress, stakingAddress); // The staking address and the staker are the same. poolInfo[stakingAddress].publicKey = _publicKey; poolInfo[stakingAddress].internetAddress = _ip; _setNodeOperator(stakingAddress, _nodeOperatorAddress, _operatorShare); _stake(stakingAddress, stakingAddress, amount); emit PlacedStake(stakingAddress, stakingAddress, stakingEpoch, amount); } /// @dev Removes the candidate's or validator's pool from the `pools` array (a list of active pools which /// can be retrieved by the `getPools` getter). When a candidate or validator wants to remove their pool, /// they should call this function from their staking address. function removeMyPool() external gasPriceIsValid { address stakingAddress = msg.sender; address miningAddress = validatorSetContract.miningByStakingAddress(stakingAddress); // initial validator cannot remove their pool during the initial staking epoch if (stakingEpoch == 0 && validatorSetContract.isValidator(miningAddress)) { revert PoolCannotBeRemoved(stakingAddress); } _removePool(stakingAddress); } /// @dev set's the pool info for a specific ethereum address. /// @param _publicKey public key of the (future) signing address. /// @param _ip (optional) IPV4 address of a running Node Software or Proxy. /// @param _port (optional) port of IPv4 address of a running Node Software or Proxy. /// Stores the supplied data for a staking (pool) address. /// This function is external available without security checks, /// since no array operations are used in the implementation, /// this allows the flexibility to set the pool information before /// adding the stake to the pool. function setPoolInfo(bytes calldata _publicKey, bytes16 _ip, bytes2 _port) external { poolInfo[msg.sender].publicKey = _publicKey; poolInfo[msg.sender].internetAddress = _ip; poolInfo[msg.sender].port = _port; } /// @dev Set's the pool node operator configuration for a specific ethereum address. /// @param _operatorAddress Node operator address. /// @param _operatorShare Node operator reward share percent. function setNodeOperator(address _operatorAddress, uint256 _operatorShare) external { if (validatorSetContract.miningByStakingAddress(msg.sender) == address(0)) { revert PoolNotExist(msg.sender); } _setNodeOperator(msg.sender, _operatorAddress, _operatorShare); } /// @dev Removes a specified pool from the `pools` array (a list of active pools which can be retrieved by the /// `getPools` getter). Called by the `ValidatorSetHbbft._removeMaliciousValidator` internal function, /// and the `ValidatorSetHbbft.handleFailedKeyGeneration` function /// when a pool must be removed by the algorithm. /// @param _stakingAddress The staking address of the pool to be removed. function removePool(address _stakingAddress) external onlyValidatorSetContract { _removePool(_stakingAddress); } /// @dev Removes pools which are in the `_poolsToBeRemoved` internal array from the `pools` array. /// Called by the `ValidatorSetHbbft.newValidatorSet` function when a pool must be removed by the algorithm. function removePools() external onlyValidatorSetContract { address[] memory poolsToRemove = _poolsToBeRemoved.values(); for (uint256 i = 0; i < poolsToRemove.length; i++) { _removePool(poolsToRemove[i]); } } /// @dev Moves the specified amount of staking coins from the staker's address to the staking address of /// the specified pool. Actually, the amount is stored in a balance of this StakingHbbft contract. /// A staker calls this function when they want to make a stake into a pool. /// @param _toPoolStakingAddress The staking address of the pool where the coins should be staked. function stake(address _toPoolStakingAddress) external payable gasPriceIsValid { address staker = msg.sender; uint256 amount = msg.value; _stake(_toPoolStakingAddress, staker, amount); emit PlacedStake(_toPoolStakingAddress, staker, stakingEpoch, amount); } /// @dev Moves the specified amount of staking coins from the staking address of /// the specified pool to the staker's address. A staker calls this function when they want to withdraw /// their coins. /// @param _fromPoolStakingAddress The staking address of the pool from which the coins should be withdrawn. /// @param _amount The amount of coins to be withdrawn. The amount cannot exceed the value returned /// by the `maxWithdrawAllowed` getter. function withdraw(address _fromPoolStakingAddress, uint256 _amount) external gasPriceIsValid nonReentrant { address payable staker = payable(msg.sender); _withdraw(_fromPoolStakingAddress, staker, _amount); TransferUtils.transferNative(staker, _amount); emit WithdrewStake(_fromPoolStakingAddress, staker, stakingEpoch, _amount); } /// @dev Moves staking coins from one pool to another. A staker calls this function when they want /// to move their coins from one pool to another without withdrawing their coins. /// @param _fromPoolStakingAddress The staking address of the source pool. /// @param _toPoolStakingAddress The staking address of the target pool. /// @param _amount The amount of staking coins to be moved. The amount cannot exceed the value returned /// by the `maxWithdrawAllowed` getter. function moveStake( address _fromPoolStakingAddress, address _toPoolStakingAddress, uint256 _amount ) external gasPriceIsValid { if (_fromPoolStakingAddress == _toPoolStakingAddress) { revert InvalidMoveStakePoolsAddress(); } address staker = msg.sender; _withdraw(_fromPoolStakingAddress, staker, _amount); _stake(_toPoolStakingAddress, staker, _amount); emit MovedStake(_fromPoolStakingAddress, _toPoolStakingAddress, staker, stakingEpoch, _amount); } function restake( address _poolStakingAddress, uint256 _validatorMinRewardPercent ) external payable onlyBlockRewardContract { // msg.value is a pool reward if (msg.value == 0) { return; } uint256 poolReward = msg.value; uint256 totalStake = snapshotPoolTotalStakeAmount[stakingEpoch][_poolStakingAddress]; PoolRewardShares memory shares = _splitPoolReward(_poolStakingAddress, poolReward, _validatorMinRewardPercent); address[] memory delegators = poolDelegators(_poolStakingAddress); for (uint256 i = 0; i < delegators.length; ++i) { uint256 delegatorReward = (shares.delegatorsShare * _getDelegatorStake(stakingEpoch, _poolStakingAddress, delegators[i])) / totalStake; stakeAmount[_poolStakingAddress][delegators[i]] += delegatorReward; _stakeAmountByEpoch[_poolStakingAddress][delegators[i]][stakingEpoch] += delegatorReward; } if (shares.nodeOperatorShare != 0) { _rewardNodeOperator(_poolStakingAddress, shares.nodeOperatorShare); } stakeAmount[_poolStakingAddress][_poolStakingAddress] += shares.validatorShare; stakeAmountTotal[_poolStakingAddress] += poolReward; totalStakedAmount += poolReward; _setLikelihood(_poolStakingAddress); emit RestakeReward( _poolStakingAddress, stakingEpoch, shares.validatorShare, poolReward - shares.validatorShare ); } /// @dev Orders coins withdrawal from the staking address of the specified pool to the /// staker's address. The requested coins can be claimed after the current staking epoch is complete using /// the `claimOrderedWithdraw` function. /// @param _poolStakingAddress The staking address of the pool from which the amount will be withdrawn. /// @param _amount The amount to be withdrawn. A positive value means the staker wants to either set or /// increase their withdrawal amount. A negative value means the staker wants to decrease a /// withdrawal amount that was previously set. The amount cannot exceed the value returned by the /// `maxWithdrawOrderAllowed` getter. function orderWithdraw(address _poolStakingAddress, int256 _amount) external gasPriceIsValid { if (_poolStakingAddress == address(0)) { revert ZeroAddress(); } if (_amount == 0) { revert ZeroWidthrawAmount(); } address staker = msg.sender; if (!areStakeAndWithdrawAllowed()) { revert WithdrawNotAllowed(); } uint256 newOrderedAmount = orderedWithdrawAmount[_poolStakingAddress][staker]; uint256 newOrderedAmountTotal = orderedWithdrawAmountTotal[_poolStakingAddress]; uint256 newStakeAmount = stakeAmount[_poolStakingAddress][staker]; uint256 newStakeAmountTotal = stakeAmountTotal[_poolStakingAddress]; if (_amount > 0) { uint256 amount = uint256(_amount); // How much can `staker` order for withdrawal from `_poolStakingAddress` at the moment? uint256 allowedWithdraw = maxWithdrawOrderAllowed(_poolStakingAddress, staker); if (amount > allowedWithdraw) { revert MaxAllowedWithdrawExceeded(allowedWithdraw, amount); } newOrderedAmount = newOrderedAmount + amount; newOrderedAmountTotal = newOrderedAmountTotal + amount; newStakeAmount = newStakeAmount - amount; newStakeAmountTotal = newStakeAmountTotal - amount; totalStakedAmount -= amount; orderWithdrawEpoch[_poolStakingAddress][staker] = stakingEpoch; } else { uint256 amount = uint256(-_amount); newOrderedAmount = newOrderedAmount - amount; newOrderedAmountTotal = newOrderedAmountTotal - amount; newStakeAmount = newStakeAmount + amount; newStakeAmountTotal = newStakeAmountTotal + amount; totalStakedAmount += amount; } orderedWithdrawAmount[_poolStakingAddress][staker] = newOrderedAmount; orderedWithdrawAmountTotal[_poolStakingAddress] = newOrderedAmountTotal; stakeAmount[_poolStakingAddress][staker] = newStakeAmount; stakeAmountTotal[_poolStakingAddress] = newStakeAmountTotal; if (staker == _poolStakingAddress) { // The amount to be withdrawn must be the whole staked amount or // must not exceed the diff between the entire amount and `candidateMinStake` if (newStakeAmount != 0 && newStakeAmount < candidateMinStake) { revert InvalidOrderWithdrawAmount(_poolStakingAddress, staker, _amount); } if (_amount > 0) { // if the validator orders the `_amount` for withdrawal if (newStakeAmount == 0) { // If the validator orders their entire stake, // mark their pool as `to be removed` _addPoolToBeRemoved(_poolStakingAddress); } } else { // If the validator wants to reduce withdrawal value, // add their pool as `active` if it hasn't been already done. _addPoolActive(_poolStakingAddress, true); } } else { // The amount to be withdrawn must be the whole staked amount or // must not exceed the diff between the entire amount and `delegatorMinStake` if (newStakeAmount != 0 && newStakeAmount < delegatorMinStake) { revert InvalidOrderWithdrawAmount(_poolStakingAddress, staker, _amount); } if (_amount > 0) { // if the delegator orders the `_amount` for withdrawal if (newStakeAmount == 0) { // If the delegator orders their entire stake, // remove the delegator from delegator list of the pool _removePoolDelegator(_poolStakingAddress, staker); } } else { // If the delegator wants to reduce withdrawal value, // add them to delegator list of the pool if it hasn't already done _addPoolDelegator(_poolStakingAddress, staker); } // Remember stake movement to use it later in the `claimReward` function // _snapshotDelegatorStake(_poolStakingAddress, staker); } _setLikelihood(_poolStakingAddress); emit OrderedWithdrawal(_poolStakingAddress, staker, stakingEpoch, _amount); } /// @dev Withdraws the staking coins from the specified pool ordered during the previous staking epochs with /// the `orderWithdraw` function. The ordered amount can be retrieved by the `orderedWithdrawAmount` getter. /// @param _poolStakingAddress The staking address of the pool from which the ordered coins are withdrawn. function claimOrderedWithdraw(address _poolStakingAddress) external gasPriceIsValid nonReentrant { address payable staker = payable(msg.sender); if (stakingEpoch <= orderWithdrawEpoch[_poolStakingAddress][staker]) { revert CannotClaimWithdrawOrderYet(_poolStakingAddress, staker); } if (!areStakeAndWithdrawAllowed()) { revert WithdrawNotAllowed(); } uint256 claimAmount = orderedWithdrawAmount[_poolStakingAddress][staker]; if (claimAmount == 0) { revert ZeroWidthrawAmount(); } orderedWithdrawAmount[_poolStakingAddress][staker] = 0; orderedWithdrawAmountTotal[_poolStakingAddress] = orderedWithdrawAmountTotal[_poolStakingAddress] - claimAmount; if (stakeAmount[_poolStakingAddress][staker] == 0) { _withdrawCheckPool(_poolStakingAddress, staker); } TransferUtils.transferNative(staker, claimAmount); emit ClaimedOrderedWithdrawal(_poolStakingAddress, staker, stakingEpoch, claimAmount); } /// @dev Distribute abandoned stakes among Reinsert and Governance pots. /// 50% goes to reinsert and 50% to governance pot. /// Coins are considered abandoned if they were staked on a validator inactive for 10 years. function recoverAbandonedStakes() external gasPriceIsValid { uint256 totalAbandonedAmount = 0; address[] memory inactivePools = _poolsInactive.values(); if (inactivePools.length == 0) { revert NoStakesToRecover(); } for (uint256 i = 0; i < inactivePools.length; ++i) { address stakingAddress = inactivePools[i]; if (_isPoolEmpty(stakingAddress) || !validatorSetContract.isValidatorAbandoned(stakingAddress)) { continue; } _poolsInactive.remove(stakingAddress); abandonedAndRemoved[stakingAddress] = true; uint256 gatheredPerStakingAddress = stakeAmountTotal[stakingAddress]; stakeAmountTotal[stakingAddress] = 0; totalStakedAmount -= gatheredPerStakingAddress; address[] memory delegators = poolDelegators(stakingAddress); for (uint256 j = 0; j < delegators.length; ++j) { address delegator = delegators[j]; stakeAmount[stakingAddress][delegator] = 0; _removePoolDelegator(stakingAddress, delegator); } totalAbandonedAmount += gatheredPerStakingAddress; emit GatherAbandonedStakes(msg.sender, stakingAddress, gatheredPerStakingAddress); } if (totalAbandonedAmount == 0) { revert NoStakesToRecover(); } uint256 governanceShare = totalAbandonedAmount / 2; uint256 reinsertShare = totalAbandonedAmount - governanceShare; IBlockRewardHbbft blockRewardHbbft = IBlockRewardHbbft(validatorSetContract.blockRewardContract()); address governanceAddress = blockRewardHbbft.getGovernanceAddress(); // slither-disable-next-line arbitrary-send-eth blockRewardHbbft.addToReinsertPot{ value: reinsertShare }(); TransferUtils.transferNative(governanceAddress, governanceShare); emit RecoverAbandonedStakes(msg.sender, reinsertShare, governanceShare); } /// @dev Makes snapshots of total amount staked into the specified pool /// before the specified staking epoch. Used by the `reward` function. /// @param _epoch The number of upcoming staking epoch. /// @param _stakingPool The staking address of the pool. function snapshotPoolStakeAmounts(uint256 _epoch, address _stakingPool) external onlyBlockRewardContract { if (snapshotPoolTotalStakeAmount[_epoch][_stakingPool] != 0) { return; } uint256 totalAmount = stakeAmountTotal[_stakingPool]; if (totalAmount == 0) { return; } snapshotPoolTotalStakeAmount[_epoch][_stakingPool] = totalAmount; snapshotPoolValidatorStakeAmount[_epoch][_stakingPool] = stakeAmount[_stakingPool][_stakingPool]; } function updatePoolLikelihood(address mining, uint256 validatorScore) external onlyBonusScoreContract { address stakingAddress = validatorSetContract.stakingByMiningAddress(mining); _updateLikelihood(stakingAddress, validatorScore); } // =============================================== Getters ======================================================== /// @dev Returns an array of the current active pools (the staking addresses of candidates and validators). /// The size of the array cannot exceed MAX_CANDIDATES. A pool can be added to this array with the `_addPoolActive` /// internal function which is called by the `stake` or `orderWithdraw` function. A pool is considered active /// if its address has at least the minimum stake and this stake is not ordered to be withdrawn. function getPools() external view returns (address[] memory) { return _pools.values(); } /// @dev Return the Public Key used by a Node to send targeted HBBFT Consensus Messages. /// @param _poolAddress The Pool Address to query the public key for. /// @return the public key for the given pool address. /// Note that the public key does not convert to the ethereum address of the pool address. /// The pool address is used for stacking, and not for signing HBBFT messages. function getPoolPublicKey(address _poolAddress) external view returns (bytes memory) { return poolInfo[_poolAddress].publicKey; } /// @dev Returns the registered IPv4 Address for the node. /// @param _poolAddress The Pool Address to query the IPv4Address for. /// @return IPv4 Address for the given pool address. function getPoolInternetAddress(address _poolAddress) external view returns (bytes16, bytes2) { return (poolInfo[_poolAddress].internetAddress, poolInfo[_poolAddress].port); } /// @dev Returns an array of the current inactive pools (the staking addresses of former candidates). /// A pool can be added to this array with the `_addPoolInactive` internal function which is called /// by `_removePool`. A pool is considered inactive if it is banned for some reason, if its address /// has zero stake, or if its entire stake is ordered to be withdrawn. function getPoolsInactive() external view returns (address[] memory) { return _poolsInactive.values(); } /// @dev Returns the array of stake amounts for each corresponding /// address in the `poolsToBeElected` array (see the `getPoolsToBeElected` getter) and a sum of these amounts. /// Used by the `ValidatorSetHbbft.newValidatorSet` function when randomly selecting new validators at the last /// block of a staking epoch. An array value is updated every time any staked amount is changed in this pool /// (see the `_setLikelihood` internal function). /// @return likelihoods `uint256[] likelihoods` - The array of the coefficients. The array length is always equal /// to the length of the `poolsToBeElected` array. /// `uint256 sum` - The total sum of the amounts. function getPoolsLikelihood() external view returns (uint256[] memory likelihoods, uint256 sum) { return (_poolsLikelihood, _poolsLikelihoodSum); } /// @dev Returns the list of pools (their staking addresses) which will participate in a new validator set /// selection process in the `ValidatorSetHbbft.newValidatorSet` function. This is an array of pools /// which will be considered as candidates when forming a new validator set (at the last block of a staking epoch). /// This array is kept updated by the `_addPoolToBeElected` and `_deletePoolToBeElected` internal functions. function getPoolsToBeElected() external view returns (address[] memory) { return _poolsToBeElected; } /// @dev Returns the list of pools (their staking addresses) which will be removed by the /// `ValidatorSetHbbft.newValidatorSet` function from the active `pools` array (at the last block /// of a staking epoch). This array is kept updated by the `_addPoolToBeRemoved` /// and `_deletePoolToBeRemoved` internal functions. A pool is added to this array when the pool's /// address withdraws (or orders) all of its own staking coins from the pool, inactivating the pool. function getPoolsToBeRemoved() external view returns (address[] memory) { return _poolsToBeRemoved.values(); } function getPoolValidatorStakeAmount(uint256 _epoch, address _stakingPool) external view returns (uint256) { return snapshotPoolValidatorStakeAmount[_epoch][_stakingPool]; } /// @dev Determines whether staking/withdrawal operations are allowed at the moment. /// Used by all staking/withdrawal functions. function areStakeAndWithdrawAllowed() public pure returns (bool) { //experimental change to always allow to stake withdraw. //see https://github.com/DMDcoin/hbbft-posdao-contracts/issues/14 for discussion. return true; // used for testing // if (stakingFixedEpochDuration == 0){ // return true; // } // uint256 currentTimestamp = block.timestamp; // uint256 allowedDuration = stakingFixedEpochDuration - stakingWithdrawDisallowPeriod; // return currentTimestamp - stakingEpochStartTime > allowedDuration; //TODO: should be < not <=? } /// @dev Returns a flag indicating whether a specified address is in the `pools` array. /// See the `getPools` getter. /// @param _stakingAddress The staking address of the pool. function isPoolActive(address _stakingAddress) public view returns (bool) { return _pools.contains(_stakingAddress); } /// @dev Returns a flag indicating whether a specified address is in the `_pools` or `poolsInactive` array. /// @param _stakingAddress The staking address of the pool. function isPoolValid(address _stakingAddress) public view returns (bool) { return _pools.contains(_stakingAddress) || _poolsInactive.contains(_stakingAddress); } /// @dev Returns the maximum amount which can be withdrawn from the specified pool by the specified staker /// at the moment. Used by the `withdraw` and `moveStake` functions. /// @param _poolStakingAddress The pool staking address from which the withdrawal will be made. /// @param _staker The staker address that is going to withdraw. function maxWithdrawAllowed(address _poolStakingAddress, address _staker) public view returns (uint256) { address miningAddress = validatorSetContract.miningByStakingAddress(_poolStakingAddress); if (!areStakeAndWithdrawAllowed() || abandonedAndRemoved[_poolStakingAddress]) { return 0; } uint256 canWithdraw = stakeAmount[_poolStakingAddress][_staker]; if (!validatorSetContract.isValidatorOrPending(miningAddress)) { // The pool is not a validator and is not going to become one, // so the staker can only withdraw staked amount minus already // ordered amount return canWithdraw; } // The pool is a validator (active or pending), so the staker can only // withdraw staked amount minus already ordered amount but // no more than the amount staked during the current staking epoch uint256 stakedDuringEpoch = stakeAmountByCurrentEpoch(_poolStakingAddress, _staker); if (canWithdraw > stakedDuringEpoch) { canWithdraw = stakedDuringEpoch; } return canWithdraw; } /// @dev Returns the maximum amount which can be ordered to be withdrawn from the specified pool by the /// specified staker at the moment. Used by the `orderWithdraw` function. /// @param _poolStakingAddress The pool staking address from which the withdrawal will be ordered. /// @param _staker The staker address that is going to order the withdrawal. function maxWithdrawOrderAllowed(address _poolStakingAddress, address _staker) public view returns (uint256) { address miningAddress = validatorSetContract.miningByStakingAddress(_poolStakingAddress); if (!areStakeAndWithdrawAllowed()) { return 0; } if (!validatorSetContract.isValidatorOrPending(miningAddress)) { // If the pool is a candidate (not an active validator and not pending one), // no one can order withdrawal from the `_poolStakingAddress`, but // anyone can withdraw immediately (see the `maxWithdrawAllowed` getter) return 0; } // If the pool is an active or pending validator, the staker can order withdrawal // up to their total staking amount minus an already ordered amount // minus an amount staked during the current staking epoch return stakeAmount[_poolStakingAddress][_staker] - stakeAmountByCurrentEpoch(_poolStakingAddress, _staker); } /// @dev Returns an array of the current active delegators of the specified pool. /// A delegator is considered active if they have staked into the specified /// pool and their stake is not ordered to be withdrawn. /// @param _poolStakingAddress The pool staking address. function poolDelegators(address _poolStakingAddress) public view returns (address[] memory) { return _poolDelegators[_poolStakingAddress].values(); } /// @dev Returns an array of the current inactive delegators of the specified pool. /// A delegator is considered inactive if their entire stake is ordered to be withdrawn /// but not yet claimed. /// @param _poolStakingAddress The pool staking address. function poolDelegatorsInactive(address _poolStakingAddress) external view returns (address[] memory) { return _poolDelegatorsInactive[_poolStakingAddress].values(); } /// @dev Returns the amount of staking coins staked into the specified pool by the specified staker /// during the current staking epoch (see the `stakingEpoch` getter). /// Used by the `stake`, `withdraw`, and `orderWithdraw` functions. /// @param _poolStakingAddress The pool staking address. /// @param _staker The staker's address. function stakeAmountByCurrentEpoch(address _poolStakingAddress, address _staker) public view returns (uint256) { return _stakeAmountByEpoch[_poolStakingAddress][_staker][stakingEpoch]; } /// @dev indicates the time when the new validatorset for the next epoch gets chosen. /// this is the start of a timeframe before the end of the epoch, /// that is long enough for the validators /// to create a new shared key. function startTimeOfNextPhaseTransition() public view returns (uint256) { return stakingEpochStartTime + stakingFixedEpochDuration - stakingTransitionTimeframeLength; } /// @dev Returns an indicative time of the last block of the current staking epoch before key generation starts. function stakingFixedEpochEndTime() public view returns (uint256) { uint256 startTime = stakingEpochStartTime; return startTime + stakingFixedEpochDuration + currentKeyGenExtraTimeWindow - (stakingFixedEpochDuration == 0 ? 0 : 1); } /// @dev Adds the specified staking address to the array of active pools returned by /// the `getPools` getter. Used by the `stake`, `addPool`, and `orderWithdraw` functions. /// @param _stakingAddress The pool added to the array of active pools. /// @param _toBeElected The boolean flag which defines whether the specified address should be /// added simultaneously to the `poolsToBeElected` array. See the `getPoolsToBeElected` getter. function _addPoolActive(address _stakingAddress, bool _toBeElected) internal { if (!isPoolActive(_stakingAddress)) { _pools.add(_stakingAddress); if (_pools.length() > _getMaxCandidates()) { revert MaxPoolsCountExceeded(); } } _poolsInactive.remove(_stakingAddress); if (_toBeElected) { _addPoolToBeElected(_stakingAddress); } } /// @dev Adds the specified staking address to the array of inactive pools returned by /// the `getPoolsInactive` getter. Used by the `_removePool` internal function. /// @param _stakingAddress The pool added to the array of inactive pools. function _addPoolInactive(address _stakingAddress) internal { // This function performs internal checks if value already exists _poolsInactive.add(_stakingAddress); } /// @dev Adds the specified staking address to the array of pools returned by the `getPoolsToBeElected` /// getter. Used by the `_addPoolActive` internal function. See the `getPoolsToBeElected` getter. /// @param _stakingAddress The pool added to the `poolsToBeElected` array. function _addPoolToBeElected(address _stakingAddress) private { uint256 index = poolToBeElectedIndex[_stakingAddress]; uint256 length = _poolsToBeElected.length; if (index >= length || _poolsToBeElected[index] != _stakingAddress) { poolToBeElectedIndex[_stakingAddress] = length; _poolsToBeElected.push(_stakingAddress); _poolsLikelihood.push(0); // assumes the likelihood is set with `_setLikelihood` function hereinafter } _deletePoolToBeRemoved(_stakingAddress); } /// @dev Adds the specified staking address to the array of pools returned by the `getPoolsToBeRemoved` /// getter. Used by withdrawal functions. See the `getPoolsToBeRemoved` getter. /// @param _stakingAddress The pool added to the `poolsToBeRemoved` array. function _addPoolToBeRemoved(address _stakingAddress) private { _poolsToBeRemoved.add(_stakingAddress); _deletePoolToBeElected(_stakingAddress); } /// @dev Deletes the specified staking address from the array of pools returned by the /// `getPoolsToBeElected` getter. Used by the `_addPoolToBeRemoved` and `_removePool` internal functions. /// See the `getPoolsToBeElected` getter. /// @param _stakingAddress The pool deleted from the `poolsToBeElected` array. function _deletePoolToBeElected(address _stakingAddress) private { if (_poolsToBeElected.length != _poolsLikelihood.length) return; uint256 indexToDelete = poolToBeElectedIndex[_stakingAddress]; if (_poolsToBeElected.length > indexToDelete && _poolsToBeElected[indexToDelete] == _stakingAddress) { if (_poolsLikelihoodSum >= _poolsLikelihood[indexToDelete]) { _poolsLikelihoodSum -= _poolsLikelihood[indexToDelete]; } else { _poolsLikelihoodSum = 0; } uint256 lastPoolIndex = _poolsToBeElected.length - 1; address lastPool = _poolsToBeElected[lastPoolIndex]; _poolsToBeElected[indexToDelete] = lastPool; _poolsLikelihood[indexToDelete] = _poolsLikelihood[lastPoolIndex]; poolToBeElectedIndex[lastPool] = indexToDelete; poolToBeElectedIndex[_stakingAddress] = 0; _poolsToBeElected.pop(); _poolsLikelihood.pop(); } } /// @dev Deletes the specified staking address from the array of pools returned by the /// `getPoolsToBeRemoved` getter. Used by the `_addPoolToBeElected` and `_removePool` internal functions. /// See the `getPoolsToBeRemoved` getter. /// @param _stakingAddress The pool deleted from the `poolsToBeRemoved` array. function _deletePoolToBeRemoved(address _stakingAddress) private { _poolsToBeRemoved.remove(_stakingAddress); } /// @dev Removes the specified staking address from the array of active pools returned by /// the `getPools` getter. Used by the `removePool`, `removeMyPool`, and withdrawal functions. /// @param _stakingAddress The pool removed from the array of active pools. function _removePool(address _stakingAddress) private { // This function performs existence check internally _pools.remove(_stakingAddress); if (_isPoolEmpty(_stakingAddress)) { _poolsInactive.remove(_stakingAddress); } else { _addPoolInactive(_stakingAddress); } _deletePoolToBeElected(_stakingAddress); _deletePoolToBeRemoved(_stakingAddress); } function _validateStakingParams(StakingParams calldata params) private pure { if ( params._stakingFixedEpochDuration == 0 || params._stakingFixedEpochDuration <= params._stakingWithdrawDisallowPeriod ) { revert InvalidFixedEpochDuration(); } if (params._stakingWithdrawDisallowPeriod == 0) { revert ZeroWidthrawDisallowPeriod(); } if ( params._stakingTransitionTimeframeLength == 0 || params._stakingTransitionTimeframeLength >= params._stakingFixedEpochDuration ) { revert InvalidTransitionTimeFrame(); } if (params._validatorSetContract == address(0)) { revert ZeroAddress(); } if (params._initialStakingAddresses.length == 0) { revert InitialStakingPoolsListEmpty(); } if (params._delegatorMinStake == 0 || params._candidateMinStake == 0) { revert InvalidInitialStakeAmount(params._candidateMinStake, params._delegatorMinStake); } if (params._maxStake <= params._candidateMinStake) { revert InvalidMaxStakeAmount(); } } /// @dev Returns the max number of candidates (including validators). See the MAX_CANDIDATES constant. /// Needed mostly for unit tests. function _getMaxCandidates() internal pure virtual returns (uint256) { return MAX_CANDIDATES; } /// @dev Adds the specified address to the array of the current active delegators of the specified pool. /// Used by the `stake` and `orderWithdraw` functions. See the `poolDelegators` getter. /// @param _poolStakingAddress The pool staking address. /// @param _delegator The delegator's address. function _addPoolDelegator(address _poolStakingAddress, address _delegator) private { _poolDelegators[_poolStakingAddress].add(_delegator); _removePoolDelegatorInactive(_poolStakingAddress, _delegator); } /// @dev Adds the specified address to the array of the current inactive delegators of the specified pool. /// Used by the `_removePoolDelegator` internal function. /// @param _poolStakingAddress The pool staking address. /// @param _delegator The delegator's address. function _addPoolDelegatorInactive(address _poolStakingAddress, address _delegator) private { _poolDelegatorsInactive[_poolStakingAddress].add(_delegator); } /// @dev Removes the specified address from the array of the current active delegators of the specified pool. /// Used by the withdrawal functions. See the `poolDelegators` getter. /// @param _poolStakingAddress The pool staking address. /// @param _delegator The delegator's address. function _removePoolDelegator(address _poolStakingAddress, address _delegator) private { _poolDelegators[_poolStakingAddress].remove(_delegator); if (orderedWithdrawAmount[_poolStakingAddress][_delegator] != 0) { _addPoolDelegatorInactive(_poolStakingAddress, _delegator); } else { _removePoolDelegatorInactive(_poolStakingAddress, _delegator); } } /// @dev Removes the specified address from the array of the inactive delegators of the specified pool. /// Used by the `_addPoolDelegator` and `_removePoolDelegator` internal functions. /// @param _poolStakingAddress The pool staking address. /// @param _delegator The delegator's address. function _removePoolDelegatorInactive(address _poolStakingAddress, address _delegator) private { _poolDelegatorsInactive[_poolStakingAddress].remove(_delegator); } /// @dev Calculates (updates) the probability of being selected as a validator for the specified pool /// and updates the total sum of probability coefficients. Actually, the probability is equal to the /// amount totally staked into the pool multiplied by validator bonus score. See the `getPoolsLikelihood` getter. /// Used by the staking and withdrawal functions. /// @param _poolStakingAddress The address of the pool for which the probability coefficient must be updated. function _setLikelihood(address _poolStakingAddress) private { address miningAddress = validatorSetContract.miningByStakingAddress(_poolStakingAddress); uint256 validatorBonusScore = bonusScoreContract.getValidatorScore(miningAddress); _updateLikelihood(_poolStakingAddress, validatorBonusScore); } function _updateLikelihood(address _poolStakingAddress, uint256 validatorBonusScore) private { (bool isToBeElected, uint256 index) = _isPoolToBeElected(_poolStakingAddress); if (!isToBeElected) return; uint256 oldValue = _poolsLikelihood[index]; uint256 newValue = stakeAmountTotal[_poolStakingAddress] * validatorBonusScore; _poolsLikelihood[index] = newValue; _poolsLikelihoodSum = _poolsLikelihoodSum - oldValue + newValue; } /// @dev The internal function used by the `_stake` and `moveStake` functions. /// See the `stake` public function for more details. /// @param _poolStakingAddress The staking address of the pool where the coins should be staked. /// @param _staker The staker's address. /// @param _amount The amount of coins to be staked. function _stake(address _poolStakingAddress, address _staker, uint256 _amount) private { if (_poolStakingAddress == address(0)) { revert ZeroAddress(); } address poolMiningAddress = validatorSetContract.miningByStakingAddress(_poolStakingAddress); if (poolMiningAddress == address(0)) { revert PoolNotExist(_poolStakingAddress); } if (_amount == 0) { revert InsufficientStakeAmount(_poolStakingAddress, _staker); } if (abandonedAndRemoved[_poolStakingAddress]) { revert PoolAbandoned(_poolStakingAddress); } //require(areStakeAndWithdrawAllowed(), "Stake: disallowed period"); bool selfStake = _staker == _poolStakingAddress; uint256 newStakeAmount = stakeAmount[_poolStakingAddress][_staker] + _amount; uint256 requiredStakeAmount; if (selfStake) { requiredStakeAmount = candidateMinStake; } else { requiredStakeAmount = delegatorMinStake; // The delegator cannot stake into the pool of the candidate which hasn't self-staked. // Also, that candidate shouldn't want to withdraw all their funds. if (stakeAmount[_poolStakingAddress][_poolStakingAddress] == 0) { revert PoolEmpty(_poolStakingAddress); } } if (newStakeAmount < requiredStakeAmount) { revert InsufficientStakeAmount(_poolStakingAddress, _staker); } if (stakeAmountTotal[_poolStakingAddress] + _amount > maxStakeAmount) { revert PoolStakeLimitExceeded(_poolStakingAddress, _staker); } _stakeAmountByEpoch[_poolStakingAddress][_staker][stakingEpoch] += _amount; stakeAmountTotal[_poolStakingAddress] += _amount; totalStakedAmount += _amount; if (selfStake) { // `staker` places a stake for himself and becomes a candidate // Add `_poolStakingAddress` to the array of pools _addPoolActive(_poolStakingAddress, true); } else { // Add `_staker` to the array of pool's delegators _addPoolDelegator(_poolStakingAddress, _staker); // Save amount value staked by the delegator _snapshotDelegatorStake(_poolStakingAddress, poolMiningAddress, _staker); } stakeAmount[_poolStakingAddress][_staker] = newStakeAmount; _setLikelihood(_poolStakingAddress); } /// @dev The internal function used by the `withdraw` and `moveStake` functions. /// See the `withdraw` public function for more details. /// @param _poolStakingAddress The staking address of the pool from which the coins should be withdrawn. /// @param _staker The staker's address. /// @param _amount The amount of coins to be withdrawn. function _withdraw(address _poolStakingAddress, address _staker, uint256 _amount) private { if (_poolStakingAddress == address(0)) { revert ZeroAddress(); } if (_amount == 0) { revert ZeroWidthrawAmount(); } // How much can `staker` withdraw from `_poolStakingAddress` at the moment? uint256 allowedMaxWithdraw = maxWithdrawAllowed(_poolStakingAddress, _staker); if (_amount > allowedMaxWithdraw) { revert MaxAllowedWithdrawExceeded(allowedMaxWithdraw, _amount); } uint256 newStakeAmount = stakeAmount[_poolStakingAddress][_staker] - _amount; // The amount to be withdrawn must be the whole staked amount or // must not exceed the diff between the entire amount and MIN_STAKE uint256 minAllowedStake = (_poolStakingAddress == _staker) ? candidateMinStake : delegatorMinStake; if (newStakeAmount != 0 && newStakeAmount < minAllowedStake) { revert InvalidWithdrawAmount(_poolStakingAddress, _staker, _amount); } if (_staker != _poolStakingAddress) { address miningAddress = validatorSetContract.miningByStakingAddress(_poolStakingAddress); _snapshotDelegatorStake(_poolStakingAddress, miningAddress, _staker); } stakeAmount[_poolStakingAddress][_staker] = newStakeAmount; uint256 amountByEpoch = stakeAmountByCurrentEpoch(_poolStakingAddress, _staker); _stakeAmountByEpoch[_poolStakingAddress][_staker][stakingEpoch] = amountByEpoch >= _amount ? amountByEpoch - _amount : 0; stakeAmountTotal[_poolStakingAddress] -= _amount; totalStakedAmount -= _amount; if (newStakeAmount == 0) { _withdrawCheckPool(_poolStakingAddress, _staker); } _setLikelihood(_poolStakingAddress); } /// @dev The internal function used by the `_withdraw` and `claimOrderedWithdraw` functions. /// Contains a common logic for these functions. /// @param _poolStakingAddress The staking address of the pool from which the coins are withdrawn. /// @param _staker The staker's address. function _withdrawCheckPool(address _poolStakingAddress, address _staker) private { if (_staker == _poolStakingAddress) { address miningAddress = validatorSetContract.miningByStakingAddress(_poolStakingAddress); if (validatorSetContract.isValidator(miningAddress)) { _addPoolToBeRemoved(_poolStakingAddress); } else { _removePool(_poolStakingAddress); } } else { _removePoolDelegator(_poolStakingAddress, _staker); if (_isPoolEmpty(_poolStakingAddress)) { _poolsInactive.remove(_poolStakingAddress); } } } function _snapshotDelegatorStake(address _stakingAddress, address _miningAddress, address _delegator) private { if (!validatorSetContract.isValidatorOrPending(_miningAddress) || stakingEpoch == 0) { return; } uint256 lastSnapshotEpochNumber = _stakeSnapshotLastEpoch[_stakingAddress][_delegator]; if (lastSnapshotEpochNumber < stakingEpoch) { _delegatorStakeSnapshot[_stakingAddress][_delegator][stakingEpoch] = stakeAmount[_stakingAddress][ _delegator ]; _stakeSnapshotLastEpoch[_stakingAddress][_delegator] = stakingEpoch; } } function _setNodeOperator( address _stakingAddress, address _operatorAddress, uint256 _operatorSharePercent ) private { if (_operatorSharePercent > MAX_NODE_OPERATOR_SHARE_PERCENT) { revert InvalidNodeOperatorShare(_operatorSharePercent); } if (_operatorAddress == address(0) && _operatorSharePercent != 0) { revert InvalidNodeOperatorConfiguration(_operatorAddress, _operatorSharePercent); } uint256 lastChangeEpoch = poolNodeOperatorLastChangeEpoch[_stakingAddress]; if (lastChangeEpoch != 0 && lastChangeEpoch == stakingEpoch) { revert OnlyOncePerEpoch(stakingEpoch); } poolNodeOperator[_stakingAddress] = _operatorAddress; poolNodeOperatorShare[_stakingAddress] = _operatorSharePercent; poolNodeOperatorLastChangeEpoch[_stakingAddress] = stakingEpoch; emit SetNodeOperator(_stakingAddress, _operatorAddress, _operatorSharePercent); } function _rewardNodeOperator(address _stakingAddress, uint256 _operatorShare) private { address nodeOperator = poolNodeOperator[_stakingAddress]; if (!_poolDelegators[_stakingAddress].contains(nodeOperator)) { _addPoolDelegator(_stakingAddress, nodeOperator); } stakeAmount[_stakingAddress][nodeOperator] += _operatorShare; _stakeAmountByEpoch[_stakingAddress][nodeOperator][stakingEpoch] += _operatorShare; } function _getDelegatorStake( uint256 _stakingEpoch, address _stakingAddress, address _delegator ) private view returns (uint256) { if (_stakingEpoch == 0) { return 0; } if (_stakeSnapshotLastEpoch[_stakingAddress][_delegator] == _stakingEpoch) { return _delegatorStakeSnapshot[_stakingAddress][_delegator][_stakingEpoch]; } else { return stakeAmount[_stakingAddress][_delegator]; } } /// @dev Returns a boolean flag indicating whether the specified pool is fully empty /// (all stakes are withdrawn including ordered withdrawals). /// @param _poolStakingAddress The staking address of the pool function _isPoolEmpty(address _poolStakingAddress) private view returns (bool) { return stakeAmountTotal[_poolStakingAddress] == 0 && orderedWithdrawAmountTotal[_poolStakingAddress] == 0; } /// @dev Determines if the specified pool is in the `poolsToBeElected` array. See the `getPoolsToBeElected` getter. /// Used by the `_setLikelihood` internal function. /// @param _stakingAddress The staking address of the pool. /// @return toBeElected `bool toBeElected` - The boolean flag indicating whether the `_stakingAddress` is in the /// `poolsToBeElected` array. /// `uint256 index` - The position of the item in the `poolsToBeElected` array if `toBeElected` is `true`. function _isPoolToBeElected(address _stakingAddress) private view returns (bool toBeElected, uint256 index) { index = poolToBeElectedIndex[_stakingAddress]; if (_poolsToBeElected.length > index && _poolsToBeElected[index] == _stakingAddress) { return (true, index); } return (false, 0); } function _splitPoolReward( address _poolAddress, uint256 _poolReward, uint256 _validatorMinRewardPercent ) private view returns (PoolRewardShares memory shares) { uint256 totalStake = snapshotPoolTotalStakeAmount[stakingEpoch][_poolAddress]; uint256 validatorStake = snapshotPoolValidatorStakeAmount[stakingEpoch][_poolAddress]; uint256 validatorFixedReward = (_poolReward * _validatorMinRewardPercent) / 100; shares.delegatorsShare = _poolReward - validatorFixedReward; uint256 operatorSharePercent = poolNodeOperatorShare[_poolAddress]; if (poolNodeOperator[_poolAddress] != address(0) && operatorSharePercent != 0) { shares.nodeOperatorShare = (_poolReward * operatorSharePercent) / PERCENT_DENOMINATOR; } shares.validatorShare = validatorFixedReward - shares.nodeOperatorShare + (shares.delegatorsShare * validatorStake) / totalStake; } /// @dev For deployment, the length of stakingTransitionTimeframeLength was chosen not long enough, leading to bonus score losses. /// see https://github.com/DMDcoin/Beta1/issues/6 for more infos. function updateStakingTransitionTimeframeLength() external { stakingTransitionTimeframeLength = 900; }}// slither-disable-end unused-return
@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)pragma solidity ^0.8.20;import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";import {Initializable} from "../proxy/utils/Initializable.sol";/** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); }}
@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)pragma solidity ^0.8.20;/** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } }}
@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)pragma solidity ^0.8.20;import {Initializable} from "../proxy/utils/Initializable.sol";/** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; }}
@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)pragma solidity ^0.8.20;import {Initializable} from "../proxy/utils/Initializable.sol";/** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; }}
@openzeppelin/contracts/utils/structs/EnumerableSet.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.pragma solidity ^0.8.20;/** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._positions[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; }}
contracts/interfaces/IBlockRewardHbbft.sol
// SPDX-License-Identifier: Apache 2.0pragma solidity =0.8.25;interface IBlockRewardHbbft { function addToReinsertPot() external payable; function notifyEarlyEpochEnd() external; function getGovernanceAddress() external view returns (address);}
contracts/interfaces/IBonusScoreSystem.sol
// SPDX-License-Identifier: Apache 2.0pragma solidity =0.8.25;enum ScoringFactor { StandByBonus, NoStandByPenalty, NoKeyWritePenalty, BadPerformancePenalty}interface IBonusScoreSystem { function getValidatorScore(address mining) external view returns (uint256); function rewardStandBy(address mining, uint256 time) external; function penaliseNoStandBy(address mining, uint256 time) external; function penaliseNoKeyWrite(address mining) external; function penaliseBadPerformance(address mining, uint256 time) external;}
contracts/interfaces/IStakingHbbft.sol
// SPDX-License-Identifier: Apache 2.0pragma solidity =0.8.25;interface IStakingHbbft { struct PoolRewardShares { uint256 validatorShare; uint256 nodeOperatorShare; uint256 delegatorsShare; } struct StakingParams { address _validatorSetContract; address _bonusScoreContract; address[] _initialStakingAddresses; uint256 _delegatorMinStake; uint256 _candidateMinStake; uint256 _maxStake; uint256 _stakingFixedEpochDuration; uint256 _stakingTransitionTimeframeLength; uint256 _stakingWithdrawDisallowPeriod; } function incrementStakingEpoch() external; function removePool(address) external; function removePools() external; function setStakingEpochStartTime(uint256) external; function notifyKeyGenFailed() external; function notifyAvailability(address _stakingAddress) external; function notifyNetworkOfftimeDetected(uint256) external; function updatePoolLikelihood(address mining, uint256 validatorScore) external; function getPoolPublicKey(address _poolAddress) external view returns (bytes memory); function getPoolsLikelihood() external view returns (uint256[] memory, uint256); function getPoolsToBeElected() external view returns (address[] memory); function getPoolsToBeRemoved() external view returns (address[] memory); function getPoolsInactive() external view returns (address[] memory); function isPoolActive(address) external view returns (bool); function isPoolValid(address) external view returns (bool); function MAX_CANDIDATES() external pure returns (uint256); // solhint-disable-line func-name-mixedcase function orderedWithdrawAmount(address, address) external view returns (uint256); function poolDelegators(address) external view returns (address[] memory); function setValidatorInternetAddress( address, bytes16, bytes2 ) external; function stakeAmount(address, address) external view returns (uint256); function stakeAmountTotal(address) external view returns (uint256); function totalStakedAmount() external view returns (uint256); function stakingWithdrawDisallowPeriod() external view returns (uint256); function stakingEpoch() external view returns (uint256); function stakingFixedEpochDuration() external view returns (uint256); function startTimeOfNextPhaseTransition() external view returns (uint256); function stakingFixedEpochEndTime() external view returns (uint256); function stakingEpochStartTime() external view returns (uint256); function stakingEpochStartBlock() external view returns (uint256); function restake( address _poolStakingAddress, uint256 validatorReward ) external payable; function snapshotPoolStakeAmounts( uint256 _epoch, address _stakingPool ) external; function getPoolValidatorStakeAmount( uint256 _epoch, address _stakingPool ) external view returns (uint256);}
contracts/interfaces/IValidatorSetHbbft.sol
// SPDX-License-Identifier: Apache 2.0pragma solidity =0.8.25;interface IValidatorSetHbbft { struct ValidatorSetParams { address blockRewardContract; address randomContract; address stakingContract; address keyGenHistoryContract; address bonusScoreContract; address connectivityTrackerContract; uint256 validatorInactivityThreshold; } // Key Generation states of validator. enum KeyGenMode { NotAPendingValidator, WritePart, WaitForOtherParts, WriteAck, WaitForOtherAcks, AllKeysDone } function announceAvailability(uint256, bytes32) external; function finalizeChange() external; function newValidatorSet() external; function setStakingAddress(address, address) external; function handleFailedKeyGeneration() external; function isFullHealth() external view returns (bool); function blockRewardContract() external view returns (address); function canCallAnnounceAvailability(address _miningAddress) external view returns (bool); function getPendingValidators() external view returns (address[] memory); function getPreviousValidators() external view returns (address[] memory); function getValidators() external view returns (address[] memory); function isValidator(address) external view returns (bool); function isValidatorOrPending(address) external view returns (bool); function isPendingValidator(address) external view returns (bool); function getPendingValidatorKeyGenerationMode(address) external view returns (KeyGenMode); function maxValidators() external view returns (uint256); function miningByStakingAddress(address) external view returns (address); function randomContract() external view returns (address); function notifyUnavailability(address) external; function stakingByMiningAddress(address) external view returns (address); function publicKeyByStakingAddress(address) external view returns (bytes memory); function getPublicKey(address) external view returns (bytes memory); function getStakingContract() external view returns (address); function validatorAvailableSince(address) external view returns (uint256); function isValidatorAbandoned(address) external view returns (bool); function getValidatorCountSweetSpot(uint256) external view returns (uint256); function getCurrentValidatorsCount() external view returns (uint256);}
contracts/lib/Errors.sol
// SPDX-License-Identifier: Apache 2.0pragma solidity =0.8.25;error Unauthorized();error ValidatorsListEmpty();error ZeroAddress();error ZeroGasPrice();
contracts/lib/ValueGuards.sol
// SPDX-License-Identifier: Apache 2.0pragma solidity =0.8.25;import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";abstract contract ValueGuards is OwnableUpgradeable { // =============================================== Storage ======================================================== /** * @dev Represents a parameter range for a specific getter function. * @param getter The getter function signature. * @param range The range of values for the parameter. */ struct ParameterRange { bytes4 getter; uint256[] range; } struct ValueGuardsStorage { /** * @dev A mapping that stores the allowed parameter ranges for each function signature. */ mapping(bytes4 => ParameterRange) allowedParameterRange; } bytes32 private constant VALUEGUARDS_STORAGE_NAMESPACE = keccak256(abi.encode(uint256(keccak256("valueguards.storage")) - 1)) & ~bytes32(uint256(0xff)); function _getValueGuardsStorage() private pure returns (ValueGuardsStorage storage $) { bytes32 slot = VALUEGUARDS_STORAGE_NAMESPACE; // solhint-disable-next-line no-inline-assembly assembly { $.slot := slot } } // ============================================== Events ========================================================== /** * @dev Event emitted when changeable parameters are set. * @param setter Setter function signature. * @param getter Getter function signature. * @param params An array of uint256 values representing the parameters. */ event SetChangeableParameter(bytes4 setter, bytes4 getter, uint256[] params); /** * @dev Emitted when changeable parameters are removed. * @param funcSelector The function selector of the removed changeable parameters. */ event RemoveChangeableParameter(bytes4 funcSelector); // ============================================== Errors ========================================================== error NewValueOutOfRange(uint256 _newVal); error GetterCallFailed(); // ============================================== Modifiers ======================================================= /** * @dev Modifier to check if a new value is within the allowed range. * @param newVal The new value to be checked. * @notice This modifier is used to ensure that the new value is within the allowed range. * If the new value is not within the allowed range, the function using this modifier * will revert with an error message. */ modifier withinAllowedRange(uint256 newVal) { if (!isWithinAllowedRange(msg.sig, newVal)) { revert NewValueOutOfRange(newVal); } _; } // =============================================== Initializers ==================================================== /** * @dev Inits the allowed changeable parameter for a specific setter function. * @param setter Setter function selector. * @param getter Getter function selector. * @param params The array of allowed parameter values. */ function __initAllowedChangeableParameter( bytes4 setter, bytes4 getter, uint256[] memory params ) internal onlyInitializing { ValueGuardsStorage storage $ = _getValueGuardsStorage(); $.allowedParameterRange[setter] = ParameterRange({ getter: getter, range: params }); emit SetChangeableParameter(setter, getter, params); } // =============================================== Setters ======================================================== /** * @dev Sets the allowed changeable parameter for a specific setter function. * @param setter Setter function selector. * @param getter Getter function selector. * @param params The array of allowed parameter values. */ function setAllowedChangeableParameter(bytes4 setter, bytes4 getter, uint256[] calldata params) public onlyOwner { ValueGuardsStorage storage $ = _getValueGuardsStorage(); $.allowedParameterRange[setter] = ParameterRange({ getter: getter, range: params }); emit SetChangeableParameter(setter, getter, params); } /** * @dev Removes the allowed changeable parameter for a given function selector. * @param funcSelector The function selector for which the allowed changeable parameter should be removed. */ function removeAllowedChangeableParameter(bytes4 funcSelector) public onlyOwner { ValueGuardsStorage storage $ = _getValueGuardsStorage(); delete $.allowedParameterRange[funcSelector]; emit RemoveChangeableParameter(funcSelector); } // =============================================== Getters ======================================================== /** * @dev Checks if the given `newVal` is within the allowed range for the specified function selector. * @param funcSelector The function selector. * @param newVal The new value to be checked. * @return A boolean indicating whether the `newVal` is within the allowed range. */ function isWithinAllowedRange(bytes4 funcSelector, uint256 newVal) public view returns (bool) { ValueGuardsStorage storage $ = _getValueGuardsStorage(); ParameterRange memory allowedRange = $.allowedParameterRange[funcSelector]; if (allowedRange.range.length == 0) { return false; } uint256[] memory range = allowedRange.range; uint256 currVal = _getValueWithSelector(allowedRange.getter); for (uint256 i = 0; i < range.length; i++) { if (range[i] == currVal) { uint256 leftVal = (i > 0) ? range[i - 1] : range[0]; uint256 rightVal = (i < range.length - 1) ? range[i + 1] : range[range.length - 1]; return !(newVal != leftVal && newVal != rightVal); } } return false; } function getAllowedParamsRange(string memory _selector) external view returns (ParameterRange memory) { return _getValueGuardsStorage().allowedParameterRange[bytes4(keccak256(bytes(_selector)))]; } function getAllowedParamsRangeWithSelector(bytes4 _selector) external view returns (ParameterRange memory) { return _getValueGuardsStorage().allowedParameterRange[_selector]; } // =============================================== Internal ======================================================== /** * @dev Internal function to get the value of a contract state variable using a getter function. * @param getterSelector The selector of the getter function. * @return The value of the contract state variable. */ function _getValueWithSelector(bytes4 getterSelector) private view returns (uint256) { bytes memory payload = abi.encodeWithSelector(getterSelector); (bool success, bytes memory result) = address(this).staticcall(payload); if (!success) { revert GetterCallFailed(); } return abi.decode(result, (uint256)); }}
contracts/utils/TransferUtils.sol
// SPDX-License-Identifier: Apache 2.0pragma solidity =0.8.25;library TransferUtils { error InsufficientBalance(); error TransferFailed(address recipient, uint256 amount); function transferNative(address recipient, uint256 amount) internal { if (address(this).balance < amount) { revert InsufficientBalance(); } // solhint-disable-next-line avoid-low-level-calls (bool success, ) = recipient.call{ value: amount }(""); if (!success) { revert TransferFailed(recipient, amount); } }}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"error","name":"CannotClaimWithdrawOrderYet","inputs":[{"type":"address","name":"pool","internalType":"address"},{"type":"address","name":"staker","internalType":"address"}]},{"type":"error","name":"GetterCallFailed","inputs":[]},{"type":"error","name":"InitialStakingPoolsListEmpty","inputs":[]},{"type":"error","name":"InsufficientBalance","inputs":[]},{"type":"error","name":"InsufficientStakeAmount","inputs":[{"type":"address","name":"pool","internalType":"address"},{"type":"address","name":"delegator","internalType":"address"}]},{"type":"error","name":"InvalidFixedEpochDuration","inputs":[]},{"type":"error","name":"InvalidInitialStakeAmount","inputs":[{"type":"uint256","name":"candidateStake","internalType":"uint256"},{"type":"uint256","name":"delegatorStake","internalType":"uint256"}]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"InvalidIpAddressesCount","inputs":[]},{"type":"error","name":"InvalidMaxStakeAmount","inputs":[]},{"type":"error","name":"InvalidMoveStakePoolsAddress","inputs":[]},{"type":"error","name":"InvalidNodeOperatorConfiguration","inputs":[{"type":"address","name":"_operator","internalType":"address"},{"type":"uint256","name":"_share","internalType":"uint256"}]},{"type":"error","name":"InvalidNodeOperatorShare","inputs":[{"type":"uint256","name":"_share","internalType":"uint256"}]},{"type":"error","name":"InvalidOrderWithdrawAmount","inputs":[{"type":"address","name":"pool","internalType":"address"},{"type":"address","name":"delegator","internalType":"address"},{"type":"int256","name":"amount","internalType":"int256"}]},{"type":"error","name":"InvalidPublicKeysCount","inputs":[]},{"type":"error","name":"InvalidStakingFixedEpochDuration","inputs":[]},{"type":"error","name":"InvalidStakingTransitionTimeframe","inputs":[]},{"type":"error","name":"InvalidTransitionTimeFrame","inputs":[]},{"type":"error","name":"InvalidWithdrawAmount","inputs":[{"type":"address","name":"pool","internalType":"address"},{"type":"address","name":"delegator","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"error","name":"MaxAllowedWithdrawExceeded","inputs":[{"type":"uint256","name":"allowed","internalType":"uint256"},{"type":"uint256","name":"desired","internalType":"uint256"}]},{"type":"error","name":"MaxPoolsCountExceeded","inputs":[]},{"type":"error","name":"NewValueOutOfRange","inputs":[{"type":"uint256","name":"_newVal","internalType":"uint256"}]},{"type":"error","name":"NoStakesToRecover","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]},{"type":"error","name":"NotPayable","inputs":[]},{"type":"error","name":"OnlyOncePerEpoch","inputs":[{"type":"uint256","name":"_epoch","internalType":"uint256"}]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"error","name":"PoolAbandoned","inputs":[{"type":"address","name":"pool","internalType":"address"}]},{"type":"error","name":"PoolCannotBeRemoved","inputs":[{"type":"address","name":"pool","internalType":"address"}]},{"type":"error","name":"PoolEmpty","inputs":[{"type":"address","name":"pool","internalType":"address"}]},{"type":"error","name":"PoolNotExist","inputs":[{"type":"address","name":"pool","internalType":"address"}]},{"type":"error","name":"PoolStakeLimitExceeded","inputs":[{"type":"address","name":"pool","internalType":"address"},{"type":"address","name":"delegator","internalType":"address"}]},{"type":"error","name":"ReentrancyGuardReentrantCall","inputs":[]},{"type":"error","name":"TransferFailed","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"error","name":"Unauthorized","inputs":[]},{"type":"error","name":"WithdrawNotAllowed","inputs":[]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"error","name":"ZeroGasPrice","inputs":[]},{"type":"error","name":"ZeroWidthrawAmount","inputs":[]},{"type":"error","name":"ZeroWidthrawDisallowPeriod","inputs":[]},{"type":"event","name":"ClaimedOrderedWithdrawal","inputs":[{"type":"address","name":"fromPoolStakingAddress","internalType":"address","indexed":true},{"type":"address","name":"staker","internalType":"address","indexed":true},{"type":"uint256","name":"stakingEpoch","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GatherAbandonedStakes","inputs":[{"type":"address","name":"caller","internalType":"address","indexed":true},{"type":"address","name":"stakingAddress","internalType":"address","indexed":true},{"type":"uint256","name":"gatheredFunds","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint64","name":"version","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"MovedStake","inputs":[{"type":"address","name":"fromPoolStakingAddress","internalType":"address","indexed":false},{"type":"address","name":"toPoolStakingAddress","internalType":"address","indexed":true},{"type":"address","name":"staker","internalType":"address","indexed":true},{"type":"uint256","name":"stakingEpoch","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OrderedWithdrawal","inputs":[{"type":"address","name":"fromPoolStakingAddress","internalType":"address","indexed":true},{"type":"address","name":"staker","internalType":"address","indexed":true},{"type":"uint256","name":"stakingEpoch","internalType":"uint256","indexed":true},{"type":"int256","name":"amount","internalType":"int256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"PlacedStake","inputs":[{"type":"address","name":"toPoolStakingAddress","internalType":"address","indexed":true},{"type":"address","name":"staker","internalType":"address","indexed":true},{"type":"uint256","name":"stakingEpoch","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RecoverAbandonedStakes","inputs":[{"type":"address","name":"caller","internalType":"address","indexed":true},{"type":"uint256","name":"reinsertShare","internalType":"uint256","indexed":false},{"type":"uint256","name":"governanceShare","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RemoveChangeableParameter","inputs":[{"type":"bytes4","name":"funcSelector","internalType":"bytes4","indexed":false}],"anonymous":false},{"type":"event","name":"RestakeReward","inputs":[{"type":"address","name":"poolStakingAddress","internalType":"address","indexed":true},{"type":"uint256","name":"stakingEpoch","internalType":"uint256","indexed":true},{"type":"uint256","name":"validatorReward","internalType":"uint256","indexed":false},{"type":"uint256","name":"delegatorsReward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetChangeableParameter","inputs":[{"type":"bytes4","name":"setter","internalType":"bytes4","indexed":false},{"type":"bytes4","name":"getter","internalType":"bytes4","indexed":false},{"type":"uint256[]","name":"params","internalType":"uint256[]","indexed":false}],"anonymous":false},{"type":"event","name":"SetDelegatorMinStake","inputs":[{"type":"uint256","name":"minStake","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetNodeOperator","inputs":[{"type":"address","name":"poolStakingAddress","internalType":"address","indexed":true},{"type":"address","name":"nodeOperatorAddress","internalType":"address","indexed":true},{"type":"uint256","name":"operatorShare","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"WithdrewStake","inputs":[{"type":"address","name":"fromPoolStakingAddress","internalType":"address","indexed":true},{"type":"address","name":"staker","internalType":"address","indexed":true},{"type":"uint256","name":"stakingEpoch","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_CANDIDATES","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_NODE_OPERATOR_SHARE_PERCENT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"PERCENT_DENOMINATOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"abandonedAndRemoved","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"addPool","inputs":[{"type":"address","name":"_miningAddress","internalType":"address"},{"type":"address","name":"_nodeOperatorAddress","internalType":"address"},{"type":"uint256","name":"_operatorShare","internalType":"uint256"},{"type":"bytes","name":"_publicKey","internalType":"bytes"},{"type":"bytes16","name":"_ip","internalType":"bytes16"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"areStakeAndWithdrawAllowed","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IBonusScoreSystem"}],"name":"bonusScoreContract","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"candidateMinStake","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimOrderedWithdraw","inputs":[{"type":"address","name":"_poolStakingAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"currentKeyGenExtraTimeWindow","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"delegatorMinStake","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct ValueGuards.ParameterRange","components":[{"type":"bytes4","name":"getter","internalType":"bytes4"},{"type":"uint256[]","name":"range","internalType":"uint256[]"}]}],"name":"getAllowedParamsRange","inputs":[{"type":"string","name":"_selector","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct ValueGuards.ParameterRange","components":[{"type":"bytes4","name":"getter","internalType":"bytes4"},{"type":"uint256[]","name":"range","internalType":"uint256[]"}]}],"name":"getAllowedParamsRangeWithSelector","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes16","name":"","internalType":"bytes16"},{"type":"bytes2","name":"","internalType":"bytes2"}],"name":"getPoolInternetAddress","inputs":[{"type":"address","name":"_poolAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"getPoolPublicKey","inputs":[{"type":"address","name":"_poolAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPoolValidatorStakeAmount","inputs":[{"type":"uint256","name":"_epoch","internalType":"uint256"},{"type":"address","name":"_stakingPool","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getPools","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getPoolsInactive","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"likelihoods","internalType":"uint256[]"},{"type":"uint256","name":"sum","internalType":"uint256"}],"name":"getPoolsLikelihood","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getPoolsToBeElected","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getPoolsToBeRemoved","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"incrementStakingEpoch","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_contractOwner","internalType":"address"},{"type":"tuple","name":"stakingParams","internalType":"struct IStakingHbbft.StakingParams","components":[{"type":"address","name":"_validatorSetContract","internalType":"address"},{"type":"address","name":"_bonusScoreContract","internalType":"address"},{"type":"address[]","name":"_initialStakingAddresses","internalType":"address[]"},{"type":"uint256","name":"_delegatorMinStake","internalType":"uint256"},{"type":"uint256","name":"_candidateMinStake","internalType":"uint256"},{"type":"uint256","name":"_maxStake","internalType":"uint256"},{"type":"uint256","name":"_stakingFixedEpochDuration","internalType":"uint256"},{"type":"uint256","name":"_stakingTransitionTimeframeLength","internalType":"uint256"},{"type":"uint256","name":"_stakingWithdrawDisallowPeriod","internalType":"uint256"}]},{"type":"bytes32[]","name":"_publicKeys","internalType":"bytes32[]"},{"type":"bytes16[]","name":"_internetAddresses","internalType":"bytes16[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isPoolActive","inputs":[{"type":"address","name":"_stakingAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isPoolValid","inputs":[{"type":"address","name":"_stakingAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isWithinAllowedRange","inputs":[{"type":"bytes4","name":"funcSelector","internalType":"bytes4"},{"type":"uint256","name":"newVal","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxStakeAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxWithdrawAllowed","inputs":[{"type":"address","name":"_poolStakingAddress","internalType":"address"},{"type":"address","name":"_staker","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxWithdrawOrderAllowed","inputs":[{"type":"address","name":"_poolStakingAddress","internalType":"address"},{"type":"address","name":"_staker","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"moveStake","inputs":[{"type":"address","name":"_fromPoolStakingAddress","internalType":"address"},{"type":"address","name":"_toPoolStakingAddress","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"notifyAvailability","inputs":[{"type":"address","name":"_stakingAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"notifyKeyGenFailed","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"notifyNetworkOfftimeDetected","inputs":[{"type":"uint256","name":"detectedOfflineTime","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"orderWithdraw","inputs":[{"type":"address","name":"_poolStakingAddress","internalType":"address"},{"type":"int256","name":"_amount","internalType":"int256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"orderWithdrawEpoch","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"orderedWithdrawAmount","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"orderedWithdrawAmountTotal","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"poolDelegators","inputs":[{"type":"address","name":"_poolStakingAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"poolDelegatorsInactive","inputs":[{"type":"address","name":"_poolStakingAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"publicKey","internalType":"bytes"},{"type":"bytes16","name":"internetAddress","internalType":"bytes16"},{"type":"bytes2","name":"port","internalType":"bytes2"}],"name":"poolInfo","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"poolNodeOperator","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolNodeOperatorLastChangeEpoch","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolNodeOperatorShare","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolToBeElectedIndex","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recoverAbandonedStakes","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeAllowedChangeableParameter","inputs":[{"type":"bytes4","name":"funcSelector","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeMyPool","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removePool","inputs":[{"type":"address","name":"_stakingAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removePools","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"restake","inputs":[{"type":"address","name":"_poolStakingAddress","internalType":"address"},{"type":"uint256","name":"_validatorMinRewardPercent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAllowedChangeableParameter","inputs":[{"type":"bytes4","name":"setter","internalType":"bytes4"},{"type":"bytes4","name":"getter","internalType":"bytes4"},{"type":"uint256[]","name":"params","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDelegatorMinStake","inputs":[{"type":"uint256","name":"_minStake","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setNodeOperator","inputs":[{"type":"address","name":"_operatorAddress","internalType":"address"},{"type":"uint256","name":"_operatorShare","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPoolInfo","inputs":[{"type":"bytes","name":"_publicKey","internalType":"bytes"},{"type":"bytes16","name":"_ip","internalType":"bytes16"},{"type":"bytes2","name":"_port","internalType":"bytes2"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setStakingEpochStartTime","inputs":[{"type":"uint256","name":"_timestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setValidatorInternetAddress","inputs":[{"type":"address","name":"_validatorAddress","internalType":"address"},{"type":"bytes16","name":"_ip","internalType":"bytes16"},{"type":"bytes2","name":"_port","internalType":"bytes2"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"snapshotPoolStakeAmounts","inputs":[{"type":"uint256","name":"_epoch","internalType":"uint256"},{"type":"address","name":"_stakingPool","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"snapshotPoolTotalStakeAmount","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"snapshotPoolValidatorStakeAmount","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"stake","inputs":[{"type":"address","name":"_toPoolStakingAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakeAmount","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakeAmountByCurrentEpoch","inputs":[{"type":"address","name":"_poolStakingAddress","internalType":"address"},{"type":"address","name":"_staker","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakeAmountTotal","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakingEpoch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakingEpochStartBlock","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakingEpochStartTime","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakingFixedEpochDuration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakingFixedEpochEndTime","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakingTransitionTimeframeLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakingWithdrawDisallowPeriod","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"startTimeOfNextPhaseTransition","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalStakedAmount","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePoolLikelihood","inputs":[{"type":"address","name":"mining","internalType":"address"},{"type":"uint256","name":"validatorScore","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateStakingTransitionTimeframeLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IValidatorSetHbbft"}],"name":"validatorSetContract","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"address","name":"_fromPoolStakingAddress","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x6080604052348015600f57600080fd5b506016601a565b60ca565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560695760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c75780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b615e30806100d96000396000f3fe60806040526004361061055c5760003560e01c8063862be287116102ca578063c6912cc011610179578063e9ab0300116100d6578063f3fef3a31161008a578063f6c578611161006f578063f6c5786114610f96578063f9d4d54414610fb6578063fa4aaf4714610fe357600080fd5b8063f3fef3a314610f62578063f494250114610f8257600080fd5b8063ee435f55116100bb578063ee435f5514610f17578063f078609614610f2c578063f2fde38b14610f4257600080fd5b8063e9ab030014610eca578063edd7db7514610f0257600080fd5b8063d5c4b08a1161012d578063dadee88a11610112578063dadee88a14610e68578063df6f55f514610e95578063dfc8bf4e14610eaa57600080fd5b8063d5c4b08a14610e3a578063da7a9b6a14610e5257600080fd5b8063cfef14411161015e578063cfef144114610de5578063d0ac76f614610e05578063d290c21d14610e2557600080fd5b8063c6912cc014610db0578063c6af311a14610dc557600080fd5b8063a420596711610227578063ae1aaf80116101db578063b710c15d116101c0578063b710c15d14610d43578063ba08d23714610d70578063bf348f8614610d9057600080fd5b8063ae1aaf8014610d0d578063b61ed63a14610d2357600080fd5b8063a697ecff1161020c578063a697ecff14610ca0578063a711e6a114610cd8578063adddc0cf14610cf857600080fd5b8063a420596714610c53578063a5d54f6514610c8b57600080fd5b80639a7b5f111161027e5780639e6c2959116102635780639e6c295914610bfd5780639e72c63514610c135780639ea8082b14610c3357600080fd5b80639a7b5f1114610bb85780639b03d74414610be757600080fd5b8063921e274b116102af578063921e274b14610b62578063950a651314610b75578063957950a714610b9557600080fd5b8063862be28714610b055780638da5cb5b14610b2557600080fd5b80634f9a8d8f11610426578063715018a6116103835780637b0a0f9b116103375780637d8149db1161031c5780637d8149db14610a985780638247a23914610ab857806384725c7614610ad857600080fd5b80637b0a0f9b14610a585780637b15b94c14610a7857600080fd5b806373c218031161036857806373c21803146109d2578063750dd2a1146109f2578063794c0c6814610a4257600080fd5b8063715018a614610987578063728345db1461099c57600080fd5b80635fef7643116103da578063673a2a1f116103bf578063673a2a1f1461092f5780636bda1577146109515780637069e7461461097157600080fd5b80635fef7643146108e3578063615f2b71146108f957600080fd5b8063567e98f91161040b578063567e98f9146108975780635b4eafe0146108ad5780635d80ca32146108cd57600080fd5b80634f9a8d8f146108545780635267e1d61461086a57600080fd5b806326476204116104d45780633b7d0946116104885780634160d3861161046d5780634160d386146107e75780634346845f146108075780634e9b426d1461082757600080fd5b80633b7d0946146107b45780633f3afe01146107d457600080fd5b80633219d600116104b95780633219d600146107495780633715426314610789578063379b046a1461079e57600080fd5b806326476204146107165780632bafde8d1461072957600080fd5b80631555371c1161052b57806320c07cd81161051057806320c07cd8146106cb57806322e3d986146106e1578063251441a9146106f657600080fd5b80631555371c1461063a5780631fb31e431461064f57600080fd5b8063028b8bdb1461057f5780630ac6e291146105a85780630b770cdf146105ca5780631345b8a51461060257600080fd5b3661057a57604051631574f9f360e01b815260040160405180910390fd5b600080fd5b34801561058b57600080fd5b5061059560145481565b6040519081526020015b60405180910390f35b3480156105b457600080fd5b506105c86105c336600461534f565b611010565b005b3480156105d657600080fd5b506024546105ea906001600160a01b031681565b6040516001600160a01b03909116815260200161059f565b34801561060e57600080fd5b5061059561061d3660046153ff565b602160209081526000928352604080842090915290825290205481565b34801561064657600080fd5b506105c86115a7565b34801561065b57600080fd5b5061069961066a36600461542f565b6001600160a01b03166000908152601e6020526040902060010154608081901b91600160801b90910460f01b90565b604080516fffffffffffffffffffffffffffffffff1990931683526001600160f01b031990911660208301520161059f565b3480156106d757600080fd5b506105956107d081565b3480156106ed57600080fd5b50610595611619565b34801561070257600080fd5b506105c861071136600461544c565b611660565b6105c861072436600461542f565b61171e565b34801561073557600080fd5b506105c861074436600461548d565b6117a1565b34801561075557600080fd5b5061077961076436600461542f565b601f6020526000908152604090205460ff1681565b604051901515815260200161059f565b34801561079557600080fd5b506105c8611822565b3480156107aa57600080fd5b50610595601a5481565b3480156107c057600080fd5b506105c86107cf36600461542f565b611c1d565b6105c86107e23660046154a6565b611c53565b3480156107f357600080fd5b506105c86108023660046154a6565b611f89565b34801561081357600080fd5b506105c86108223660046154ef565b612028565b34801561083357600080fd5b5061084761084236600461542f565b61212e565b60405161059f91906155a0565b34801561086057600080fd5b5061059560165481565b34801561087657600080fd5b5061059561088536600461542f565b601b6020526000908152604090205481565b3480156108a357600080fd5b50610595601c5481565b3480156108b957600080fd5b506105956108c83660046153ff565b6121da565b3480156108d957600080fd5b50610595600e5481565b3480156108ef57600080fd5b50610595600c5481565b34801561090557600080fd5b506105ea61091436600461542f565b6025602052600090815260409020546001600160a01b031681565b34801561093b57600080fd5b50610944612204565b60405161059f91906155b3565b34801561095d57600080fd5b5061059561096c366004615600565b612215565b34801561097d57600080fd5b5061059560195481565b34801561099357600080fd5b506105c8612395565b3480156109a857600080fd5b506105956109b73660046153ff565b60208080526000928352604080842090915290825290205481565b3480156109de57600080fd5b506109446109ed36600461542f565b6123a9565b3480156109fe57600080fd5b50610595610a0d366004615600565b6001600160a01b039182166000908152600b602090815260408083209390941682529182528281206015548252909152205490565b348015610a4e57600080fd5b5061059560155481565b348015610a6457600080fd5b506105c8610a73366004615667565b6123cd565b348015610a8457600080fd5b506105c8610a9336600461542f565b61244a565b348015610aa457600080fd5b506105c8610ab33660046156ac565b6124b1565b348015610ac457600080fd5b506105c8610ad336600461548d565b612533565b348015610ae457600080fd5b50610595610af336600461542f565b60266020526000908152604090205481565b348015610b1157600080fd5b506105c8610b20366004615709565b612566565b348015610b3157600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03166105ea565b6105c8610b7036600461576e565b6125c9565b348015610b8157600080fd5b50610595610b90366004615600565b612712565b348015610ba157600080fd5b50610baa61285a565b60405161059f92919061582c565b348015610bc457600080fd5b50610bd8610bd336600461542f565b6128bd565b60405161059f9392919061584e565b348015610bf357600080fd5b5061059560185481565b348015610c0957600080fd5b5061059561271081565b348015610c1f57600080fd5b506105c8610c2e36600461548d565b612971565b348015610c3f57600080fd5b50610944610c4e36600461542f565b6129bc565b348015610c5f57600080fd5b50610595610c6e366004615600565b601160209081526000928352604080842090915290825290205481565b348015610c9757600080fd5b506109446129e0565b348015610cac57600080fd5b50610595610cbb366004615600565b601360209081526000928352604080842090915290825290205481565b348015610ce457600080fd5b50610779610cf336600461542f565b612a42565b348015610d0457600080fd5b506105c8612a4e565b348015610d1957600080fd5b5061059560175481565b348015610d2f57600080fd5b506105c8610d3e3660046154a6565b612a93565b348015610d4f57600080fd5b50610d63610d5e3660046158ab565b612dfa565b60405161059f919061595c565b348015610d7c57600080fd5b50610779610d8b36600461598a565b612eaa565b348015610d9c57600080fd5b50610d63610dab3660046156ac565b613085565b348015610dbc57600080fd5b5061059561312a565b348015610dd157600080fd5b506105c8610de03660046154a6565b613149565b348015610df157600080fd5b506105c8610e0036600461542f565b6131f3565b348015610e1157600080fd5b506105c8610e203660046153ff565b6133c6565b348015610e3157600080fd5b50610944613505565b348015610e4657600080fd5b506105c8610384601755565b348015610e5e57600080fd5b50610595600d5481565b348015610e7457600080fd5b50610595610e8336600461542f565b60106020526000908152604090205481565b348015610ea157600080fd5b50610944613511565b348015610eb657600080fd5b50601d546105ea906001600160a01b031681565b348015610ed657600080fd5b50610595610ee5366004615600565b600f60209081526000928352604080842090915290825290205481565b348015610f0e57600080fd5b506105c861351d565b348015610f2357600080fd5b506105c861365d565b348015610f3857600080fd5b50610595610bb881565b348015610f4e57600080fd5b506105c8610f5d36600461542f565b6136a3565b348015610f6e57600080fd5b506105c8610f7d3660046154a6565b6136de565b348015610f8e57600080fd5b506001610779565b348015610fa257600080fd5b50610779610fb136600461542f565b613797565b348015610fc257600080fd5b50610595610fd136600461542f565b60276020526000908152604090205481565b348015610fef57600080fd5b50610595610ffe36600461542f565b60126020526000908152604090205481565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff1660008115801561105b5750825b905060008267ffffffffffffffff1660011480156110785750303b155b905081158015611086575080155b156110a45760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156110d857845468ff00000000000000001916680100000000000000001785555b6001600160a01b038b166110ff5760405163d92e233d60e01b815260040160405180910390fd5b6111088a6137b4565b8761111660408c018c6159a6565b61112291506002615a06565b1461113f5760405162d6988760e81b815260040160405180910390fd5b8561114d60408c018c6159a6565b90501461116d576040516320041afd60e01b815260040160405180910390fd5b6111768b613917565b61117e613928565b61118b60208b018b61542f565b601d80546001600160a01b0319166001600160a01b03929092169190911790556111bb60408b0160208c0161542f565b602480546001600160a01b0319166001600160a01b03929092169190911790553660006111eb60408d018d6159a6565b9150915060005b8181101561140e57600083838381811061120e5761120e615a1d565b9050602002016020810190611223919061542f565b6001600160a01b03160361124a5760405163d92e233d60e01b815260040160405180910390fd5b61127b83838381811061125f5761125f615a1d565b9050602002016020810190611274919061542f565b6000613938565b6112aa83838381811061129057611290615a1d565b90506020020160208101906112a5919061542f565b613998565b8b8b6112b7836002615a06565b8181106112c6576112c6615a1d565b905060200201358c8c8360026112dc9190615a06565b6112e7906001615a33565b8181106112f6576112f6615a1d565b90506020020135604051602001611317929190918252602082015260400190565b604051602081830303815290604052601e600085858581811061133c5761133c615a1d565b9050602002016020810190611351919061542f565b6001600160a01b031681526020810191909152604001600020906113759082615ad0565b5089898281811061138857611388615a1d565b905060200201602081019061139d9190615b90565b601e60008585858181106113b3576113b3615a1d565b90506020020160208101906113c8919061542f565b6001600160a01b031681526020810191909152604001600020600190810180546fffffffffffffffffffffffffffffffff191660809390931c92909217909155016111f2565b5060408051600580825260c082019092526000916020820160a0803683370190505090506802b5e3af16b18800008160008151811061144f5761144f615a1d565b60200260200101818152505068056bc75e2d631000008160018151811061147857611478615a1d565b602002602001018181525050680821ab0d4414980000816002815181106114a1576114a1615a1d565b602002602001018181525050680ad78ebc5ac6200000816003815181106114ca576114ca615a1d565b602002602001018181525050680d8d726b7177a80000816004815181106114f3576114f3615a1d565b6020908102919091010152611517632bafde8d60e01b636d3d4db560e11b836139ad565b50505060608a0135600d5560808a0135600c5560a08a0135600e5560c08a01356016556101008a01356014554260185560e08a0135601755831561159a57845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050505050565b601d546001600160a01b031633146115d1576040516282b42960e81b815260040160405180910390fd5b60006115dd6004613a62565b905060005b81518110156116155761160d82828151811061160057611600615a1d565b6020026020010151613a76565b6001016115e2565b5050565b601854601654600091901561162f576001611632565b60005b60ff16601a54601654836116469190615a33565b6116509190615a33565b61165a9190615bab565b91505090565b3a60000361168157604051630e661aed60e41b815260040160405180910390fd5b816001600160a01b0316836001600160a01b0316036116b357604051630a5eddd560e01b815260040160405180910390fd5b336116bf848284613abc565b6116ca838284613d6a565b601554604080516001600160a01b0387811682526020820186905280851692908716917f4480d8e4b1e9095b94bf513961d26fe1d32386ebdd103d18fe8738cf4b2223ff910160405180910390a450505050565b3a60000361173f57604051630e661aed60e41b815260040160405180910390fd5b333461174c838383613d6a565b601554826001600160a01b0316846001600160a01b03167f2273de02cb1f69ba6259d22c4bc22c60e4c94c193265ef6afee324a04a9b6d228460405161179491815260200190565b60405180910390a4505050565b6117a96140bb565b806117c06000356001600160e01b03191682612eaa565b6117e5576040516373330d9b60e01b8152600481018290526024015b60405180910390fd5b600d8290556040518281527ffee02ce7aa40f9c49eaabd26d404fa88714b97cb209af8954cfd5eeb8213b93e906020015b60405180910390a15050565b3a60000361184357604051630e661aed60e41b815260040160405180910390fd5b6000806118506002613a62565b9050805160000361187457604051631c369b4560e21b815260040160405180910390fd5b60005b8151811015611a5c57600082828151811061189457611894615a1d565b602002602001015190506118a781614116565b8061191d5750601d54604051639d6fc1d160e01b81526001600160a01b03838116600483015290911690639d6fc1d190602401602060405180830381865afa1580156118f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191b9190615bbe565b155b156119285750611a54565b611933600282614154565b506001600160a01b0381166000908152601f60209081526040808320805460ff19166001179055601b9091528120805490829055601c80549192839261197a908490615bab565b909155506000905061198b836129bc565b905060005b81518110156119f65760008282815181106119ad576119ad615a1d565b6020908102919091018101516001600160a01b03808816600090815260138452604080822092841682529190935282209190915590506119ed8582614169565b50600101611990565b50611a018287615a33565b9550826001600160a01b0316336001600160a01b03167f8e6a4ccd7dccdca9ac211d00fcc3fa7c71be75ff73d3a35f63ea023173cc100484604051611a4891815260200190565b60405180910390a35050505b600101611877565b5081600003611a7e57604051631c369b4560e21b815260040160405180910390fd5b6000611a8b600284615be0565b90506000611a998285615bab565b90506000601d60009054906101000a90046001600160a01b03166001600160a01b03166356b54bae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b149190615c02565b90506000816001600160a01b031663732524946040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b7a9190615c02565b9050816001600160a01b031663af182535846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611bb757600080fd5b505af1158015611bcb573d6000803e3d6000fd5b5050505050611bda81856141cb565b604080518481526020810186905233917f1c113e6bae9530fea40323e612aeb0cb7817dedb5a0b0f6bdfbff97d55920dc7910160405180910390a2505050505050565b601d546001600160a01b03163314611c47576040516282b42960e81b815260040160405180910390fd5b611c5081613a76565b50565b601d60009054906101000a90046001600160a01b03166001600160a01b03166356b54bae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ca6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cca9190615c02565b6001600160a01b0316336001600160a01b031614611cfa576040516282b42960e81b815260040160405180910390fd5b3415611615576015546000908152602080805260408083206001600160a01b03861684529091528120543491611d31858486614272565b90506000611d3e866129bc565b905060005b8151811015611e8d57600084611d756015548a868681518110611d6857611d68615a1d565b6020026020010151614391565b8560400151611d849190615a06565b611d8e9190615be0565b905080601360008a6001600160a01b03166001600160a01b031681526020019081526020016000206000858581518110611dca57611dca615a1d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254611e019190615a33565b90915550506001600160a01b0388166000908152600b602052604081208451839290869086908110611e3557611e35615a1d565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600060155481526020019081526020016000206000828254611e7f9190615a33565b909155505050600101611d43565b50602082015115611ea657611ea6868360200151614432565b81516001600160a01b038716600090815260136020908152604080832090915281208054909190611ed8908490615a33565b90915550506001600160a01b0386166000908152601b602052604081208054869290611f05908490615a33565b9250508190555083601c6000828254611f1e9190615a33565b90915550611f2d9050866144f9565b60155482516001600160a01b038816907f72093068b9f28053bd924ac15d7710b987f9b6ef1e0f89f47d8b4bd7cac776dc90611f698189615bab565b6040805192835260208301919091520160405180910390a3505050505050565b601d546040516253517560e01b81523360048201526000916001600160a01b0316906253517590602401602060405180830381865afa158015611fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ff49190615c02565b6001600160a01b03160361201d57604051632670461960e11b81523360048201526024016117dc565b6116153383836145e5565b6120306140bb565b600061203a61471d565b90506040518060400160405280857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200184848080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509390945250506001600160e01b031988168152602084815260409091208351815463ffffffff191660e09190911c1781558382015180519193506120e6926001850192910190615274565b509050507f3665bf9cd0ba4ddceeec259e21dcf8a4510f3b1130bd42e950828e69d85408ba8585858560405161211f9493929190615c1f565b60405180910390a15050505050565b6001600160a01b0381166000908152601e6020526040902080546060919061215590615a46565b80601f016020809104026020016040519081016040528092919081815260200182805461218190615a46565b80156121ce5780601f106121a3576101008083540402835291602001916121ce565b820191906000526020600020905b8154815290600101906020018083116121b157829003601f168201915b50505050509050919050565b60008281526021602090815260408083206001600160a01b03851684529091529020545b92915050565b60606122106000613a62565b905090565b601d546040516253517560e01b81526001600160a01b03848116600483015260009283929116906253517590602401602060405180830381865afa158015612261573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122859190615c02565b90506001600160a01b0384166000908152601f602052604090205460ff16156122b25760009150506121fe565b6001600160a01b03848116600090815260136020908152604080832087851684529091529081902054601d54915163a0d16cad60e01b815284841660048201529092919091169063a0d16cad90602401602060405180830381865afa15801561231f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123439190615bbe565b6123505791506121fe9050565b6001600160a01b038581166000908152600b6020908152604080832093881683529281528282206015548352905220548082111561238c578091505b50949350505050565b61239d6140bb565b6123a7600061477f565b565b6001600160a01b0381166000908152600a602052604090206060906121fe90613a62565b601d546001600160a01b031633146123f7576040516282b42960e81b815260040160405180910390fd5b6001600160a01b039092166000908152601e60205260409020600101805460f09390931c600160801b0271ffffffffffffffffffffffffffffffffffff1990931660809290921c91909117919091179055565b601d546001600160a01b03163314612474576040516282b42960e81b815260040160405180910390fd5b600c546001600160a01b038216600090815260136020908152604080832090915290205410611c50576124a8816001613938565b611c50816144f9565b6124b96140bb565b60006124c361471d565b6001600160e01b031983166000908152602082905260408120805463ffffffff191681559192506124f760018301826152bf565b50506040516001600160e01b0319831681527fed27cb02231782dadf13473a7828cb980c4d685791b7a3136dde00f8c3594cb690602001611816565b601d546001600160a01b0316331461255d576040516282b42960e81b815260040160405180910390fd5b60185543601955565b336000908152601e60205260409020612580848683615c8c565b50336000908152601e60205260409020600101805460f09290921c600160801b0271ffffffffffffffffffffffffffffffffffff1990921660809390931c929092171790555050565b3a6000036125ea57604051630e661aed60e41b815260040160405180910390fd5b601d54604051630526083960e11b81526001600160a01b0388811660048301523360248301819052923492911690630a4c107290604401600060405180830381600087803b15801561263b57600080fd5b505af115801561264f573d6000803e3d6000fd5b505050506001600160a01b0382166000908152601e60205260409020612676858783615c8c565b506001600160a01b0382166000908152601e6020526040902060010180546fffffffffffffffffffffffffffffffff1916608085901c1790556126ba8288886145e5565b6126c5828383613d6a565b6015546040518281526001600160a01b0384169081907f2273de02cb1f69ba6259d22c4bc22c60e4c94c193265ef6afee324a04a9b6d229060200160405180910390a45050505050505050565b601d546040516253517560e01b81526001600160a01b03848116600483015260009283929116906253517590602401602060405180830381865afa15801561275e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127829190615c02565b9050601d5460405163a0d16cad60e01b81526001600160a01b0383811660048301529091169063a0d16cad90602401602060405180830381865afa1580156127ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127f29190615bbe565b6128005760009150506121fe565b6001600160a01b038481166000818152600b6020908152604080832094881680845294825280832060155484528252808320549383526013825280832094835293905291909120546128529190615bab565b949350505050565b606060006007600854818054806020026020016040519081016040528092919081815260200182805480156128ae57602002820191906000526020600020905b81548152602001906001019080831161289a575b50505050509150915091509091565b601e602052600090815260409020805481906128d890615a46565b80601f016020809104026020016040519081016040528092919081815260200182805461290490615a46565b80156129515780601f1061292657610100808354040283529160200191612951565b820191906000526020600020905b81548152906001019060200180831161293457829003601f168201915b50505060019093015491925050608081901b90600160801b900460f01b83565b601d546001600160a01b0316331461299b576040516282b42960e81b815260040160405180910390fd5b60175481601a546129ac9190615a33565b6129b69190615a33565b601a5550565b6001600160a01b03811660009081526009602052604090206060906121fe90613a62565b60606006805480602002602001604051908101604052809291908181526020018280548015612a3857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a1a575b5050505050905090565b60006121fe81836147f0565b601d546001600160a01b03163314612a78576040516282b42960e81b815260040160405180910390fd5b601754601a6000828254612a8c9190615a33565b9091555050565b3a600003612ab457604051630e661aed60e41b815260040160405180910390fd5b6001600160a01b038216612adb5760405163d92e233d60e01b815260040160405180910390fd5b80600003612afc57604051633ca0029d60e01b815260040160405180910390fd5b6001600160a01b0382166000818152600f602090815260408083203380855290835281842054858552601084528285205460138552838620838752855283862054968652601b9094529184205490949193861315612c0657856000612b618988612712565b905080821115612b8e57604051632de4882160e01b815260048101829052602481018390526044016117dc565b612b988287615a33565b9550612ba48286615a33565b9450612bb08285615bab565b9350612bbc8284615bab565b925081601c6000828254612bd09190615bab565b90915550506015546001600160a01b03808b166000908152601160209081526040808320938c168352929052205550612c5c9050565b6000612c1187615d4d565b9050612c1d8186615bab565b9450612c298185615bab565b9350612c358184615a33565b9250612c418183615a33565b915080601c6000828254612c559190615a33565b9091555050505b6001600160a01b038088166000818152600f60209081526040808320948a1680845294825280832089905583835260108252808320889055601382528083208584528252808320879055838352601b90915290208390559003612d2b578115801590612cc95750600c5482105b15612d0157604051636fe84f3d60e01b81526001600160a01b03808916600483015286166024820152604481018790526064016117dc565b6000861315612d205781600003612d1b57612d1b87613998565b612d98565b612d1b876001613938565b8115801590612d3b5750600d5482105b15612d7357604051636fe84f3d60e01b81526001600160a01b03808916600483015286166024820152604481018790526064016117dc565b6000861315612d8e5781600003612d1b57612d1b8786614169565b612d988786614812565b612da1876144f9565b601554856001600160a01b0316886001600160a01b03167f80d5c777e5f7ac6ee89723223803ca5c0ec0204f89e99c1b0cde973c66a6459489604051612de991815260200190565b60405180910390a450505050505050565b604080518082019091526000815260606020820152612e1761471d565b82516020808501919091206001600160e01b0319908116600090815292825260409283902083518085018552815460e01b9092168252600181018054855181860281018601909652808652929491938581019390830182828015612e9a57602002820191906000526020600020905b815481526020019060010190808311612e86575b5050505050815250509050919050565b600080612eb561471d565b6001600160e01b031980861660009081526020838152604080832081518083018352815460e01b90951685526001810180548351818602810186019094528084529697509395909385840193909190830182828015612f3357602002820191906000526020600020905b815481526020019060010190808311612f1f575b5050505050815250509050806020015151600003612f56576000925050506121fe565b60208101518151600090612f699061483f565b905060005b82518110156130775781838281518110612f8a57612f8a615a1d565b60200260200101510361306f576000808211612fc05783600081518110612fb357612fb3615a1d565b6020026020010151612fe5565b83612fcc600184615bab565b81518110612fdc57612fdc615a1d565b60200260200101515b9050600060018551612ff79190615bab565b831061302957846001865161300c9190615bab565b8151811061301c5761301c615a1d565b602002602001015161304e565b84613035846001615a33565b8151811061304557613045615a1d565b60200260200101515b90508189141580156130605750808914155b159750505050505050506121fe565b600101612f6e565b506000979650505050505050565b6040805180820190915260008152606060208201526130a261471d565b6001600160e01b03198084166000908152602092835260409081902081518083018352815460e01b9093168352600181018054835181870281018701909452808452939491938583019392830182828015612e9a5760200282019190600052602060002090815481526020019060010190808311612e86575050505050815250509050919050565b600060175460165460185461313f9190615a33565b6122109190615bab565b6024546001600160a01b03163314613173576040516282b42960e81b815260040160405180910390fd5b601d546040516307b9342f60e21b81526001600160a01b0384811660048301526000921690631ee4d0bc90602401602060405180830381865afa1580156131be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e29190615c02565b90506131ee8183614916565b505050565b3a60000361321457604051630e661aed60e41b815260040160405180910390fd5b61321c6149c0565b6001600160a01b0381166000908152601160209081526040808320338085529252909120546015541161327557604051630b06352b60e31b81526001600160a01b038084166004830152821660248201526044016117dc565b6001600160a01b038083166000908152600f60209081526040808320938516835292905290812054908190036132be57604051633ca0029d60e01b815260040160405180910390fd5b6001600160a01b038084166000818152600f602090815260408083209487168352938152838220829055918152601090915220546132fd908290615bab565b6001600160a01b0380851660009081526010602090815260408083209490945560138152838220928616825291909152908120549003613341576133418383614a0a565b61334b82826141cb565b601554826001600160a01b0316846001600160a01b03167ff380b0bc887e00f5b50d3c9d4eaaf5c9a0afd97b956316b995159384c4ede9b38460405161339391815260200190565b60405180910390a45050611c5060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b601d60009054906101000a90046001600160a01b03166001600160a01b03166356b54bae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613419573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343d9190615c02565b6001600160a01b0316336001600160a01b03161461346d576040516282b42960e81b815260040160405180910390fd5b6000828152602080805260408083206001600160a01b03851684529091528120549003611615576001600160a01b0381166000908152601b6020526040812054908190036134ba57505050565b6000838152602080805260408083206001600160a01b038616808552908352818420949094556013825280832082528083205486845260218352818420948452939091529020555050565b60606122106004613a62565b60606122106002613a62565b3a60000361353e57604051630e661aed60e41b815260040160405180910390fd5b601d546040516253517560e01b81523360048201819052916000916001600160a01b03909116906253517590602401602060405180830381865afa15801561358a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ae9190615c02565b9050601554600014801561362b5750601d5460405163facd743b60e01b81526001600160a01b0383811660048301529091169063facd743b90602401602060405180830381865afa158015613607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061362b9190615bbe565b15613654576040516303d71f2d60e51b81526001600160a01b03831660048201526024016117dc565b61161582613a76565b601d546001600160a01b03163314613687576040516282b42960e81b815260040160405180910390fd5b6015805490600061369783615d69565b90915550506000601a55565b6136ab6140bb565b6001600160a01b0381166136d557604051631e4fbdf760e01b8152600060048201526024016117dc565b611c508161477f565b3a6000036136ff57604051630e661aed60e41b815260040160405180910390fd5b6137076149c0565b33613713838284613abc565b61371d81836141cb565b601554816001600160a01b0316846001600160a01b03167fa7c0f0cac6bd4d18042007706c84a8abe823751cf289b69c01e83eef7b5915c78560405161376591815260200190565b60405180910390a45061161560017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b60006137a381836147f0565b806121fe57506121fe6002836147f0565b60c081013515806137ce57508061010001358160c0013511155b156137ec5760405163c671116b60e01b815260040160405180910390fd5b806101000135600003613812576040516332154b4760e01b815260040160405180910390fd5b60e0810135158061382b57508060c001358160e0013510155b1561384957604051630685efe960e01b815260040160405180910390fd5b6000613858602083018361542f565b6001600160a01b03160361387f5760405163d92e233d60e01b815260040160405180910390fd5b61388c60408201826159a6565b90506000036138ae57604051635c9a24ed60e11b815260040160405180910390fd5b606081013515806138c157506080810135155b156138ef5760405163633373e160e11b815260808201356004820152606082013560248201526044016117dc565b80608001358160a0013511611c5057604051631c6d3b1560e01b815260040160405180910390fd5b61391f614b60565b611c5081614bae565b613930614b60565b6123a7614bb6565b61394182612a42565b61397d57613950600083614bbe565b50610bb861395e6000614bd3565b111561397d5760405163398dcd9d60e21b815260040160405180910390fd5b613988600283614154565b5080156116155761161582614bdd565b6139a3600482614bbe565b50611c5081614cd2565b6139b5614b60565b60006139bf61471d565b6040805180820182526001600160e01b0319868116825260208083018781529189166000908152858252939093208251815463ffffffff191660e09190911c1781559051805194955091939092613a1d926001850192910190615274565b509050507f3665bf9cd0ba4ddceeec259e21dcf8a4510f3b1130bd42e950828e69d85408ba848484604051613a5493929190615d82565b60405180910390a150505050565b60606000613a6f83614eef565b9392505050565b613a81600082614154565b50613a8b81614116565b15613aa157613a9b600282614154565b50613aaa565b613aaa81614f4a565b613ab381614cd2565b611c5081614f55565b6001600160a01b038316613ae35760405163d92e233d60e01b815260040160405180910390fd5b80600003613b0457604051633ca0029d60e01b815260040160405180910390fd5b6000613b108484612215565b905080821115613b3d57604051632de4882160e01b815260048101829052602481018390526044016117dc565b6001600160a01b038085166000908152601360209081526040808320938716835292905290812054613b70908490615bab565b90506000846001600160a01b0316866001600160a01b031614613b9557600d54613b99565b600c545b90508115801590613ba957508082105b15613be157604051639e612d5760e01b81526001600160a01b03808816600483015286166024820152604481018590526064016117dc565b856001600160a01b0316856001600160a01b031614613c7657601d546040516253517560e01b81526001600160a01b03888116600483015260009216906253517590602401602060405180830381865afa158015613c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c679190615c02565b9050613c74878288614f60565b505b6001600160a01b038681166000818152601360209081526040808320948a16808452948252808320879055928252600b8152828220938252928352818120601554825290925290205484811015613cce576000613cd8565b613cd88582615bab565b6001600160a01b038089166000818152600b60209081526040808320948c1683529381528382206015548352815283822094909455908152601b90925281208054879290613d27908490615bab565b9250508190555084601c6000828254613d409190615bab565b90915550506000839003613d5857613d588787614a0a565b613d61876144f9565b50505050505050565b6001600160a01b038316613d915760405163d92e233d60e01b815260040160405180910390fd5b601d546040516253517560e01b81526001600160a01b03858116600483015260009216906253517590602401602060405180830381865afa158015613dda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dfe9190615c02565b90506001600160a01b038116613e3257604051632670461960e11b81526001600160a01b03851660048201526024016117dc565b81600003613e665760405163e59f5c3960e01b81526001600160a01b038086166004830152841660248201526044016117dc565b6001600160a01b0384166000908152601f602052604090205460ff1615613eab5760405163078137eb60e41b81526001600160a01b03851660048201526024016117dc565b6001600160a01b038085166000818152601360209081526040808320948816808452949091528120549290911491613ee4908590615a33565b905060008215613ef75750600c54613f46565b50600d546001600160a01b03871660009081526013602090815260408083209091528120549003613f465760405163cbbeb0bd60e01b81526001600160a01b03881660048201526024016117dc565b80821015613f7a5760405163e59f5c3960e01b81526001600160a01b038089166004830152871660248201526044016117dc565b600e546001600160a01b0388166000908152601b6020526040902054613fa1908790615a33565b1115613fd357604051632c2b174160e21b81526001600160a01b038089166004830152871660248201526044016117dc565b6001600160a01b038088166000908152600b60209081526040808320938a168352928152828220601554835290529081208054879290614014908490615a33565b90915550506001600160a01b0387166000908152601b602052604081208054879290614041908490615a33565b9250508190555084601c600082825461405a9190615a33565b9091555050821561407557614070876001613938565b61408a565b61407f8787614812565b61408a878588614f60565b6001600160a01b038088166000908152601360209081526040808320938a16835292905220829055613d61876144f9565b336140ed7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146123a75760405163118cdaa760e01b81523360048201526024016117dc565b6001600160a01b0381166000908152601b60205260408120541580156121fe5750506001600160a01b03166000908152601060205260409020541590565b6000613a6f836001600160a01b03841661507c565b6001600160a01b038216600090815260096020526040902061418b9082614154565b506001600160a01b038083166000908152600f6020908152604080832093851683529290522054156141c157611615828261516f565b6116158282615191565b804710156141ec57604051631e9acf1760e31b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614239576040519150601f19603f3d011682016040523d82523d6000602084013e61423e565b606091505b50509050806131ee57604051630e21dcbb60e11b81526001600160a01b0384166004820152602481018390526044016117dc565b61429660405180606001604052806000815260200160008152602001600081525090565b6015546000818152602080805260408083206001600160a01b03891680855290835281842054948452602183528184209084529091528120549060646142dc8688615a06565b6142e69190615be0565b90506142f28187615bab565b6040808601919091526001600160a01b0380891660009081526026602090815283822054602590915292902054161580159061432d57508015155b1561434f5761271061433f8289615a06565b6143499190615be0565b60208601525b838386604001516143609190615a06565b61436a9190615be0565b60208601516143799084615bab565b6143839190615a33565b855250929695505050505050565b6000836000036143a357506000613a6f565b6001600160a01b0380841660009081526023602090815260408083209386168352929052205484900361440457506001600160a01b038083166000908152602260209081526040808320938516835292815282822086835290522054613a6f565b506001600160a01b038083166000908152601360209081526040808320938516835292905220549392505050565b6001600160a01b03808316600090815260256020908152604080832054600990925290912091169061446490826147f0565b614472576144728382614812565b6001600160a01b038084166000908152601360209081526040808320938516835292905290812080548492906144a9908490615a33565b90915550506001600160a01b038084166000908152600b6020908152604080832093851683529281528282206015548352905290812080548492906144ef908490615a33565b9091555050505050565b601d546040516253517560e01b81526001600160a01b03838116600483015260009216906253517590602401602060405180830381865afa158015614542573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145669190615c02565b60248054604051633941e77760e21b81526001600160a01b0380851660048301529394506000939091169163e5079ddc9101602060405180830381865afa1580156145b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145d99190615daf565b90506131ee8382614916565b6107d081111561460b5760405163e429b69160e01b8152600481018290526024016117dc565b6001600160a01b03821615801561462157508015155b156146515760405163073c315960e11b81526001600160a01b0383166004820152602481018290526044016117dc565b6001600160a01b038316600090815260276020526040902054801580159061467a575060155481145b1561469e5760155460405163e7cbc70160e01b81526004016117dc91815260200190565b6001600160a01b03848116600081815260256020908152604080832080546001600160a01b03191695891695861790556026825280832087905560155460278352928190209290925590518581527fd6ae57aa2cc060d4094c47d20c672afe0e53963e6459c15cab215abb8c88b863910160405180910390a350505050565b60008060ff1961474e60017fdace3fd3d1fbdfd33853f19ba191d28c617e373ec58fc73cf7b58db5aff2c2ab615bab565b60405160200161476091815260200190565b60408051601f1981840301815291905280516020909101201692915050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b6001600160a01b03811660009081526001830160205260408120541515613a6f565b6001600160a01b03821660009081526009602052604090206148349082614bbe565b506116158282615191565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03198516179052905160009190829081903090614896908590615dc8565b600060405180830381855afa9150503d80600081146148d1576040519150601f19603f3d011682016040523d82523d6000602084013e6148d6565b606091505b5091509150816148f957604051635fbab09b60e11b815260040160405180910390fd5b8080602001905181019061490d9190615daf565b95945050505050565b600080614922846151b3565b91509150816149315750505050565b60006007828154811061494657614946615a1d565b60009182526020808320909101546001600160a01b0388168352601b9091526040822054909250614978908690615a06565b9050806007848154811061498e5761498e615a1d565b906000526020600020018190555080826008546149ab9190615bab565b6149b59190615a33565b600855505050505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901614a0457604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b816001600160a01b0316816001600160a01b031603614b1757601d546040516253517560e01b81526001600160a01b03848116600483015260009216906253517590602401602060405180830381865afa158015614a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a909190615c02565b601d5460405163facd743b60e01b81526001600160a01b03808416600483015292935091169063facd743b90602401602060405180830381865afa158015614adc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b009190615bbe565b15614b0e576131ee83613998565b6131ee83613a76565b614b218282614169565b614b2a82614116565b15611615576131ee600283614154565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff166123a757604051631afcd79f60e31b815260040160405180910390fd5b6136ab614b60565b614b3a614b60565b6000613a6f836001600160a01b038416615225565b60006121fe825490565b6001600160a01b0381166000908152601260205260409020546006548082101580614c385750826001600160a01b031660068381548110614c2057614c20615a1d565b6000918252602090912001546001600160a01b031614155b15614cc9576001600160a01b03831660008181526012602052604081208390556006805460018181019092557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0180546001600160a01b03191690931790925560078054928301815581527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909101555b6131ee83614f55565b60075460065414614ce05750565b6001600160a01b03811660009081526012602052604090205460065481108015614d395750816001600160a01b031660068281548110614d2257614d22615a1d565b6000918252602090912001546001600160a01b0316145b156116155760078181548110614d5157614d51615a1d565b906000526020600020015460085410614d9e5760078181548110614d7757614d77615a1d565b906000526020600020015460086000828254614d939190615bab565b90915550614da49050565b60006008555b600654600090614db690600190615bab565b9050600060068281548110614dcd57614dcd615a1d565b600091825260209091200154600680546001600160a01b039092169250829185908110614dfc57614dfc615a1d565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060078281548110614e3d57614e3d615a1d565b906000526020600020015460078481548110614e5b57614e5b615a1d565b60009182526020808320909101929092556001600160a01b038084168252601290925260408082208690559186168152908120556006805480614ea057614ea0615de4565b600082815260209020810160001990810180546001600160a01b03191690550190556007805480614ed357614ed3615de4565b6001900381819060005260206000200160009055905550505050565b6060816000018054806020026020016040519081016040528092919081815260200182805480156121ce57602002820191906000526020600020905b815481526020019060010190808311614f2b5750505050509050919050565b611615600282614bbe565b611615600482614154565b601d5460405163a0d16cad60e01b81526001600160a01b0384811660048301529091169063a0d16cad90602401602060405180830381865afa158015614faa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614fce9190615bbe565b1580614fda5750601554155b15614fe457505050565b6001600160a01b03808416600090815260236020908152604080832093851683529290522054601554811015615076576001600160a01b0380851660008181526013602090815260408083209487168084529482528083205484845260228352818420868552835281842060158054865290845282852091909155549383526023825280832094835293905291909120555b50505050565b600081815260018301602052604081205480156151655760006150a0600183615bab565b85549091506000906150b490600190615bab565b90508082146151195760008660000182815481106150d4576150d4615a1d565b90600052602060002001549050808760000184815481106150f7576150f7615a1d565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061512a5761512a615de4565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506121fe565b60009150506121fe565b6001600160a01b0382166000908152600a602052604090206131ee9082614bbe565b6001600160a01b0382166000908152600a602052604090206131ee9082614154565b6001600160a01b0381166000908152601260205260408120546006548110801561520c5750826001600160a01b0316600682815481106151f5576151f5615a1d565b6000918252602090912001546001600160a01b0316145b1561521a5760019150915091565b506000928392509050565b600081815260018301602052604081205461526c575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556121fe565b5060006121fe565b8280548282559060005260206000209081019282156152af579160200282015b828111156152af578251825591602001919060010190615294565b506152bb9291506152d9565b5090565b5080546000825590600052602060002090810190611c5091905b5b808211156152bb57600081556001016152da565b6001600160a01b0381168114611c5057600080fd5b60008083601f84011261531557600080fd5b50813567ffffffffffffffff81111561532d57600080fd5b6020830191508360208260051b850101111561534857600080fd5b9250929050565b6000806000806000806080878903121561536857600080fd5b8635615373816152ee565b9550602087013567ffffffffffffffff8082111561539057600080fd5b90880190610120828b0312156153a557600080fd5b909550604088013590808211156153bb57600080fd5b6153c78a838b01615303565b909650945060608901359150808211156153e057600080fd5b506153ed89828a01615303565b979a9699509497509295939492505050565b6000806040838503121561541257600080fd5b823591506020830135615424816152ee565b809150509250929050565b60006020828403121561544157600080fd5b8135613a6f816152ee565b60008060006060848603121561546157600080fd5b833561546c816152ee565b9250602084013561547c816152ee565b929592945050506040919091013590565b60006020828403121561549f57600080fd5b5035919050565b600080604083850312156154b957600080fd5b82356154c4816152ee565b946020939093013593505050565b80356001600160e01b0319811681146154ea57600080fd5b919050565b6000806000806060858703121561550557600080fd5b61550e856154d2565b935061551c602086016154d2565b9250604085013567ffffffffffffffff81111561553857600080fd5b61554487828801615303565b95989497509550505050565b60005b8381101561556b578181015183820152602001615553565b50506000910152565b6000815180845261558c816020860160208601615550565b601f01601f19169290920160200192915050565b602081526000613a6f6020830184615574565b6020808252825182820181905260009190848201906040850190845b818110156155f45783516001600160a01b0316835292840192918401916001016155cf565b50909695505050505050565b6000806040838503121561561357600080fd5b823561561e816152ee565b91506020830135615424816152ee565b80356fffffffffffffffffffffffffffffffff19811681146154ea57600080fd5b80356001600160f01b0319811681146154ea57600080fd5b60008060006060848603121561567c57600080fd5b8335615687816152ee565b92506156956020850161562e565b91506156a36040850161564f565b90509250925092565b6000602082840312156156be57600080fd5b613a6f826154d2565b60008083601f8401126156d957600080fd5b50813567ffffffffffffffff8111156156f157600080fd5b60208301915083602082850101111561534857600080fd5b6000806000806060858703121561571f57600080fd5b843567ffffffffffffffff81111561573657600080fd5b615742878288016156c7565b909550935061575590506020860161562e565b91506157636040860161564f565b905092959194509250565b60008060008060008060a0878903121561578757600080fd5b8635615792816152ee565b955060208701356157a2816152ee565b945060408701359350606087013567ffffffffffffffff8111156157c557600080fd5b6157d189828a016156c7565b90945092506157e490506080880161562e565b90509295509295509295565b60008151808452602080850194506020840160005b8381101561582157815187529582019590820190600101615805565b509495945050505050565b60408152600061583f60408301856157f0565b90508260208301529392505050565b6060815260006158616060830186615574565b6fffffffffffffffffffffffffffffffff19949094166020830152506001600160f01b031991909116604090910152919050565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156158bd57600080fd5b813567ffffffffffffffff808211156158d557600080fd5b818401915084601f8301126158e957600080fd5b8135818111156158fb576158fb615895565b604051601f8201601f19908116603f0116810190838211818310171561592357615923615895565b8160405282815287602084870101111561593c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b602080825282516001600160e01b0319168282015282015160408083015260009061285260608401826157f0565b6000806040838503121561599d57600080fd5b6154c4836154d2565b6000808335601e198436030181126159bd57600080fd5b83018035915067ffffffffffffffff8211156159d857600080fd5b6020019150600581901b360382131561534857600080fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176121fe576121fe6159f0565b634e487b7160e01b600052603260045260246000fd5b808201808211156121fe576121fe6159f0565b600181811c90821680615a5a57607f821691505b602082108103615a7a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156131ee576000816000526020600020601f850160051c81016020861015615aa95750805b601f850160051c820191505b81811015615ac857828155600101615ab5565b505050505050565b815167ffffffffffffffff811115615aea57615aea615895565b615afe81615af88454615a46565b84615a80565b602080601f831160018114615b335760008415615b1b5750858301515b600019600386901b1c1916600185901b178555615ac8565b600085815260208120601f198616915b82811015615b6257888601518255948401946001909101908401615b43565b5085821015615b805787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215615ba257600080fd5b613a6f8261562e565b818103818111156121fe576121fe6159f0565b600060208284031215615bd057600080fd5b81518015158114613a6f57600080fd5b600082615bfd57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615c1457600080fd5b8151613a6f816152ee565b6001600160e01b0319858116825284166020820152606060408201819052810182905260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115615c7157600080fd5b8260051b808560808501379190910160800195945050505050565b67ffffffffffffffff831115615ca457615ca4615895565b615cb883615cb28354615a46565b83615a80565b6000601f841160018114615cec5760008515615cd45750838201355b600019600387901b1c1916600186901b178355615d46565b600083815260209020601f19861690835b82811015615d1d5786850135825560209485019460019092019101615cfd565b5086821015615d3a5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6000600160ff1b8201615d6257615d626159f0565b5060000390565b600060018201615d7b57615d7b6159f0565b5060010190565b6001600160e01b031984811682528316602082015260606040820181905260009061490d908301846157f0565b600060208284031215615dc157600080fd5b5051919050565b60008251615dda818460208701615550565b9190910192915050565b634e487b7160e01b600052603160045260246000fdfea26469706673582212201e8e54a31c16c621fa88c77c6ff088a6e5e931cf9c5ea285dbbc5f542d912b4564736f6c63430008190033
Deployed ByteCode
0x60806040526004361061055c5760003560e01c8063862be287116102ca578063c6912cc011610179578063e9ab0300116100d6578063f3fef3a31161008a578063f6c578611161006f578063f6c5786114610f96578063f9d4d54414610fb6578063fa4aaf4714610fe357600080fd5b8063f3fef3a314610f62578063f494250114610f8257600080fd5b8063ee435f55116100bb578063ee435f5514610f17578063f078609614610f2c578063f2fde38b14610f4257600080fd5b8063e9ab030014610eca578063edd7db7514610f0257600080fd5b8063d5c4b08a1161012d578063dadee88a11610112578063dadee88a14610e68578063df6f55f514610e95578063dfc8bf4e14610eaa57600080fd5b8063d5c4b08a14610e3a578063da7a9b6a14610e5257600080fd5b8063cfef14411161015e578063cfef144114610de5578063d0ac76f614610e05578063d290c21d14610e2557600080fd5b8063c6912cc014610db0578063c6af311a14610dc557600080fd5b8063a420596711610227578063ae1aaf80116101db578063b710c15d116101c0578063b710c15d14610d43578063ba08d23714610d70578063bf348f8614610d9057600080fd5b8063ae1aaf8014610d0d578063b61ed63a14610d2357600080fd5b8063a697ecff1161020c578063a697ecff14610ca0578063a711e6a114610cd8578063adddc0cf14610cf857600080fd5b8063a420596714610c53578063a5d54f6514610c8b57600080fd5b80639a7b5f111161027e5780639e6c2959116102635780639e6c295914610bfd5780639e72c63514610c135780639ea8082b14610c3357600080fd5b80639a7b5f1114610bb85780639b03d74414610be757600080fd5b8063921e274b116102af578063921e274b14610b62578063950a651314610b75578063957950a714610b9557600080fd5b8063862be28714610b055780638da5cb5b14610b2557600080fd5b80634f9a8d8f11610426578063715018a6116103835780637b0a0f9b116103375780637d8149db1161031c5780637d8149db14610a985780638247a23914610ab857806384725c7614610ad857600080fd5b80637b0a0f9b14610a585780637b15b94c14610a7857600080fd5b806373c218031161036857806373c21803146109d2578063750dd2a1146109f2578063794c0c6814610a4257600080fd5b8063715018a614610987578063728345db1461099c57600080fd5b80635fef7643116103da578063673a2a1f116103bf578063673a2a1f1461092f5780636bda1577146109515780637069e7461461097157600080fd5b80635fef7643146108e3578063615f2b71146108f957600080fd5b8063567e98f91161040b578063567e98f9146108975780635b4eafe0146108ad5780635d80ca32146108cd57600080fd5b80634f9a8d8f146108545780635267e1d61461086a57600080fd5b806326476204116104d45780633b7d0946116104885780634160d3861161046d5780634160d386146107e75780634346845f146108075780634e9b426d1461082757600080fd5b80633b7d0946146107b45780633f3afe01146107d457600080fd5b80633219d600116104b95780633219d600146107495780633715426314610789578063379b046a1461079e57600080fd5b806326476204146107165780632bafde8d1461072957600080fd5b80631555371c1161052b57806320c07cd81161051057806320c07cd8146106cb57806322e3d986146106e1578063251441a9146106f657600080fd5b80631555371c1461063a5780631fb31e431461064f57600080fd5b8063028b8bdb1461057f5780630ac6e291146105a85780630b770cdf146105ca5780631345b8a51461060257600080fd5b3661057a57604051631574f9f360e01b815260040160405180910390fd5b600080fd5b34801561058b57600080fd5b5061059560145481565b6040519081526020015b60405180910390f35b3480156105b457600080fd5b506105c86105c336600461534f565b611010565b005b3480156105d657600080fd5b506024546105ea906001600160a01b031681565b6040516001600160a01b03909116815260200161059f565b34801561060e57600080fd5b5061059561061d3660046153ff565b602160209081526000928352604080842090915290825290205481565b34801561064657600080fd5b506105c86115a7565b34801561065b57600080fd5b5061069961066a36600461542f565b6001600160a01b03166000908152601e6020526040902060010154608081901b91600160801b90910460f01b90565b604080516fffffffffffffffffffffffffffffffff1990931683526001600160f01b031990911660208301520161059f565b3480156106d757600080fd5b506105956107d081565b3480156106ed57600080fd5b50610595611619565b34801561070257600080fd5b506105c861071136600461544c565b611660565b6105c861072436600461542f565b61171e565b34801561073557600080fd5b506105c861074436600461548d565b6117a1565b34801561075557600080fd5b5061077961076436600461542f565b601f6020526000908152604090205460ff1681565b604051901515815260200161059f565b34801561079557600080fd5b506105c8611822565b3480156107aa57600080fd5b50610595601a5481565b3480156107c057600080fd5b506105c86107cf36600461542f565b611c1d565b6105c86107e23660046154a6565b611c53565b3480156107f357600080fd5b506105c86108023660046154a6565b611f89565b34801561081357600080fd5b506105c86108223660046154ef565b612028565b34801561083357600080fd5b5061084761084236600461542f565b61212e565b60405161059f91906155a0565b34801561086057600080fd5b5061059560165481565b34801561087657600080fd5b5061059561088536600461542f565b601b6020526000908152604090205481565b3480156108a357600080fd5b50610595601c5481565b3480156108b957600080fd5b506105956108c83660046153ff565b6121da565b3480156108d957600080fd5b50610595600e5481565b3480156108ef57600080fd5b50610595600c5481565b34801561090557600080fd5b506105ea61091436600461542f565b6025602052600090815260409020546001600160a01b031681565b34801561093b57600080fd5b50610944612204565b60405161059f91906155b3565b34801561095d57600080fd5b5061059561096c366004615600565b612215565b34801561097d57600080fd5b5061059560195481565b34801561099357600080fd5b506105c8612395565b3480156109a857600080fd5b506105956109b73660046153ff565b60208080526000928352604080842090915290825290205481565b3480156109de57600080fd5b506109446109ed36600461542f565b6123a9565b3480156109fe57600080fd5b50610595610a0d366004615600565b6001600160a01b039182166000908152600b602090815260408083209390941682529182528281206015548252909152205490565b348015610a4e57600080fd5b5061059560155481565b348015610a6457600080fd5b506105c8610a73366004615667565b6123cd565b348015610a8457600080fd5b506105c8610a9336600461542f565b61244a565b348015610aa457600080fd5b506105c8610ab33660046156ac565b6124b1565b348015610ac457600080fd5b506105c8610ad336600461548d565b612533565b348015610ae457600080fd5b50610595610af336600461542f565b60266020526000908152604090205481565b348015610b1157600080fd5b506105c8610b20366004615709565b612566565b348015610b3157600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03166105ea565b6105c8610b7036600461576e565b6125c9565b348015610b8157600080fd5b50610595610b90366004615600565b612712565b348015610ba157600080fd5b50610baa61285a565b60405161059f92919061582c565b348015610bc457600080fd5b50610bd8610bd336600461542f565b6128bd565b60405161059f9392919061584e565b348015610bf357600080fd5b5061059560185481565b348015610c0957600080fd5b5061059561271081565b348015610c1f57600080fd5b506105c8610c2e36600461548d565b612971565b348015610c3f57600080fd5b50610944610c4e36600461542f565b6129bc565b348015610c5f57600080fd5b50610595610c6e366004615600565b601160209081526000928352604080842090915290825290205481565b348015610c9757600080fd5b506109446129e0565b348015610cac57600080fd5b50610595610cbb366004615600565b601360209081526000928352604080842090915290825290205481565b348015610ce457600080fd5b50610779610cf336600461542f565b612a42565b348015610d0457600080fd5b506105c8612a4e565b348015610d1957600080fd5b5061059560175481565b348015610d2f57600080fd5b506105c8610d3e3660046154a6565b612a93565b348015610d4f57600080fd5b50610d63610d5e3660046158ab565b612dfa565b60405161059f919061595c565b348015610d7c57600080fd5b50610779610d8b36600461598a565b612eaa565b348015610d9c57600080fd5b50610d63610dab3660046156ac565b613085565b348015610dbc57600080fd5b5061059561312a565b348015610dd157600080fd5b506105c8610de03660046154a6565b613149565b348015610df157600080fd5b506105c8610e0036600461542f565b6131f3565b348015610e1157600080fd5b506105c8610e203660046153ff565b6133c6565b348015610e3157600080fd5b50610944613505565b348015610e4657600080fd5b506105c8610384601755565b348015610e5e57600080fd5b50610595600d5481565b348015610e7457600080fd5b50610595610e8336600461542f565b60106020526000908152604090205481565b348015610ea157600080fd5b50610944613511565b348015610eb657600080fd5b50601d546105ea906001600160a01b031681565b348015610ed657600080fd5b50610595610ee5366004615600565b600f60209081526000928352604080842090915290825290205481565b348015610f0e57600080fd5b506105c861351d565b348015610f2357600080fd5b506105c861365d565b348015610f3857600080fd5b50610595610bb881565b348015610f4e57600080fd5b506105c8610f5d36600461542f565b6136a3565b348015610f6e57600080fd5b506105c8610f7d3660046154a6565b6136de565b348015610f8e57600080fd5b506001610779565b348015610fa257600080fd5b50610779610fb136600461542f565b613797565b348015610fc257600080fd5b50610595610fd136600461542f565b60276020526000908152604090205481565b348015610fef57600080fd5b50610595610ffe36600461542f565b60126020526000908152604090205481565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff1660008115801561105b5750825b905060008267ffffffffffffffff1660011480156110785750303b155b905081158015611086575080155b156110a45760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156110d857845468ff00000000000000001916680100000000000000001785555b6001600160a01b038b166110ff5760405163d92e233d60e01b815260040160405180910390fd5b6111088a6137b4565b8761111660408c018c6159a6565b61112291506002615a06565b1461113f5760405162d6988760e81b815260040160405180910390fd5b8561114d60408c018c6159a6565b90501461116d576040516320041afd60e01b815260040160405180910390fd5b6111768b613917565b61117e613928565b61118b60208b018b61542f565b601d80546001600160a01b0319166001600160a01b03929092169190911790556111bb60408b0160208c0161542f565b602480546001600160a01b0319166001600160a01b03929092169190911790553660006111eb60408d018d6159a6565b9150915060005b8181101561140e57600083838381811061120e5761120e615a1d565b9050602002016020810190611223919061542f565b6001600160a01b03160361124a5760405163d92e233d60e01b815260040160405180910390fd5b61127b83838381811061125f5761125f615a1d565b9050602002016020810190611274919061542f565b6000613938565b6112aa83838381811061129057611290615a1d565b90506020020160208101906112a5919061542f565b613998565b8b8b6112b7836002615a06565b8181106112c6576112c6615a1d565b905060200201358c8c8360026112dc9190615a06565b6112e7906001615a33565b8181106112f6576112f6615a1d565b90506020020135604051602001611317929190918252602082015260400190565b604051602081830303815290604052601e600085858581811061133c5761133c615a1d565b9050602002016020810190611351919061542f565b6001600160a01b031681526020810191909152604001600020906113759082615ad0565b5089898281811061138857611388615a1d565b905060200201602081019061139d9190615b90565b601e60008585858181106113b3576113b3615a1d565b90506020020160208101906113c8919061542f565b6001600160a01b031681526020810191909152604001600020600190810180546fffffffffffffffffffffffffffffffff191660809390931c92909217909155016111f2565b5060408051600580825260c082019092526000916020820160a0803683370190505090506802b5e3af16b18800008160008151811061144f5761144f615a1d565b60200260200101818152505068056bc75e2d631000008160018151811061147857611478615a1d565b602002602001018181525050680821ab0d4414980000816002815181106114a1576114a1615a1d565b602002602001018181525050680ad78ebc5ac6200000816003815181106114ca576114ca615a1d565b602002602001018181525050680d8d726b7177a80000816004815181106114f3576114f3615a1d565b6020908102919091010152611517632bafde8d60e01b636d3d4db560e11b836139ad565b50505060608a0135600d5560808a0135600c5560a08a0135600e5560c08a01356016556101008a01356014554260185560e08a0135601755831561159a57845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050505050565b601d546001600160a01b031633146115d1576040516282b42960e81b815260040160405180910390fd5b60006115dd6004613a62565b905060005b81518110156116155761160d82828151811061160057611600615a1d565b6020026020010151613a76565b6001016115e2565b5050565b601854601654600091901561162f576001611632565b60005b60ff16601a54601654836116469190615a33565b6116509190615a33565b61165a9190615bab565b91505090565b3a60000361168157604051630e661aed60e41b815260040160405180910390fd5b816001600160a01b0316836001600160a01b0316036116b357604051630a5eddd560e01b815260040160405180910390fd5b336116bf848284613abc565b6116ca838284613d6a565b601554604080516001600160a01b0387811682526020820186905280851692908716917f4480d8e4b1e9095b94bf513961d26fe1d32386ebdd103d18fe8738cf4b2223ff910160405180910390a450505050565b3a60000361173f57604051630e661aed60e41b815260040160405180910390fd5b333461174c838383613d6a565b601554826001600160a01b0316846001600160a01b03167f2273de02cb1f69ba6259d22c4bc22c60e4c94c193265ef6afee324a04a9b6d228460405161179491815260200190565b60405180910390a4505050565b6117a96140bb565b806117c06000356001600160e01b03191682612eaa565b6117e5576040516373330d9b60e01b8152600481018290526024015b60405180910390fd5b600d8290556040518281527ffee02ce7aa40f9c49eaabd26d404fa88714b97cb209af8954cfd5eeb8213b93e906020015b60405180910390a15050565b3a60000361184357604051630e661aed60e41b815260040160405180910390fd5b6000806118506002613a62565b9050805160000361187457604051631c369b4560e21b815260040160405180910390fd5b60005b8151811015611a5c57600082828151811061189457611894615a1d565b602002602001015190506118a781614116565b8061191d5750601d54604051639d6fc1d160e01b81526001600160a01b03838116600483015290911690639d6fc1d190602401602060405180830381865afa1580156118f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191b9190615bbe565b155b156119285750611a54565b611933600282614154565b506001600160a01b0381166000908152601f60209081526040808320805460ff19166001179055601b9091528120805490829055601c80549192839261197a908490615bab565b909155506000905061198b836129bc565b905060005b81518110156119f65760008282815181106119ad576119ad615a1d565b6020908102919091018101516001600160a01b03808816600090815260138452604080822092841682529190935282209190915590506119ed8582614169565b50600101611990565b50611a018287615a33565b9550826001600160a01b0316336001600160a01b03167f8e6a4ccd7dccdca9ac211d00fcc3fa7c71be75ff73d3a35f63ea023173cc100484604051611a4891815260200190565b60405180910390a35050505b600101611877565b5081600003611a7e57604051631c369b4560e21b815260040160405180910390fd5b6000611a8b600284615be0565b90506000611a998285615bab565b90506000601d60009054906101000a90046001600160a01b03166001600160a01b03166356b54bae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b149190615c02565b90506000816001600160a01b031663732524946040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b7a9190615c02565b9050816001600160a01b031663af182535846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611bb757600080fd5b505af1158015611bcb573d6000803e3d6000fd5b5050505050611bda81856141cb565b604080518481526020810186905233917f1c113e6bae9530fea40323e612aeb0cb7817dedb5a0b0f6bdfbff97d55920dc7910160405180910390a2505050505050565b601d546001600160a01b03163314611c47576040516282b42960e81b815260040160405180910390fd5b611c5081613a76565b50565b601d60009054906101000a90046001600160a01b03166001600160a01b03166356b54bae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ca6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cca9190615c02565b6001600160a01b0316336001600160a01b031614611cfa576040516282b42960e81b815260040160405180910390fd5b3415611615576015546000908152602080805260408083206001600160a01b03861684529091528120543491611d31858486614272565b90506000611d3e866129bc565b905060005b8151811015611e8d57600084611d756015548a868681518110611d6857611d68615a1d565b6020026020010151614391565b8560400151611d849190615a06565b611d8e9190615be0565b905080601360008a6001600160a01b03166001600160a01b031681526020019081526020016000206000858581518110611dca57611dca615a1d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254611e019190615a33565b90915550506001600160a01b0388166000908152600b602052604081208451839290869086908110611e3557611e35615a1d565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600060155481526020019081526020016000206000828254611e7f9190615a33565b909155505050600101611d43565b50602082015115611ea657611ea6868360200151614432565b81516001600160a01b038716600090815260136020908152604080832090915281208054909190611ed8908490615a33565b90915550506001600160a01b0386166000908152601b602052604081208054869290611f05908490615a33565b9250508190555083601c6000828254611f1e9190615a33565b90915550611f2d9050866144f9565b60155482516001600160a01b038816907f72093068b9f28053bd924ac15d7710b987f9b6ef1e0f89f47d8b4bd7cac776dc90611f698189615bab565b6040805192835260208301919091520160405180910390a3505050505050565b601d546040516253517560e01b81523360048201526000916001600160a01b0316906253517590602401602060405180830381865afa158015611fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ff49190615c02565b6001600160a01b03160361201d57604051632670461960e11b81523360048201526024016117dc565b6116153383836145e5565b6120306140bb565b600061203a61471d565b90506040518060400160405280857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200184848080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509390945250506001600160e01b031988168152602084815260409091208351815463ffffffff191660e09190911c1781558382015180519193506120e6926001850192910190615274565b509050507f3665bf9cd0ba4ddceeec259e21dcf8a4510f3b1130bd42e950828e69d85408ba8585858560405161211f9493929190615c1f565b60405180910390a15050505050565b6001600160a01b0381166000908152601e6020526040902080546060919061215590615a46565b80601f016020809104026020016040519081016040528092919081815260200182805461218190615a46565b80156121ce5780601f106121a3576101008083540402835291602001916121ce565b820191906000526020600020905b8154815290600101906020018083116121b157829003601f168201915b50505050509050919050565b60008281526021602090815260408083206001600160a01b03851684529091529020545b92915050565b60606122106000613a62565b905090565b601d546040516253517560e01b81526001600160a01b03848116600483015260009283929116906253517590602401602060405180830381865afa158015612261573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122859190615c02565b90506001600160a01b0384166000908152601f602052604090205460ff16156122b25760009150506121fe565b6001600160a01b03848116600090815260136020908152604080832087851684529091529081902054601d54915163a0d16cad60e01b815284841660048201529092919091169063a0d16cad90602401602060405180830381865afa15801561231f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123439190615bbe565b6123505791506121fe9050565b6001600160a01b038581166000908152600b6020908152604080832093881683529281528282206015548352905220548082111561238c578091505b50949350505050565b61239d6140bb565b6123a7600061477f565b565b6001600160a01b0381166000908152600a602052604090206060906121fe90613a62565b601d546001600160a01b031633146123f7576040516282b42960e81b815260040160405180910390fd5b6001600160a01b039092166000908152601e60205260409020600101805460f09390931c600160801b0271ffffffffffffffffffffffffffffffffffff1990931660809290921c91909117919091179055565b601d546001600160a01b03163314612474576040516282b42960e81b815260040160405180910390fd5b600c546001600160a01b038216600090815260136020908152604080832090915290205410611c50576124a8816001613938565b611c50816144f9565b6124b96140bb565b60006124c361471d565b6001600160e01b031983166000908152602082905260408120805463ffffffff191681559192506124f760018301826152bf565b50506040516001600160e01b0319831681527fed27cb02231782dadf13473a7828cb980c4d685791b7a3136dde00f8c3594cb690602001611816565b601d546001600160a01b0316331461255d576040516282b42960e81b815260040160405180910390fd5b60185543601955565b336000908152601e60205260409020612580848683615c8c565b50336000908152601e60205260409020600101805460f09290921c600160801b0271ffffffffffffffffffffffffffffffffffff1990921660809390931c929092171790555050565b3a6000036125ea57604051630e661aed60e41b815260040160405180910390fd5b601d54604051630526083960e11b81526001600160a01b0388811660048301523360248301819052923492911690630a4c107290604401600060405180830381600087803b15801561263b57600080fd5b505af115801561264f573d6000803e3d6000fd5b505050506001600160a01b0382166000908152601e60205260409020612676858783615c8c565b506001600160a01b0382166000908152601e6020526040902060010180546fffffffffffffffffffffffffffffffff1916608085901c1790556126ba8288886145e5565b6126c5828383613d6a565b6015546040518281526001600160a01b0384169081907f2273de02cb1f69ba6259d22c4bc22c60e4c94c193265ef6afee324a04a9b6d229060200160405180910390a45050505050505050565b601d546040516253517560e01b81526001600160a01b03848116600483015260009283929116906253517590602401602060405180830381865afa15801561275e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127829190615c02565b9050601d5460405163a0d16cad60e01b81526001600160a01b0383811660048301529091169063a0d16cad90602401602060405180830381865afa1580156127ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127f29190615bbe565b6128005760009150506121fe565b6001600160a01b038481166000818152600b6020908152604080832094881680845294825280832060155484528252808320549383526013825280832094835293905291909120546128529190615bab565b949350505050565b606060006007600854818054806020026020016040519081016040528092919081815260200182805480156128ae57602002820191906000526020600020905b81548152602001906001019080831161289a575b50505050509150915091509091565b601e602052600090815260409020805481906128d890615a46565b80601f016020809104026020016040519081016040528092919081815260200182805461290490615a46565b80156129515780601f1061292657610100808354040283529160200191612951565b820191906000526020600020905b81548152906001019060200180831161293457829003601f168201915b50505060019093015491925050608081901b90600160801b900460f01b83565b601d546001600160a01b0316331461299b576040516282b42960e81b815260040160405180910390fd5b60175481601a546129ac9190615a33565b6129b69190615a33565b601a5550565b6001600160a01b03811660009081526009602052604090206060906121fe90613a62565b60606006805480602002602001604051908101604052809291908181526020018280548015612a3857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a1a575b5050505050905090565b60006121fe81836147f0565b601d546001600160a01b03163314612a78576040516282b42960e81b815260040160405180910390fd5b601754601a6000828254612a8c9190615a33565b9091555050565b3a600003612ab457604051630e661aed60e41b815260040160405180910390fd5b6001600160a01b038216612adb5760405163d92e233d60e01b815260040160405180910390fd5b80600003612afc57604051633ca0029d60e01b815260040160405180910390fd5b6001600160a01b0382166000818152600f602090815260408083203380855290835281842054858552601084528285205460138552838620838752855283862054968652601b9094529184205490949193861315612c0657856000612b618988612712565b905080821115612b8e57604051632de4882160e01b815260048101829052602481018390526044016117dc565b612b988287615a33565b9550612ba48286615a33565b9450612bb08285615bab565b9350612bbc8284615bab565b925081601c6000828254612bd09190615bab565b90915550506015546001600160a01b03808b166000908152601160209081526040808320938c168352929052205550612c5c9050565b6000612c1187615d4d565b9050612c1d8186615bab565b9450612c298185615bab565b9350612c358184615a33565b9250612c418183615a33565b915080601c6000828254612c559190615a33565b9091555050505b6001600160a01b038088166000818152600f60209081526040808320948a1680845294825280832089905583835260108252808320889055601382528083208584528252808320879055838352601b90915290208390559003612d2b578115801590612cc95750600c5482105b15612d0157604051636fe84f3d60e01b81526001600160a01b03808916600483015286166024820152604481018790526064016117dc565b6000861315612d205781600003612d1b57612d1b87613998565b612d98565b612d1b876001613938565b8115801590612d3b5750600d5482105b15612d7357604051636fe84f3d60e01b81526001600160a01b03808916600483015286166024820152604481018790526064016117dc565b6000861315612d8e5781600003612d1b57612d1b8786614169565b612d988786614812565b612da1876144f9565b601554856001600160a01b0316886001600160a01b03167f80d5c777e5f7ac6ee89723223803ca5c0ec0204f89e99c1b0cde973c66a6459489604051612de991815260200190565b60405180910390a450505050505050565b604080518082019091526000815260606020820152612e1761471d565b82516020808501919091206001600160e01b0319908116600090815292825260409283902083518085018552815460e01b9092168252600181018054855181860281018601909652808652929491938581019390830182828015612e9a57602002820191906000526020600020905b815481526020019060010190808311612e86575b5050505050815250509050919050565b600080612eb561471d565b6001600160e01b031980861660009081526020838152604080832081518083018352815460e01b90951685526001810180548351818602810186019094528084529697509395909385840193909190830182828015612f3357602002820191906000526020600020905b815481526020019060010190808311612f1f575b5050505050815250509050806020015151600003612f56576000925050506121fe565b60208101518151600090612f699061483f565b905060005b82518110156130775781838281518110612f8a57612f8a615a1d565b60200260200101510361306f576000808211612fc05783600081518110612fb357612fb3615a1d565b6020026020010151612fe5565b83612fcc600184615bab565b81518110612fdc57612fdc615a1d565b60200260200101515b9050600060018551612ff79190615bab565b831061302957846001865161300c9190615bab565b8151811061301c5761301c615a1d565b602002602001015161304e565b84613035846001615a33565b8151811061304557613045615a1d565b60200260200101515b90508189141580156130605750808914155b159750505050505050506121fe565b600101612f6e565b506000979650505050505050565b6040805180820190915260008152606060208201526130a261471d565b6001600160e01b03198084166000908152602092835260409081902081518083018352815460e01b9093168352600181018054835181870281018701909452808452939491938583019392830182828015612e9a5760200282019190600052602060002090815481526020019060010190808311612e86575050505050815250509050919050565b600060175460165460185461313f9190615a33565b6122109190615bab565b6024546001600160a01b03163314613173576040516282b42960e81b815260040160405180910390fd5b601d546040516307b9342f60e21b81526001600160a01b0384811660048301526000921690631ee4d0bc90602401602060405180830381865afa1580156131be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e29190615c02565b90506131ee8183614916565b505050565b3a60000361321457604051630e661aed60e41b815260040160405180910390fd5b61321c6149c0565b6001600160a01b0381166000908152601160209081526040808320338085529252909120546015541161327557604051630b06352b60e31b81526001600160a01b038084166004830152821660248201526044016117dc565b6001600160a01b038083166000908152600f60209081526040808320938516835292905290812054908190036132be57604051633ca0029d60e01b815260040160405180910390fd5b6001600160a01b038084166000818152600f602090815260408083209487168352938152838220829055918152601090915220546132fd908290615bab565b6001600160a01b0380851660009081526010602090815260408083209490945560138152838220928616825291909152908120549003613341576133418383614a0a565b61334b82826141cb565b601554826001600160a01b0316846001600160a01b03167ff380b0bc887e00f5b50d3c9d4eaaf5c9a0afd97b956316b995159384c4ede9b38460405161339391815260200190565b60405180910390a45050611c5060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b601d60009054906101000a90046001600160a01b03166001600160a01b03166356b54bae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613419573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343d9190615c02565b6001600160a01b0316336001600160a01b03161461346d576040516282b42960e81b815260040160405180910390fd5b6000828152602080805260408083206001600160a01b03851684529091528120549003611615576001600160a01b0381166000908152601b6020526040812054908190036134ba57505050565b6000838152602080805260408083206001600160a01b038616808552908352818420949094556013825280832082528083205486845260218352818420948452939091529020555050565b60606122106004613a62565b60606122106002613a62565b3a60000361353e57604051630e661aed60e41b815260040160405180910390fd5b601d546040516253517560e01b81523360048201819052916000916001600160a01b03909116906253517590602401602060405180830381865afa15801561358a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ae9190615c02565b9050601554600014801561362b5750601d5460405163facd743b60e01b81526001600160a01b0383811660048301529091169063facd743b90602401602060405180830381865afa158015613607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061362b9190615bbe565b15613654576040516303d71f2d60e51b81526001600160a01b03831660048201526024016117dc565b61161582613a76565b601d546001600160a01b03163314613687576040516282b42960e81b815260040160405180910390fd5b6015805490600061369783615d69565b90915550506000601a55565b6136ab6140bb565b6001600160a01b0381166136d557604051631e4fbdf760e01b8152600060048201526024016117dc565b611c508161477f565b3a6000036136ff57604051630e661aed60e41b815260040160405180910390fd5b6137076149c0565b33613713838284613abc565b61371d81836141cb565b601554816001600160a01b0316846001600160a01b03167fa7c0f0cac6bd4d18042007706c84a8abe823751cf289b69c01e83eef7b5915c78560405161376591815260200190565b60405180910390a45061161560017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b60006137a381836147f0565b806121fe57506121fe6002836147f0565b60c081013515806137ce57508061010001358160c0013511155b156137ec5760405163c671116b60e01b815260040160405180910390fd5b806101000135600003613812576040516332154b4760e01b815260040160405180910390fd5b60e0810135158061382b57508060c001358160e0013510155b1561384957604051630685efe960e01b815260040160405180910390fd5b6000613858602083018361542f565b6001600160a01b03160361387f5760405163d92e233d60e01b815260040160405180910390fd5b61388c60408201826159a6565b90506000036138ae57604051635c9a24ed60e11b815260040160405180910390fd5b606081013515806138c157506080810135155b156138ef5760405163633373e160e11b815260808201356004820152606082013560248201526044016117dc565b80608001358160a0013511611c5057604051631c6d3b1560e01b815260040160405180910390fd5b61391f614b60565b611c5081614bae565b613930614b60565b6123a7614bb6565b61394182612a42565b61397d57613950600083614bbe565b50610bb861395e6000614bd3565b111561397d5760405163398dcd9d60e21b815260040160405180910390fd5b613988600283614154565b5080156116155761161582614bdd565b6139a3600482614bbe565b50611c5081614cd2565b6139b5614b60565b60006139bf61471d565b6040805180820182526001600160e01b0319868116825260208083018781529189166000908152858252939093208251815463ffffffff191660e09190911c1781559051805194955091939092613a1d926001850192910190615274565b509050507f3665bf9cd0ba4ddceeec259e21dcf8a4510f3b1130bd42e950828e69d85408ba848484604051613a5493929190615d82565b60405180910390a150505050565b60606000613a6f83614eef565b9392505050565b613a81600082614154565b50613a8b81614116565b15613aa157613a9b600282614154565b50613aaa565b613aaa81614f4a565b613ab381614cd2565b611c5081614f55565b6001600160a01b038316613ae35760405163d92e233d60e01b815260040160405180910390fd5b80600003613b0457604051633ca0029d60e01b815260040160405180910390fd5b6000613b108484612215565b905080821115613b3d57604051632de4882160e01b815260048101829052602481018390526044016117dc565b6001600160a01b038085166000908152601360209081526040808320938716835292905290812054613b70908490615bab565b90506000846001600160a01b0316866001600160a01b031614613b9557600d54613b99565b600c545b90508115801590613ba957508082105b15613be157604051639e612d5760e01b81526001600160a01b03808816600483015286166024820152604481018590526064016117dc565b856001600160a01b0316856001600160a01b031614613c7657601d546040516253517560e01b81526001600160a01b03888116600483015260009216906253517590602401602060405180830381865afa158015613c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c679190615c02565b9050613c74878288614f60565b505b6001600160a01b038681166000818152601360209081526040808320948a16808452948252808320879055928252600b8152828220938252928352818120601554825290925290205484811015613cce576000613cd8565b613cd88582615bab565b6001600160a01b038089166000818152600b60209081526040808320948c1683529381528382206015548352815283822094909455908152601b90925281208054879290613d27908490615bab565b9250508190555084601c6000828254613d409190615bab565b90915550506000839003613d5857613d588787614a0a565b613d61876144f9565b50505050505050565b6001600160a01b038316613d915760405163d92e233d60e01b815260040160405180910390fd5b601d546040516253517560e01b81526001600160a01b03858116600483015260009216906253517590602401602060405180830381865afa158015613dda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dfe9190615c02565b90506001600160a01b038116613e3257604051632670461960e11b81526001600160a01b03851660048201526024016117dc565b81600003613e665760405163e59f5c3960e01b81526001600160a01b038086166004830152841660248201526044016117dc565b6001600160a01b0384166000908152601f602052604090205460ff1615613eab5760405163078137eb60e41b81526001600160a01b03851660048201526024016117dc565b6001600160a01b038085166000818152601360209081526040808320948816808452949091528120549290911491613ee4908590615a33565b905060008215613ef75750600c54613f46565b50600d546001600160a01b03871660009081526013602090815260408083209091528120549003613f465760405163cbbeb0bd60e01b81526001600160a01b03881660048201526024016117dc565b80821015613f7a5760405163e59f5c3960e01b81526001600160a01b038089166004830152871660248201526044016117dc565b600e546001600160a01b0388166000908152601b6020526040902054613fa1908790615a33565b1115613fd357604051632c2b174160e21b81526001600160a01b038089166004830152871660248201526044016117dc565b6001600160a01b038088166000908152600b60209081526040808320938a168352928152828220601554835290529081208054879290614014908490615a33565b90915550506001600160a01b0387166000908152601b602052604081208054879290614041908490615a33565b9250508190555084601c600082825461405a9190615a33565b9091555050821561407557614070876001613938565b61408a565b61407f8787614812565b61408a878588614f60565b6001600160a01b038088166000908152601360209081526040808320938a16835292905220829055613d61876144f9565b336140ed7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146123a75760405163118cdaa760e01b81523360048201526024016117dc565b6001600160a01b0381166000908152601b60205260408120541580156121fe5750506001600160a01b03166000908152601060205260409020541590565b6000613a6f836001600160a01b03841661507c565b6001600160a01b038216600090815260096020526040902061418b9082614154565b506001600160a01b038083166000908152600f6020908152604080832093851683529290522054156141c157611615828261516f565b6116158282615191565b804710156141ec57604051631e9acf1760e31b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614239576040519150601f19603f3d011682016040523d82523d6000602084013e61423e565b606091505b50509050806131ee57604051630e21dcbb60e11b81526001600160a01b0384166004820152602481018390526044016117dc565b61429660405180606001604052806000815260200160008152602001600081525090565b6015546000818152602080805260408083206001600160a01b03891680855290835281842054948452602183528184209084529091528120549060646142dc8688615a06565b6142e69190615be0565b90506142f28187615bab565b6040808601919091526001600160a01b0380891660009081526026602090815283822054602590915292902054161580159061432d57508015155b1561434f5761271061433f8289615a06565b6143499190615be0565b60208601525b838386604001516143609190615a06565b61436a9190615be0565b60208601516143799084615bab565b6143839190615a33565b855250929695505050505050565b6000836000036143a357506000613a6f565b6001600160a01b0380841660009081526023602090815260408083209386168352929052205484900361440457506001600160a01b038083166000908152602260209081526040808320938516835292815282822086835290522054613a6f565b506001600160a01b038083166000908152601360209081526040808320938516835292905220549392505050565b6001600160a01b03808316600090815260256020908152604080832054600990925290912091169061446490826147f0565b614472576144728382614812565b6001600160a01b038084166000908152601360209081526040808320938516835292905290812080548492906144a9908490615a33565b90915550506001600160a01b038084166000908152600b6020908152604080832093851683529281528282206015548352905290812080548492906144ef908490615a33565b9091555050505050565b601d546040516253517560e01b81526001600160a01b03838116600483015260009216906253517590602401602060405180830381865afa158015614542573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145669190615c02565b60248054604051633941e77760e21b81526001600160a01b0380851660048301529394506000939091169163e5079ddc9101602060405180830381865afa1580156145b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145d99190615daf565b90506131ee8382614916565b6107d081111561460b5760405163e429b69160e01b8152600481018290526024016117dc565b6001600160a01b03821615801561462157508015155b156146515760405163073c315960e11b81526001600160a01b0383166004820152602481018290526044016117dc565b6001600160a01b038316600090815260276020526040902054801580159061467a575060155481145b1561469e5760155460405163e7cbc70160e01b81526004016117dc91815260200190565b6001600160a01b03848116600081815260256020908152604080832080546001600160a01b03191695891695861790556026825280832087905560155460278352928190209290925590518581527fd6ae57aa2cc060d4094c47d20c672afe0e53963e6459c15cab215abb8c88b863910160405180910390a350505050565b60008060ff1961474e60017fdace3fd3d1fbdfd33853f19ba191d28c617e373ec58fc73cf7b58db5aff2c2ab615bab565b60405160200161476091815260200190565b60408051601f1981840301815291905280516020909101201692915050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b6001600160a01b03811660009081526001830160205260408120541515613a6f565b6001600160a01b03821660009081526009602052604090206148349082614bbe565b506116158282615191565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03198516179052905160009190829081903090614896908590615dc8565b600060405180830381855afa9150503d80600081146148d1576040519150601f19603f3d011682016040523d82523d6000602084013e6148d6565b606091505b5091509150816148f957604051635fbab09b60e11b815260040160405180910390fd5b8080602001905181019061490d9190615daf565b95945050505050565b600080614922846151b3565b91509150816149315750505050565b60006007828154811061494657614946615a1d565b60009182526020808320909101546001600160a01b0388168352601b9091526040822054909250614978908690615a06565b9050806007848154811061498e5761498e615a1d565b906000526020600020018190555080826008546149ab9190615bab565b6149b59190615a33565b600855505050505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901614a0457604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b816001600160a01b0316816001600160a01b031603614b1757601d546040516253517560e01b81526001600160a01b03848116600483015260009216906253517590602401602060405180830381865afa158015614a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a909190615c02565b601d5460405163facd743b60e01b81526001600160a01b03808416600483015292935091169063facd743b90602401602060405180830381865afa158015614adc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b009190615bbe565b15614b0e576131ee83613998565b6131ee83613a76565b614b218282614169565b614b2a82614116565b15611615576131ee600283614154565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff166123a757604051631afcd79f60e31b815260040160405180910390fd5b6136ab614b60565b614b3a614b60565b6000613a6f836001600160a01b038416615225565b60006121fe825490565b6001600160a01b0381166000908152601260205260409020546006548082101580614c385750826001600160a01b031660068381548110614c2057614c20615a1d565b6000918252602090912001546001600160a01b031614155b15614cc9576001600160a01b03831660008181526012602052604081208390556006805460018181019092557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0180546001600160a01b03191690931790925560078054928301815581527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909101555b6131ee83614f55565b60075460065414614ce05750565b6001600160a01b03811660009081526012602052604090205460065481108015614d395750816001600160a01b031660068281548110614d2257614d22615a1d565b6000918252602090912001546001600160a01b0316145b156116155760078181548110614d5157614d51615a1d565b906000526020600020015460085410614d9e5760078181548110614d7757614d77615a1d565b906000526020600020015460086000828254614d939190615bab565b90915550614da49050565b60006008555b600654600090614db690600190615bab565b9050600060068281548110614dcd57614dcd615a1d565b600091825260209091200154600680546001600160a01b039092169250829185908110614dfc57614dfc615a1d565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060078281548110614e3d57614e3d615a1d565b906000526020600020015460078481548110614e5b57614e5b615a1d565b60009182526020808320909101929092556001600160a01b038084168252601290925260408082208690559186168152908120556006805480614ea057614ea0615de4565b600082815260209020810160001990810180546001600160a01b03191690550190556007805480614ed357614ed3615de4565b6001900381819060005260206000200160009055905550505050565b6060816000018054806020026020016040519081016040528092919081815260200182805480156121ce57602002820191906000526020600020905b815481526020019060010190808311614f2b5750505050509050919050565b611615600282614bbe565b611615600482614154565b601d5460405163a0d16cad60e01b81526001600160a01b0384811660048301529091169063a0d16cad90602401602060405180830381865afa158015614faa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614fce9190615bbe565b1580614fda5750601554155b15614fe457505050565b6001600160a01b03808416600090815260236020908152604080832093851683529290522054601554811015615076576001600160a01b0380851660008181526013602090815260408083209487168084529482528083205484845260228352818420868552835281842060158054865290845282852091909155549383526023825280832094835293905291909120555b50505050565b600081815260018301602052604081205480156151655760006150a0600183615bab565b85549091506000906150b490600190615bab565b90508082146151195760008660000182815481106150d4576150d4615a1d565b90600052602060002001549050808760000184815481106150f7576150f7615a1d565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061512a5761512a615de4565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506121fe565b60009150506121fe565b6001600160a01b0382166000908152600a602052604090206131ee9082614bbe565b6001600160a01b0382166000908152600a602052604090206131ee9082614154565b6001600160a01b0381166000908152601260205260408120546006548110801561520c5750826001600160a01b0316600682815481106151f5576151f5615a1d565b6000918252602090912001546001600160a01b0316145b1561521a5760019150915091565b506000928392509050565b600081815260018301602052604081205461526c575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556121fe565b5060006121fe565b8280548282559060005260206000209081019282156152af579160200282015b828111156152af578251825591602001919060010190615294565b506152bb9291506152d9565b5090565b5080546000825590600052602060002090810190611c5091905b5b808211156152bb57600081556001016152da565b6001600160a01b0381168114611c5057600080fd5b60008083601f84011261531557600080fd5b50813567ffffffffffffffff81111561532d57600080fd5b6020830191508360208260051b850101111561534857600080fd5b9250929050565b6000806000806000806080878903121561536857600080fd5b8635615373816152ee565b9550602087013567ffffffffffffffff8082111561539057600080fd5b90880190610120828b0312156153a557600080fd5b909550604088013590808211156153bb57600080fd5b6153c78a838b01615303565b909650945060608901359150808211156153e057600080fd5b506153ed89828a01615303565b979a9699509497509295939492505050565b6000806040838503121561541257600080fd5b823591506020830135615424816152ee565b809150509250929050565b60006020828403121561544157600080fd5b8135613a6f816152ee565b60008060006060848603121561546157600080fd5b833561546c816152ee565b9250602084013561547c816152ee565b929592945050506040919091013590565b60006020828403121561549f57600080fd5b5035919050565b600080604083850312156154b957600080fd5b82356154c4816152ee565b946020939093013593505050565b80356001600160e01b0319811681146154ea57600080fd5b919050565b6000806000806060858703121561550557600080fd5b61550e856154d2565b935061551c602086016154d2565b9250604085013567ffffffffffffffff81111561553857600080fd5b61554487828801615303565b95989497509550505050565b60005b8381101561556b578181015183820152602001615553565b50506000910152565b6000815180845261558c816020860160208601615550565b601f01601f19169290920160200192915050565b602081526000613a6f6020830184615574565b6020808252825182820181905260009190848201906040850190845b818110156155f45783516001600160a01b0316835292840192918401916001016155cf565b50909695505050505050565b6000806040838503121561561357600080fd5b823561561e816152ee565b91506020830135615424816152ee565b80356fffffffffffffffffffffffffffffffff19811681146154ea57600080fd5b80356001600160f01b0319811681146154ea57600080fd5b60008060006060848603121561567c57600080fd5b8335615687816152ee565b92506156956020850161562e565b91506156a36040850161564f565b90509250925092565b6000602082840312156156be57600080fd5b613a6f826154d2565b60008083601f8401126156d957600080fd5b50813567ffffffffffffffff8111156156f157600080fd5b60208301915083602082850101111561534857600080fd5b6000806000806060858703121561571f57600080fd5b843567ffffffffffffffff81111561573657600080fd5b615742878288016156c7565b909550935061575590506020860161562e565b91506157636040860161564f565b905092959194509250565b60008060008060008060a0878903121561578757600080fd5b8635615792816152ee565b955060208701356157a2816152ee565b945060408701359350606087013567ffffffffffffffff8111156157c557600080fd5b6157d189828a016156c7565b90945092506157e490506080880161562e565b90509295509295509295565b60008151808452602080850194506020840160005b8381101561582157815187529582019590820190600101615805565b509495945050505050565b60408152600061583f60408301856157f0565b90508260208301529392505050565b6060815260006158616060830186615574565b6fffffffffffffffffffffffffffffffff19949094166020830152506001600160f01b031991909116604090910152919050565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156158bd57600080fd5b813567ffffffffffffffff808211156158d557600080fd5b818401915084601f8301126158e957600080fd5b8135818111156158fb576158fb615895565b604051601f8201601f19908116603f0116810190838211818310171561592357615923615895565b8160405282815287602084870101111561593c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b602080825282516001600160e01b0319168282015282015160408083015260009061285260608401826157f0565b6000806040838503121561599d57600080fd5b6154c4836154d2565b6000808335601e198436030181126159bd57600080fd5b83018035915067ffffffffffffffff8211156159d857600080fd5b6020019150600581901b360382131561534857600080fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176121fe576121fe6159f0565b634e487b7160e01b600052603260045260246000fd5b808201808211156121fe576121fe6159f0565b600181811c90821680615a5a57607f821691505b602082108103615a7a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156131ee576000816000526020600020601f850160051c81016020861015615aa95750805b601f850160051c820191505b81811015615ac857828155600101615ab5565b505050505050565b815167ffffffffffffffff811115615aea57615aea615895565b615afe81615af88454615a46565b84615a80565b602080601f831160018114615b335760008415615b1b5750858301515b600019600386901b1c1916600185901b178555615ac8565b600085815260208120601f198616915b82811015615b6257888601518255948401946001909101908401615b43565b5085821015615b805787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215615ba257600080fd5b613a6f8261562e565b818103818111156121fe576121fe6159f0565b600060208284031215615bd057600080fd5b81518015158114613a6f57600080fd5b600082615bfd57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615c1457600080fd5b8151613a6f816152ee565b6001600160e01b0319858116825284166020820152606060408201819052810182905260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115615c7157600080fd5b8260051b808560808501379190910160800195945050505050565b67ffffffffffffffff831115615ca457615ca4615895565b615cb883615cb28354615a46565b83615a80565b6000601f841160018114615cec5760008515615cd45750838201355b600019600387901b1c1916600186901b178355615d46565b600083815260209020601f19861690835b82811015615d1d5786850135825560209485019460019092019101615cfd565b5086821015615d3a5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6000600160ff1b8201615d6257615d626159f0565b5060000390565b600060018201615d7b57615d7b6159f0565b5060010190565b6001600160e01b031984811682528316602082015260606040820181905260009061490d908301846157f0565b600060208284031215615dc157600080fd5b5051919050565b60008251615dda818460208701615550565b9190910192915050565b634e487b7160e01b600052603160045260246000fdfea26469706673582212201e8e54a31c16c621fa88c77c6ff088a6e5e931cf9c5ea285dbbc5f542d912b4564736f6c63430008190033