Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- StakingHbbft
- Optimization enabled
- true
- Compiler version
- v0.8.25+commit.b61c2a91
- Optimization runs
- 800
- Verified at
- 2024-12-09 15:40:08.050527Z
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; }}// slither-disable-end unused-return
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);}
@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/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":"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"}]
Deployed ByteCode
0x6080604052348015600f57600080fd5b506016601a565b60ca565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560695760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c75780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b615dfd806100d96000396000f3fe6080604052600436106105415760003560e01c8063862be287116102af578063bf348f8611610179578063e9ab0300116100d6578063f3fef3a31161008a578063f6c578611161006f578063f6c5786114610f63578063f9d4d54414610f83578063fa4aaf4714610fb057600080fd5b8063f3fef3a314610f2f578063f494250114610f4f57600080fd5b8063ee435f55116100bb578063ee435f5514610ee4578063f078609614610ef9578063f2fde38b14610f0f57600080fd5b8063e9ab030014610e97578063edd7db7514610ecf57600080fd5b8063d290c21d1161012d578063dadee88a11610112578063dadee88a14610e35578063df6f55f514610e62578063dfc8bf4e14610e7757600080fd5b8063d290c21d14610e0a578063da7a9b6a14610e1f57600080fd5b8063c6af311a1161015e578063c6af311a14610daa578063cfef144114610dca578063d0ac76f614610dea57600080fd5b8063bf348f8614610d75578063c6912cc014610d9557600080fd5b80639ea8082b11610227578063adddc0cf116101db578063b61ed63a116101c0578063b61ed63a14610d08578063b710c15d14610d28578063ba08d23714610d5557600080fd5b8063adddc0cf14610cdd578063ae1aaf8014610cf257600080fd5b8063a5d54f651161020c578063a5d54f6514610c70578063a697ecff14610c85578063a711e6a114610cbd57600080fd5b80639ea8082b14610c18578063a420596714610c3857600080fd5b8063957950a71161027e5780639b03d744116102635780639b03d74414610bcc5780639e6c295914610be25780639e72c63514610bf857600080fd5b8063957950a714610b7a5780639a7b5f1114610b9d57600080fd5b8063862be28714610aea5780638da5cb5b14610b0a578063921e274b14610b47578063950a651314610b5a57600080fd5b80634f9a8d8f1161040b578063715018a6116103685780637b0a0f9b1161031c5780637d8149db116103015780637d8149db14610a7d5780638247a23914610a9d57806384725c7614610abd57600080fd5b80637b0a0f9b14610a3d5780637b15b94c14610a5d57600080fd5b806373c218031161034d57806373c21803146109b7578063750dd2a1146109d7578063794c0c6814610a2757600080fd5b8063715018a61461096c578063728345db1461098157600080fd5b80635fef7643116103bf578063673a2a1f116103a4578063673a2a1f146109145780636bda1577146109365780637069e7461461095657600080fd5b80635fef7643146108c8578063615f2b71146108de57600080fd5b8063567e98f9116103f0578063567e98f91461087c5780635b4eafe0146108925780635d80ca32146108b257600080fd5b80634f9a8d8f146108395780635267e1d61461084f57600080fd5b806326476204116104b95780633b7d09461161046d5780634160d386116104525780634160d386146107cc5780634346845f146107ec5780634e9b426d1461080c57600080fd5b80633b7d0946146107995780633f3afe01146107b957600080fd5b80633219d6001161049e5780633219d6001461072e578063371542631461076e578063379b046a1461078357600080fd5b806326476204146106fb5780632bafde8d1461070e57600080fd5b80631555371c1161051057806320c07cd8116104f557806320c07cd8146106b057806322e3d986146106c6578063251441a9146106db57600080fd5b80631555371c1461061f5780631fb31e431461063457600080fd5b8063028b8bdb146105645780630ac6e2911461058d5780630b770cdf146105af5780631345b8a5146105e757600080fd5b3661055f57604051631574f9f360e01b815260040160405180910390fd5b600080fd5b34801561057057600080fd5b5061057a60145481565b6040519081526020015b60405180910390f35b34801561059957600080fd5b506105ad6105a836600461531c565b610fdd565b005b3480156105bb57600080fd5b506024546105cf906001600160a01b031681565b6040516001600160a01b039091168152602001610584565b3480156105f357600080fd5b5061057a6106023660046153cc565b602160209081526000928352604080842090915290825290205481565b34801561062b57600080fd5b506105ad611574565b34801561064057600080fd5b5061067e61064f3660046153fc565b6001600160a01b03166000908152601e6020526040902060010154608081901b91600160801b90910460f01b90565b604080516fffffffffffffffffffffffffffffffff1990931683526001600160f01b0319909116602083015201610584565b3480156106bc57600080fd5b5061057a6107d081565b3480156106d257600080fd5b5061057a6115e6565b3480156106e757600080fd5b506105ad6106f6366004615419565b61162d565b6105ad6107093660046153fc565b6116eb565b34801561071a57600080fd5b506105ad61072936600461545a565b61176e565b34801561073a57600080fd5b5061075e6107493660046153fc565b601f6020526000908152604090205460ff1681565b6040519015158152602001610584565b34801561077a57600080fd5b506105ad6117ef565b34801561078f57600080fd5b5061057a601a5481565b3480156107a557600080fd5b506105ad6107b43660046153fc565b611bea565b6105ad6107c7366004615473565b611c20565b3480156107d857600080fd5b506105ad6107e7366004615473565b611f56565b3480156107f857600080fd5b506105ad6108073660046154bc565b611ff5565b34801561081857600080fd5b5061082c6108273660046153fc565b6120fb565b604051610584919061556d565b34801561084557600080fd5b5061057a60165481565b34801561085b57600080fd5b5061057a61086a3660046153fc565b601b6020526000908152604090205481565b34801561088857600080fd5b5061057a601c5481565b34801561089e57600080fd5b5061057a6108ad3660046153cc565b6121a7565b3480156108be57600080fd5b5061057a600e5481565b3480156108d457600080fd5b5061057a600c5481565b3480156108ea57600080fd5b506105cf6108f93660046153fc565b6025602052600090815260409020546001600160a01b031681565b34801561092057600080fd5b506109296121d1565b6040516105849190615580565b34801561094257600080fd5b5061057a6109513660046155cd565b6121e2565b34801561096257600080fd5b5061057a60195481565b34801561097857600080fd5b506105ad612362565b34801561098d57600080fd5b5061057a61099c3660046153cc565b60208080526000928352604080842090915290825290205481565b3480156109c357600080fd5b506109296109d23660046153fc565b612376565b3480156109e357600080fd5b5061057a6109f23660046155cd565b6001600160a01b039182166000908152600b602090815260408083209390941682529182528281206015548252909152205490565b348015610a3357600080fd5b5061057a60155481565b348015610a4957600080fd5b506105ad610a58366004615634565b61239a565b348015610a6957600080fd5b506105ad610a783660046153fc565b612417565b348015610a8957600080fd5b506105ad610a98366004615679565b61247e565b348015610aa957600080fd5b506105ad610ab836600461545a565b612500565b348015610ac957600080fd5b5061057a610ad83660046153fc565b60266020526000908152604090205481565b348015610af657600080fd5b506105ad610b053660046156d6565b612533565b348015610b1657600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03166105cf565b6105ad610b5536600461573b565b612596565b348015610b6657600080fd5b5061057a610b753660046155cd565b6126df565b348015610b8657600080fd5b50610b8f612827565b6040516105849291906157f9565b348015610ba957600080fd5b50610bbd610bb83660046153fc565b61288a565b6040516105849392919061581b565b348015610bd857600080fd5b5061057a60185481565b348015610bee57600080fd5b5061057a61271081565b348015610c0457600080fd5b506105ad610c1336600461545a565b61293e565b348015610c2457600080fd5b50610929610c333660046153fc565b612989565b348015610c4457600080fd5b5061057a610c533660046155cd565b601160209081526000928352604080842090915290825290205481565b348015610c7c57600080fd5b506109296129ad565b348015610c9157600080fd5b5061057a610ca03660046155cd565b601360209081526000928352604080842090915290825290205481565b348015610cc957600080fd5b5061075e610cd83660046153fc565b612a0f565b348015610ce957600080fd5b506105ad612a1b565b348015610cfe57600080fd5b5061057a60175481565b348015610d1457600080fd5b506105ad610d23366004615473565b612a60565b348015610d3457600080fd5b50610d48610d43366004615878565b612dc7565b6040516105849190615929565b348015610d6157600080fd5b5061075e610d70366004615957565b612e77565b348015610d8157600080fd5b50610d48610d90366004615679565b613052565b348015610da157600080fd5b5061057a6130f7565b348015610db657600080fd5b506105ad610dc5366004615473565b613116565b348015610dd657600080fd5b506105ad610de53660046153fc565b6131c0565b348015610df657600080fd5b506105ad610e053660046153cc565b613393565b348015610e1657600080fd5b506109296134d2565b348015610e2b57600080fd5b5061057a600d5481565b348015610e4157600080fd5b5061057a610e503660046153fc565b60106020526000908152604090205481565b348015610e6e57600080fd5b506109296134de565b348015610e8357600080fd5b50601d546105cf906001600160a01b031681565b348015610ea357600080fd5b5061057a610eb23660046155cd565b600f60209081526000928352604080842090915290825290205481565b348015610edb57600080fd5b506105ad6134ea565b348015610ef057600080fd5b506105ad61362a565b348015610f0557600080fd5b5061057a610bb881565b348015610f1b57600080fd5b506105ad610f2a3660046153fc565b613670565b348015610f3b57600080fd5b506105ad610f4a366004615473565b6136ab565b348015610f5b57600080fd5b50600161075e565b348015610f6f57600080fd5b5061075e610f7e3660046153fc565b613764565b348015610f8f57600080fd5b5061057a610f9e3660046153fc565b60276020526000908152604090205481565b348015610fbc57600080fd5b5061057a610fcb3660046153fc565b60126020526000908152604090205481565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff166000811580156110285750825b905060008267ffffffffffffffff1660011480156110455750303b155b905081158015611053575080155b156110715760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156110a557845468ff00000000000000001916680100000000000000001785555b6001600160a01b038b166110cc5760405163d92e233d60e01b815260040160405180910390fd5b6110d58a613781565b876110e360408c018c615973565b6110ef915060026159d3565b1461110c5760405162d6988760e81b815260040160405180910390fd5b8561111a60408c018c615973565b90501461113a576040516320041afd60e01b815260040160405180910390fd5b6111438b6138e4565b61114b6138f5565b61115860208b018b6153fc565b601d80546001600160a01b0319166001600160a01b039290921691909117905561118860408b0160208c016153fc565b602480546001600160a01b0319166001600160a01b03929092169190911790553660006111b860408d018d615973565b9150915060005b818110156113db5760008383838181106111db576111db6159ea565b90506020020160208101906111f091906153fc565b6001600160a01b0316036112175760405163d92e233d60e01b815260040160405180910390fd5b61124883838381811061122c5761122c6159ea565b905060200201602081019061124191906153fc565b6000613905565b61127783838381811061125d5761125d6159ea565b905060200201602081019061127291906153fc565b613965565b8b8b6112848360026159d3565b818110611293576112936159ea565b905060200201358c8c8360026112a991906159d3565b6112b4906001615a00565b8181106112c3576112c36159ea565b905060200201356040516020016112e4929190918252602082015260400190565b604051602081830303815290604052601e6000858585818110611309576113096159ea565b905060200201602081019061131e91906153fc565b6001600160a01b031681526020810191909152604001600020906113429082615a9d565b50898982818110611355576113556159ea565b905060200201602081019061136a9190615b5d565b601e6000858585818110611380576113806159ea565b905060200201602081019061139591906153fc565b6001600160a01b031681526020810191909152604001600020600190810180546fffffffffffffffffffffffffffffffff191660809390931c92909217909155016111bf565b5060408051600580825260c082019092526000916020820160a0803683370190505090506802b5e3af16b18800008160008151811061141c5761141c6159ea565b60200260200101818152505068056bc75e2d6310000081600181518110611445576114456159ea565b602002602001018181525050680821ab0d44149800008160028151811061146e5761146e6159ea565b602002602001018181525050680ad78ebc5ac620000081600381518110611497576114976159ea565b602002602001018181525050680d8d726b7177a80000816004815181106114c0576114c06159ea565b60209081029190910101526114e4632bafde8d60e01b636d3d4db560e11b8361397a565b50505060608a0135600d5560808a0135600c5560a08a0135600e5560c08a01356016556101008a01356014554260185560e08a0135601755831561156757845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050505050565b601d546001600160a01b0316331461159e576040516282b42960e81b815260040160405180910390fd5b60006115aa6004613a2f565b905060005b81518110156115e2576115da8282815181106115cd576115cd6159ea565b6020026020010151613a43565b6001016115af565b5050565b60185460165460009190156115fc5760016115ff565b60005b60ff16601a54601654836116139190615a00565b61161d9190615a00565b6116279190615b78565b91505090565b3a60000361164e57604051630e661aed60e41b815260040160405180910390fd5b816001600160a01b0316836001600160a01b03160361168057604051630a5eddd560e01b815260040160405180910390fd5b3361168c848284613a89565b611697838284613d37565b601554604080516001600160a01b0387811682526020820186905280851692908716917f4480d8e4b1e9095b94bf513961d26fe1d32386ebdd103d18fe8738cf4b2223ff910160405180910390a450505050565b3a60000361170c57604051630e661aed60e41b815260040160405180910390fd5b3334611719838383613d37565b601554826001600160a01b0316846001600160a01b03167f2273de02cb1f69ba6259d22c4bc22c60e4c94c193265ef6afee324a04a9b6d228460405161176191815260200190565b60405180910390a4505050565b611776614088565b8061178d6000356001600160e01b03191682612e77565b6117b2576040516373330d9b60e01b8152600481018290526024015b60405180910390fd5b600d8290556040518281527ffee02ce7aa40f9c49eaabd26d404fa88714b97cb209af8954cfd5eeb8213b93e906020015b60405180910390a15050565b3a60000361181057604051630e661aed60e41b815260040160405180910390fd5b60008061181d6002613a2f565b9050805160000361184157604051631c369b4560e21b815260040160405180910390fd5b60005b8151811015611a29576000828281518110611861576118616159ea565b60200260200101519050611874816140e3565b806118ea5750601d54604051639d6fc1d160e01b81526001600160a01b03838116600483015290911690639d6fc1d190602401602060405180830381865afa1580156118c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e89190615b8b565b155b156118f55750611a21565b611900600282614121565b506001600160a01b0381166000908152601f60209081526040808320805460ff19166001179055601b9091528120805490829055601c805491928392611947908490615b78565b909155506000905061195883612989565b905060005b81518110156119c357600082828151811061197a5761197a6159ea565b6020908102919091018101516001600160a01b03808816600090815260138452604080822092841682529190935282209190915590506119ba8582614136565b5060010161195d565b506119ce8287615a00565b9550826001600160a01b0316336001600160a01b03167f8e6a4ccd7dccdca9ac211d00fcc3fa7c71be75ff73d3a35f63ea023173cc100484604051611a1591815260200190565b60405180910390a35050505b600101611844565b5081600003611a4b57604051631c369b4560e21b815260040160405180910390fd5b6000611a58600284615bad565b90506000611a668285615b78565b90506000601d60009054906101000a90046001600160a01b03166001600160a01b03166356b54bae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611abd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae19190615bcf565b90506000816001600160a01b031663732524946040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b479190615bcf565b9050816001600160a01b031663af182535846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b8457600080fd5b505af1158015611b98573d6000803e3d6000fd5b5050505050611ba78185614198565b604080518481526020810186905233917f1c113e6bae9530fea40323e612aeb0cb7817dedb5a0b0f6bdfbff97d55920dc7910160405180910390a2505050505050565b601d546001600160a01b03163314611c14576040516282b42960e81b815260040160405180910390fd5b611c1d81613a43565b50565b601d60009054906101000a90046001600160a01b03166001600160a01b03166356b54bae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c979190615bcf565b6001600160a01b0316336001600160a01b031614611cc7576040516282b42960e81b815260040160405180910390fd5b34156115e2576015546000908152602080805260408083206001600160a01b03861684529091528120543491611cfe85848661423f565b90506000611d0b86612989565b905060005b8151811015611e5a57600084611d426015548a868681518110611d3557611d356159ea565b602002602001015161435e565b8560400151611d5191906159d3565b611d5b9190615bad565b905080601360008a6001600160a01b03166001600160a01b031681526020019081526020016000206000858581518110611d9757611d976159ea565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254611dce9190615a00565b90915550506001600160a01b0388166000908152600b602052604081208451839290869086908110611e0257611e026159ea565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600060155481526020019081526020016000206000828254611e4c9190615a00565b909155505050600101611d10565b50602082015115611e7357611e738683602001516143ff565b81516001600160a01b038716600090815260136020908152604080832090915281208054909190611ea5908490615a00565b90915550506001600160a01b0386166000908152601b602052604081208054869290611ed2908490615a00565b9250508190555083601c6000828254611eeb9190615a00565b90915550611efa9050866144c6565b60155482516001600160a01b038816907f72093068b9f28053bd924ac15d7710b987f9b6ef1e0f89f47d8b4bd7cac776dc90611f368189615b78565b6040805192835260208301919091520160405180910390a3505050505050565b601d546040516253517560e01b81523360048201526000916001600160a01b0316906253517590602401602060405180830381865afa158015611f9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc19190615bcf565b6001600160a01b031603611fea57604051632670461960e11b81523360048201526024016117a9565b6115e23383836145b2565b611ffd614088565b60006120076146ea565b90506040518060400160405280857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200184848080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509390945250506001600160e01b031988168152602084815260409091208351815463ffffffff191660e09190911c1781558382015180519193506120b3926001850192910190615241565b509050507f3665bf9cd0ba4ddceeec259e21dcf8a4510f3b1130bd42e950828e69d85408ba858585856040516120ec9493929190615bec565b60405180910390a15050505050565b6001600160a01b0381166000908152601e6020526040902080546060919061212290615a13565b80601f016020809104026020016040519081016040528092919081815260200182805461214e90615a13565b801561219b5780601f106121705761010080835404028352916020019161219b565b820191906000526020600020905b81548152906001019060200180831161217e57829003601f168201915b50505050509050919050565b60008281526021602090815260408083206001600160a01b03851684529091529020545b92915050565b60606121dd6000613a2f565b905090565b601d546040516253517560e01b81526001600160a01b03848116600483015260009283929116906253517590602401602060405180830381865afa15801561222e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122529190615bcf565b90506001600160a01b0384166000908152601f602052604090205460ff161561227f5760009150506121cb565b6001600160a01b03848116600090815260136020908152604080832087851684529091529081902054601d54915163a0d16cad60e01b815284841660048201529092919091169063a0d16cad90602401602060405180830381865afa1580156122ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123109190615b8b565b61231d5791506121cb9050565b6001600160a01b038581166000908152600b60209081526040808320938816835292815282822060155483529052205480821115612359578091505b50949350505050565b61236a614088565b612374600061474c565b565b6001600160a01b0381166000908152600a602052604090206060906121cb90613a2f565b601d546001600160a01b031633146123c4576040516282b42960e81b815260040160405180910390fd5b6001600160a01b039092166000908152601e60205260409020600101805460f09390931c600160801b0271ffffffffffffffffffffffffffffffffffff1990931660809290921c91909117919091179055565b601d546001600160a01b03163314612441576040516282b42960e81b815260040160405180910390fd5b600c546001600160a01b038216600090815260136020908152604080832090915290205410611c1d57612475816001613905565b611c1d816144c6565b612486614088565b60006124906146ea565b6001600160e01b031983166000908152602082905260408120805463ffffffff191681559192506124c4600183018261528c565b50506040516001600160e01b0319831681527fed27cb02231782dadf13473a7828cb980c4d685791b7a3136dde00f8c3594cb6906020016117e3565b601d546001600160a01b0316331461252a576040516282b42960e81b815260040160405180910390fd5b60185543601955565b336000908152601e6020526040902061254d848683615c59565b50336000908152601e60205260409020600101805460f09290921c600160801b0271ffffffffffffffffffffffffffffffffffff1990921660809390931c929092171790555050565b3a6000036125b757604051630e661aed60e41b815260040160405180910390fd5b601d54604051630526083960e11b81526001600160a01b0388811660048301523360248301819052923492911690630a4c107290604401600060405180830381600087803b15801561260857600080fd5b505af115801561261c573d6000803e3d6000fd5b505050506001600160a01b0382166000908152601e60205260409020612643858783615c59565b506001600160a01b0382166000908152601e6020526040902060010180546fffffffffffffffffffffffffffffffff1916608085901c1790556126878288886145b2565b612692828383613d37565b6015546040518281526001600160a01b0384169081907f2273de02cb1f69ba6259d22c4bc22c60e4c94c193265ef6afee324a04a9b6d229060200160405180910390a45050505050505050565b601d546040516253517560e01b81526001600160a01b03848116600483015260009283929116906253517590602401602060405180830381865afa15801561272b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274f9190615bcf565b9050601d5460405163a0d16cad60e01b81526001600160a01b0383811660048301529091169063a0d16cad90602401602060405180830381865afa15801561279b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127bf9190615b8b565b6127cd5760009150506121cb565b6001600160a01b038481166000818152600b60209081526040808320948816808452948252808320601554845282528083205493835260138252808320948352939052919091205461281f9190615b78565b949350505050565b6060600060076008548180548060200260200160405190810160405280929190818152602001828054801561287b57602002820191906000526020600020905b815481526020019060010190808311612867575b50505050509150915091509091565b601e602052600090815260409020805481906128a590615a13565b80601f01602080910402602001604051908101604052809291908181526020018280546128d190615a13565b801561291e5780601f106128f35761010080835404028352916020019161291e565b820191906000526020600020905b81548152906001019060200180831161290157829003601f168201915b50505060019093015491925050608081901b90600160801b900460f01b83565b601d546001600160a01b03163314612968576040516282b42960e81b815260040160405180910390fd5b60175481601a546129799190615a00565b6129839190615a00565b601a5550565b6001600160a01b03811660009081526009602052604090206060906121cb90613a2f565b60606006805480602002602001604051908101604052809291908181526020018280548015612a0557602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116129e7575b5050505050905090565b60006121cb81836147bd565b601d546001600160a01b03163314612a45576040516282b42960e81b815260040160405180910390fd5b601754601a6000828254612a599190615a00565b9091555050565b3a600003612a8157604051630e661aed60e41b815260040160405180910390fd5b6001600160a01b038216612aa85760405163d92e233d60e01b815260040160405180910390fd5b80600003612ac957604051633ca0029d60e01b815260040160405180910390fd5b6001600160a01b0382166000818152600f602090815260408083203380855290835281842054858552601084528285205460138552838620838752855283862054968652601b9094529184205490949193861315612bd357856000612b2e89886126df565b905080821115612b5b57604051632de4882160e01b815260048101829052602481018390526044016117a9565b612b658287615a00565b9550612b718286615a00565b9450612b7d8285615b78565b9350612b898284615b78565b925081601c6000828254612b9d9190615b78565b90915550506015546001600160a01b03808b166000908152601160209081526040808320938c168352929052205550612c299050565b6000612bde87615d1a565b9050612bea8186615b78565b9450612bf68185615b78565b9350612c028184615a00565b9250612c0e8183615a00565b915080601c6000828254612c229190615a00565b9091555050505b6001600160a01b038088166000818152600f60209081526040808320948a1680845294825280832089905583835260108252808320889055601382528083208584528252808320879055838352601b90915290208390559003612cf8578115801590612c965750600c5482105b15612cce57604051636fe84f3d60e01b81526001600160a01b03808916600483015286166024820152604481018790526064016117a9565b6000861315612ced5781600003612ce857612ce887613965565b612d65565b612ce8876001613905565b8115801590612d085750600d5482105b15612d4057604051636fe84f3d60e01b81526001600160a01b03808916600483015286166024820152604481018790526064016117a9565b6000861315612d5b5781600003612ce857612ce88786614136565b612d6587866147df565b612d6e876144c6565b601554856001600160a01b0316886001600160a01b03167f80d5c777e5f7ac6ee89723223803ca5c0ec0204f89e99c1b0cde973c66a6459489604051612db691815260200190565b60405180910390a450505050505050565b604080518082019091526000815260606020820152612de46146ea565b82516020808501919091206001600160e01b0319908116600090815292825260409283902083518085018552815460e01b9092168252600181018054855181860281018601909652808652929491938581019390830182828015612e6757602002820191906000526020600020905b815481526020019060010190808311612e53575b5050505050815250509050919050565b600080612e826146ea565b6001600160e01b031980861660009081526020838152604080832081518083018352815460e01b90951685526001810180548351818602810186019094528084529697509395909385840193909190830182828015612f0057602002820191906000526020600020905b815481526020019060010190808311612eec575b5050505050815250509050806020015151600003612f23576000925050506121cb565b60208101518151600090612f369061480c565b905060005b82518110156130445781838281518110612f5757612f576159ea565b60200260200101510361303c576000808211612f8d5783600081518110612f8057612f806159ea565b6020026020010151612fb2565b83612f99600184615b78565b81518110612fa957612fa96159ea565b60200260200101515b9050600060018551612fc49190615b78565b8310612ff6578460018651612fd99190615b78565b81518110612fe957612fe96159ea565b602002602001015161301b565b84613002846001615a00565b81518110613012576130126159ea565b60200260200101515b905081891415801561302d5750808914155b159750505050505050506121cb565b600101612f3b565b506000979650505050505050565b60408051808201909152600081526060602082015261306f6146ea565b6001600160e01b03198084166000908152602092835260409081902081518083018352815460e01b9093168352600181018054835181870281018701909452808452939491938583019392830182828015612e675760200282019190600052602060002090815481526020019060010190808311612e53575050505050815250509050919050565b600060175460165460185461310c9190615a00565b6121dd9190615b78565b6024546001600160a01b03163314613140576040516282b42960e81b815260040160405180910390fd5b601d546040516307b9342f60e21b81526001600160a01b0384811660048301526000921690631ee4d0bc90602401602060405180830381865afa15801561318b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131af9190615bcf565b90506131bb81836148e3565b505050565b3a6000036131e157604051630e661aed60e41b815260040160405180910390fd5b6131e961498d565b6001600160a01b0381166000908152601160209081526040808320338085529252909120546015541161324257604051630b06352b60e31b81526001600160a01b038084166004830152821660248201526044016117a9565b6001600160a01b038083166000908152600f602090815260408083209385168352929052908120549081900361328b57604051633ca0029d60e01b815260040160405180910390fd5b6001600160a01b038084166000818152600f602090815260408083209487168352938152838220829055918152601090915220546132ca908290615b78565b6001600160a01b038085166000908152601060209081526040808320949094556013815283822092861682529190915290812054900361330e5761330e83836149d7565b6133188282614198565b601554826001600160a01b0316846001600160a01b03167ff380b0bc887e00f5b50d3c9d4eaaf5c9a0afd97b956316b995159384c4ede9b38460405161336091815260200190565b60405180910390a45050611c1d60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b601d60009054906101000a90046001600160a01b03166001600160a01b03166356b54bae6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061340a9190615bcf565b6001600160a01b0316336001600160a01b03161461343a576040516282b42960e81b815260040160405180910390fd5b6000828152602080805260408083206001600160a01b038516845290915281205490036115e2576001600160a01b0381166000908152601b60205260408120549081900361348757505050565b6000838152602080805260408083206001600160a01b038616808552908352818420949094556013825280832082528083205486845260218352818420948452939091529020555050565b60606121dd6004613a2f565b60606121dd6002613a2f565b3a60000361350b57604051630e661aed60e41b815260040160405180910390fd5b601d546040516253517560e01b81523360048201819052916000916001600160a01b03909116906253517590602401602060405180830381865afa158015613557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061357b9190615bcf565b905060155460001480156135f85750601d5460405163facd743b60e01b81526001600160a01b0383811660048301529091169063facd743b90602401602060405180830381865afa1580156135d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f89190615b8b565b15613621576040516303d71f2d60e51b81526001600160a01b03831660048201526024016117a9565b6115e282613a43565b601d546001600160a01b03163314613654576040516282b42960e81b815260040160405180910390fd5b6015805490600061366483615d36565b90915550506000601a55565b613678614088565b6001600160a01b0381166136a257604051631e4fbdf760e01b8152600060048201526024016117a9565b611c1d8161474c565b3a6000036136cc57604051630e661aed60e41b815260040160405180910390fd5b6136d461498d565b336136e0838284613a89565b6136ea8183614198565b601554816001600160a01b0316846001600160a01b03167fa7c0f0cac6bd4d18042007706c84a8abe823751cf289b69c01e83eef7b5915c78560405161373291815260200190565b60405180910390a4506115e260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b600061377081836147bd565b806121cb57506121cb6002836147bd565b60c0810135158061379b57508061010001358160c0013511155b156137b95760405163c671116b60e01b815260040160405180910390fd5b8061010001356000036137df576040516332154b4760e01b815260040160405180910390fd5b60e081013515806137f857508060c001358160e0013510155b1561381657604051630685efe960e01b815260040160405180910390fd5b600061382560208301836153fc565b6001600160a01b03160361384c5760405163d92e233d60e01b815260040160405180910390fd5b6138596040820182615973565b905060000361387b57604051635c9a24ed60e11b815260040160405180910390fd5b6060810135158061388e57506080810135155b156138bc5760405163633373e160e11b815260808201356004820152606082013560248201526044016117a9565b80608001358160a0013511611c1d57604051631c6d3b1560e01b815260040160405180910390fd5b6138ec614b2d565b611c1d81614b7b565b6138fd614b2d565b612374614b83565b61390e82612a0f565b61394a5761391d600083614b8b565b50610bb861392b6000614ba0565b111561394a5760405163398dcd9d60e21b815260040160405180910390fd5b613955600283614121565b5080156115e2576115e282614baa565b613970600482614b8b565b50611c1d81614c9f565b613982614b2d565b600061398c6146ea565b6040805180820182526001600160e01b0319868116825260208083018781529189166000908152858252939093208251815463ffffffff191660e09190911c17815590518051949550919390926139ea926001850192910190615241565b509050507f3665bf9cd0ba4ddceeec259e21dcf8a4510f3b1130bd42e950828e69d85408ba848484604051613a2193929190615d4f565b60405180910390a150505050565b60606000613a3c83614ebc565b9392505050565b613a4e600082614121565b50613a58816140e3565b15613a6e57613a68600282614121565b50613a77565b613a7781614f17565b613a8081614c9f565b611c1d81614f22565b6001600160a01b038316613ab05760405163d92e233d60e01b815260040160405180910390fd5b80600003613ad157604051633ca0029d60e01b815260040160405180910390fd5b6000613add84846121e2565b905080821115613b0a57604051632de4882160e01b815260048101829052602481018390526044016117a9565b6001600160a01b038085166000908152601360209081526040808320938716835292905290812054613b3d908490615b78565b90506000846001600160a01b0316866001600160a01b031614613b6257600d54613b66565b600c545b90508115801590613b7657508082105b15613bae57604051639e612d5760e01b81526001600160a01b03808816600483015286166024820152604481018590526064016117a9565b856001600160a01b0316856001600160a01b031614613c4357601d546040516253517560e01b81526001600160a01b03888116600483015260009216906253517590602401602060405180830381865afa158015613c10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c349190615bcf565b9050613c41878288614f2d565b505b6001600160a01b038681166000818152601360209081526040808320948a16808452948252808320879055928252600b8152828220938252928352818120601554825290925290205484811015613c9b576000613ca5565b613ca58582615b78565b6001600160a01b038089166000818152600b60209081526040808320948c1683529381528382206015548352815283822094909455908152601b90925281208054879290613cf4908490615b78565b9250508190555084601c6000828254613d0d9190615b78565b90915550506000839003613d2557613d2587876149d7565b613d2e876144c6565b50505050505050565b6001600160a01b038316613d5e5760405163d92e233d60e01b815260040160405180910390fd5b601d546040516253517560e01b81526001600160a01b03858116600483015260009216906253517590602401602060405180830381865afa158015613da7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dcb9190615bcf565b90506001600160a01b038116613dff57604051632670461960e11b81526001600160a01b03851660048201526024016117a9565b81600003613e335760405163e59f5c3960e01b81526001600160a01b038086166004830152841660248201526044016117a9565b6001600160a01b0384166000908152601f602052604090205460ff1615613e785760405163078137eb60e41b81526001600160a01b03851660048201526024016117a9565b6001600160a01b038085166000818152601360209081526040808320948816808452949091528120549290911491613eb1908590615a00565b905060008215613ec45750600c54613f13565b50600d546001600160a01b03871660009081526013602090815260408083209091528120549003613f135760405163cbbeb0bd60e01b81526001600160a01b03881660048201526024016117a9565b80821015613f475760405163e59f5c3960e01b81526001600160a01b038089166004830152871660248201526044016117a9565b600e546001600160a01b0388166000908152601b6020526040902054613f6e908790615a00565b1115613fa057604051632c2b174160e21b81526001600160a01b038089166004830152871660248201526044016117a9565b6001600160a01b038088166000908152600b60209081526040808320938a168352928152828220601554835290529081208054879290613fe1908490615a00565b90915550506001600160a01b0387166000908152601b60205260408120805487929061400e908490615a00565b9250508190555084601c60008282546140279190615a00565b909155505082156140425761403d876001613905565b614057565b61404c87876147df565b614057878588614f2d565b6001600160a01b038088166000908152601360209081526040808320938a16835292905220829055613d2e876144c6565b336140ba7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146123745760405163118cdaa760e01b81523360048201526024016117a9565b6001600160a01b0381166000908152601b60205260408120541580156121cb5750506001600160a01b03166000908152601060205260409020541590565b6000613a3c836001600160a01b038416615049565b6001600160a01b03821660009081526009602052604090206141589082614121565b506001600160a01b038083166000908152600f60209081526040808320938516835292905220541561418e576115e2828261513c565b6115e2828261515e565b804710156141b957604051631e9acf1760e31b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614206576040519150601f19603f3d011682016040523d82523d6000602084013e61420b565b606091505b50509050806131bb57604051630e21dcbb60e11b81526001600160a01b0384166004820152602481018390526044016117a9565b61426360405180606001604052806000815260200160008152602001600081525090565b6015546000818152602080805260408083206001600160a01b03891680855290835281842054948452602183528184209084529091528120549060646142a986886159d3565b6142b39190615bad565b90506142bf8187615b78565b6040808601919091526001600160a01b038089166000908152602660209081528382205460259091529290205416158015906142fa57508015155b1561431c5761271061430c82896159d3565b6143169190615bad565b60208601525b8383866040015161432d91906159d3565b6143379190615bad565b60208601516143469084615b78565b6143509190615a00565b855250929695505050505050565b60008360000361437057506000613a3c565b6001600160a01b038084166000908152602360209081526040808320938616835292905220548490036143d157506001600160a01b038083166000908152602260209081526040808320938516835292815282822086835290522054613a3c565b506001600160a01b038083166000908152601360209081526040808320938516835292905220549392505050565b6001600160a01b03808316600090815260256020908152604080832054600990925290912091169061443190826147bd565b61443f5761443f83826147df565b6001600160a01b03808416600090815260136020908152604080832093851683529290529081208054849290614476908490615a00565b90915550506001600160a01b038084166000908152600b6020908152604080832093851683529281528282206015548352905290812080548492906144bc908490615a00565b9091555050505050565b601d546040516253517560e01b81526001600160a01b03838116600483015260009216906253517590602401602060405180830381865afa15801561450f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145339190615bcf565b60248054604051633941e77760e21b81526001600160a01b0380851660048301529394506000939091169163e5079ddc9101602060405180830381865afa158015614582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145a69190615d7c565b90506131bb83826148e3565b6107d08111156145d85760405163e429b69160e01b8152600481018290526024016117a9565b6001600160a01b0382161580156145ee57508015155b1561461e5760405163073c315960e11b81526001600160a01b0383166004820152602481018290526044016117a9565b6001600160a01b0383166000908152602760205260409020548015801590614647575060155481145b1561466b5760155460405163e7cbc70160e01b81526004016117a991815260200190565b6001600160a01b03848116600081815260256020908152604080832080546001600160a01b03191695891695861790556026825280832087905560155460278352928190209290925590518581527fd6ae57aa2cc060d4094c47d20c672afe0e53963e6459c15cab215abb8c88b863910160405180910390a350505050565b60008060ff1961471b60017fdace3fd3d1fbdfd33853f19ba191d28c617e373ec58fc73cf7b58db5aff2c2ab615b78565b60405160200161472d91815260200190565b60408051601f1981840301815291905280516020909101201692915050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b6001600160a01b03811660009081526001830160205260408120541515613a3c565b6001600160a01b03821660009081526009602052604090206148019082614b8b565b506115e2828261515e565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03198516179052905160009190829081903090614863908590615d95565b600060405180830381855afa9150503d806000811461489e576040519150601f19603f3d011682016040523d82523d6000602084013e6148a3565b606091505b5091509150816148c657604051635fbab09b60e11b815260040160405180910390fd5b808060200190518101906148da9190615d7c565b95945050505050565b6000806148ef84615180565b91509150816148fe5750505050565b600060078281548110614913576149136159ea565b60009182526020808320909101546001600160a01b0388168352601b90915260408220549092506149459086906159d3565b9050806007848154811061495b5761495b6159ea565b906000526020600020018190555080826008546149789190615b78565b6149829190615a00565b600855505050505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f008054600119016149d157604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b816001600160a01b0316816001600160a01b031603614ae457601d546040516253517560e01b81526001600160a01b03848116600483015260009216906253517590602401602060405180830381865afa158015614a39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a5d9190615bcf565b601d5460405163facd743b60e01b81526001600160a01b03808416600483015292935091169063facd743b90602401602060405180830381865afa158015614aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614acd9190615b8b565b15614adb576131bb83613965565b6131bb83613a43565b614aee8282614136565b614af7826140e3565b156115e2576131bb600283614121565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff1661237457604051631afcd79f60e31b815260040160405180910390fd5b613678614b2d565b614b07614b2d565b6000613a3c836001600160a01b0384166151f2565b60006121cb825490565b6001600160a01b0381166000908152601260205260409020546006548082101580614c055750826001600160a01b031660068381548110614bed57614bed6159ea565b6000918252602090912001546001600160a01b031614155b15614c96576001600160a01b03831660008181526012602052604081208390556006805460018181019092557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0180546001600160a01b03191690931790925560078054928301815581527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909101555b6131bb83614f22565b60075460065414614cad5750565b6001600160a01b03811660009081526012602052604090205460065481108015614d065750816001600160a01b031660068281548110614cef57614cef6159ea565b6000918252602090912001546001600160a01b0316145b156115e25760078181548110614d1e57614d1e6159ea565b906000526020600020015460085410614d6b5760078181548110614d4457614d446159ea565b906000526020600020015460086000828254614d609190615b78565b90915550614d719050565b60006008555b600654600090614d8390600190615b78565b9050600060068281548110614d9a57614d9a6159ea565b600091825260209091200154600680546001600160a01b039092169250829185908110614dc957614dc96159ea565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060078281548110614e0a57614e0a6159ea565b906000526020600020015460078481548110614e2857614e286159ea565b60009182526020808320909101929092556001600160a01b038084168252601290925260408082208690559186168152908120556006805480614e6d57614e6d615db1565b600082815260209020810160001990810180546001600160a01b03191690550190556007805480614ea057614ea0615db1565b6001900381819060005260206000200160009055905550505050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561219b57602002820191906000526020600020905b815481526020019060010190808311614ef85750505050509050919050565b6115e2600282614b8b565b6115e2600482614121565b601d5460405163a0d16cad60e01b81526001600160a01b0384811660048301529091169063a0d16cad90602401602060405180830381865afa158015614f77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f9b9190615b8b565b1580614fa75750601554155b15614fb157505050565b6001600160a01b03808416600090815260236020908152604080832093851683529290522054601554811015615043576001600160a01b0380851660008181526013602090815260408083209487168084529482528083205484845260228352818420868552835281842060158054865290845282852091909155549383526023825280832094835293905291909120555b50505050565b6000818152600183016020526040812054801561513257600061506d600183615b78565b855490915060009061508190600190615b78565b90508082146150e65760008660000182815481106150a1576150a16159ea565b90600052602060002001549050808760000184815481106150c4576150c46159ea565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806150f7576150f7615db1565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506121cb565b60009150506121cb565b6001600160a01b0382166000908152600a602052604090206131bb9082614b8b565b6001600160a01b0382166000908152600a602052604090206131bb9082614121565b6001600160a01b038116600090815260126020526040812054600654811080156151d95750826001600160a01b0316600682815481106151c2576151c26159ea565b6000918252602090912001546001600160a01b0316145b156151e75760019150915091565b506000928392509050565b6000818152600183016020526040812054615239575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556121cb565b5060006121cb565b82805482825590600052602060002090810192821561527c579160200282015b8281111561527c578251825591602001919060010190615261565b506152889291506152a6565b5090565b5080546000825590600052602060002090810190611c1d91905b5b8082111561528857600081556001016152a7565b6001600160a01b0381168114611c1d57600080fd5b60008083601f8401126152e257600080fd5b50813567ffffffffffffffff8111156152fa57600080fd5b6020830191508360208260051b850101111561531557600080fd5b9250929050565b6000806000806000806080878903121561533557600080fd5b8635615340816152bb565b9550602087013567ffffffffffffffff8082111561535d57600080fd5b90880190610120828b03121561537257600080fd5b9095506040880135908082111561538857600080fd5b6153948a838b016152d0565b909650945060608901359150808211156153ad57600080fd5b506153ba89828a016152d0565b979a9699509497509295939492505050565b600080604083850312156153df57600080fd5b8235915060208301356153f1816152bb565b809150509250929050565b60006020828403121561540e57600080fd5b8135613a3c816152bb565b60008060006060848603121561542e57600080fd5b8335615439816152bb565b92506020840135615449816152bb565b929592945050506040919091013590565b60006020828403121561546c57600080fd5b5035919050565b6000806040838503121561548657600080fd5b8235615491816152bb565b946020939093013593505050565b80356001600160e01b0319811681146154b757600080fd5b919050565b600080600080606085870312156154d257600080fd5b6154db8561549f565b93506154e96020860161549f565b9250604085013567ffffffffffffffff81111561550557600080fd5b615511878288016152d0565b95989497509550505050565b60005b83811015615538578181015183820152602001615520565b50506000910152565b6000815180845261555981602086016020860161551d565b601f01601f19169290920160200192915050565b602081526000613a3c6020830184615541565b6020808252825182820181905260009190848201906040850190845b818110156155c15783516001600160a01b03168352928401929184019160010161559c565b50909695505050505050565b600080604083850312156155e057600080fd5b82356155eb816152bb565b915060208301356153f1816152bb565b80356fffffffffffffffffffffffffffffffff19811681146154b757600080fd5b80356001600160f01b0319811681146154b757600080fd5b60008060006060848603121561564957600080fd5b8335615654816152bb565b9250615662602085016155fb565b91506156706040850161561c565b90509250925092565b60006020828403121561568b57600080fd5b613a3c8261549f565b60008083601f8401126156a657600080fd5b50813567ffffffffffffffff8111156156be57600080fd5b60208301915083602082850101111561531557600080fd5b600080600080606085870312156156ec57600080fd5b843567ffffffffffffffff81111561570357600080fd5b61570f87828801615694565b90955093506157229050602086016155fb565b91506157306040860161561c565b905092959194509250565b60008060008060008060a0878903121561575457600080fd5b863561575f816152bb565b9550602087013561576f816152bb565b945060408701359350606087013567ffffffffffffffff81111561579257600080fd5b61579e89828a01615694565b90945092506157b19050608088016155fb565b90509295509295509295565b60008151808452602080850194506020840160005b838110156157ee578151875295820195908201906001016157d2565b509495945050505050565b60408152600061580c60408301856157bd565b90508260208301529392505050565b60608152600061582e6060830186615541565b6fffffffffffffffffffffffffffffffff19949094166020830152506001600160f01b031991909116604090910152919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561588a57600080fd5b813567ffffffffffffffff808211156158a257600080fd5b818401915084601f8301126158b657600080fd5b8135818111156158c8576158c8615862565b604051601f8201601f19908116603f011681019083821181831017156158f0576158f0615862565b8160405282815287602084870101111561590957600080fd5b826020860160208301376000928101602001929092525095945050505050565b602080825282516001600160e01b0319168282015282015160408083015260009061281f60608401826157bd565b6000806040838503121561596a57600080fd5b6154918361549f565b6000808335601e1984360301811261598a57600080fd5b83018035915067ffffffffffffffff8211156159a557600080fd5b6020019150600581901b360382131561531557600080fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176121cb576121cb6159bd565b634e487b7160e01b600052603260045260246000fd5b808201808211156121cb576121cb6159bd565b600181811c90821680615a2757607f821691505b602082108103615a4757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156131bb576000816000526020600020601f850160051c81016020861015615a765750805b601f850160051c820191505b81811015615a9557828155600101615a82565b505050505050565b815167ffffffffffffffff811115615ab757615ab7615862565b615acb81615ac58454615a13565b84615a4d565b602080601f831160018114615b005760008415615ae85750858301515b600019600386901b1c1916600185901b178555615a95565b600085815260208120601f198616915b82811015615b2f57888601518255948401946001909101908401615b10565b5085821015615b4d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215615b6f57600080fd5b613a3c826155fb565b818103818111156121cb576121cb6159bd565b600060208284031215615b9d57600080fd5b81518015158114613a3c57600080fd5b600082615bca57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615be157600080fd5b8151613a3c816152bb565b6001600160e01b0319858116825284166020820152606060408201819052810182905260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115615c3e57600080fd5b8260051b808560808501379190910160800195945050505050565b67ffffffffffffffff831115615c7157615c71615862565b615c8583615c7f8354615a13565b83615a4d565b6000601f841160018114615cb95760008515615ca15750838201355b600019600387901b1c1916600186901b178355615d13565b600083815260209020601f19861690835b82811015615cea5786850135825560209485019460019092019101615cca565b5086821015615d075760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6000600160ff1b8201615d2f57615d2f6159bd565b5060000390565b600060018201615d4857615d486159bd565b5060010190565b6001600160e01b03198481168252831660208201526060604082018190526000906148da908301846157bd565b600060208284031215615d8e57600080fd5b5051919050565b60008251615da781846020870161551d565b9190910192915050565b634e487b7160e01b600052603160045260246000fdfea26469706673582212201896f38a8b2275bfce0b20fc69a95c66e949efc00cf01c09be675d546a79c45964736f6c63430008190033