ETH Price: $3,104.36 (+0.20%)
Gas: 4 Gwei

Contract

0x66612207a7e8d540B72eddA94E3126935545a0B0
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
0x60806040195277472024-03-27 19:50:47105 days ago1711569047IN
 Contract Creation
0 ETH0.2198999641.58798526

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x39610072...5C4010256
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
OperationalStaking

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion
File 1 of 8 : OperationalStaking.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

contract OperationalStaking is OwnableUpgradeable {
    using SafeERC20Upgradeable for IERC20Upgradeable;

    uint256 public constant DIVIDER = 10 ** 18; // 18 decimals used for scaling rates
    uint128 public constant REWARD_REDEEM_THRESHOLD = 10 ** 8; // minimum number of tokens that can be redeemed
    uint128 public constant DEFAULT_VALIDATOR_ENABLE_MIN_STAKE = 35000 * 10 ** 18; // minimum number of self-staked tokens for a validator to become / stay enabled
    uint128 public constant DEFAULT_DELEGATOR_MIN_STAKE = 10 ** 18; // stake/unstake operations are invalid if they put you below this threshold (except unstaking to 0)

    IERC20Upgradeable public CQT;
    uint128 public rewardPool; // how many tokens are allocated for rewards
    uint128 public validatorCoolDown; // how many blocks until validator unstaking is unlocked
    uint128 public delegatorCoolDown; // how many blocks until delegator unstaking is unlocked
    uint128 public recoverUnstakingCoolDown; //how many blocks until delegator recoverUnstaking or redelegateUnstaked is unlocked
    uint128 public maxCapMultiplier; // *see readme
    uint128 public validatorMaxStake; // how many tokens validators can stake at most
    address public stakingManager;
    uint128 public validatorsN; // number of validators, used to get validator ids
    mapping(uint128 => Validator) internal _validators; // id -> validator instance

    uint128 public validatorEnableMinStake; // minimum number of self-staked tokens for a validator to become / stay enabled
    uint128 public delegatorMinStake; // stake/unstake operations are invalid if they put you below this threshold (except unstaking to 0)

    bool private _unpaused;

    struct Staking {
        uint128 shares; // # of validator shares that the delegator owns
        uint128 staked; // # of CQT that a delegator delegated originally through stake() transaction
    }

    struct Unstaking {
        uint128 outCoolDownEnd; // epoch when unstaking can be redeemed (taken out)
        uint128 recoverCoolDownEnd; // epoch when unstaking can be recovered (to the same validator) or redelegated
        uint128 amount; // # of unstaked CQT
    }

    struct Validator {
        uint128 commissionAvailableToRedeem;
        uint128 exchangeRate; // validator exchange rate
        address _address; // wallet address of the operator which is mapped to the validator instance
        uint128 delegated; // track amount of tokens delegated
        uint128 totalShares; // total number of validator shares
        uint128 commissionRate;
        uint256 disabledAtBlock;
        mapping(address => Staking) stakings;
        mapping(address => Unstaking[]) unstakings;
        bool frozen;
    }

    event InitializedSemantics(
        address cqt,
        uint128 validatorCoolDown,
        uint128 delegatorCoolDown,
        uint128 recoverUnstakingCoolDown,
        uint128 maxCapMultiplier,
        uint128 validatorMaxStake,
        uint128 validatorEnableMinStake,
        uint128 delegatorMinStake
    );

    event RewardTokensDeposited(uint128 amount);

    event ValidatorAdded(uint128 indexed id, uint128 commissionRate, address indexed validator);

    event Staked(uint128 indexed validatorId, address delegator, uint128 amount);

    event Unstaked(uint128 indexed validatorId, address indexed delegator, uint128 amount, uint128 unstakeId);

    event RecoveredUnstake(uint128 indexed validatorId, address indexed delegator, uint128 amount, uint128 unstakingId);

    event UnstakeRedeemed(uint128 indexed validatorId, address indexed delegator, uint128 indexed unstakeId, uint128 amount);

    event AllocatedTokensTaken(uint128 amount);

    event RewardFailedDueZeroStake(uint128 indexed validatorId, uint128 amount);

    event RewardFailedDueValidatorDisabled(uint128 indexed validatorId, uint128 amount);

    event RewardFailedDueValidatorFrozen(uint128 indexed validatorId, uint128 amount);

    event RewardRedeemed(uint128 indexed validatorId, address indexed beneficiary, uint128 amount);

    event CommissionRewardRedeemed(uint128 indexed validatorId, address indexed beneficiary, uint128 amount);

    event StakingManagerChanged(address indexed operationalManager);

    event ValidatorCommissionRateChanged(uint128 indexed validatorId, uint128 amount);

    event ValidatorMaxCapChanged(uint128 amount);

    event ValidatorEnableMinStakeChanged(uint128 amount);

    event DelegatorMinStakeChanged(uint128 amount);

    event ValidatorUnstakeCooldownChanged(uint128 amount);

    event DelegatorUnstakeCooldownChanged(uint128 amount);

    event RecoverUnstakeCooldownChanged(uint128 amount);

    event ValidatorDisabled(uint128 indexed validatorId, uint256 blockNumber);

    event Redelegated(uint128 indexed oldValidatorId, uint128 indexed newValidatorId, address indexed delegator, uint128 amount, uint128 unstakingId);

    event MaxCapMultiplierChanged(uint128 newMaxCapMultiplier);

    event ValidatorEnabled(uint128 indexed validatorId);

    event ValidatorAddressChanged(uint128 indexed validatorId, address indexed newAddress);

    event Paused(address account);

    event Unpaused(address account);

    event ValidatorFrozen(uint128 indexed validatorId, string reason);

    event ValidatorUnfrozen(uint128 indexed validatorId);

    event RewardsDisbursed(uint128 indexed rewardId);

    modifier onlyStakingManager() {
        require(stakingManager == msg.sender, "Caller is not stakingManager");
        _;
    }

    modifier onlyStakingManagerOrOwner() {
        require(msg.sender == stakingManager || msg.sender == owner(), "Caller is not stakingManager or owner");
        _;
    }

    modifier whenNotPaused() {
        require(_unpaused, "paused");
        _;
    }

    function initialize(address cqt, uint128 dCoolDown, uint128 vCoolDown, uint128 rCoolDown, uint128 maxCapM, uint128 vMaxStake) external initializer {
        require(cqt != address(0), "Invalid cqt address");
        __Ownable_init();
        validatorCoolDown = vCoolDown; // 180*6857 = ~ 6 months
        delegatorCoolDown = dCoolDown; //  28*6857 = ~ 28 days
        recoverUnstakingCoolDown = rCoolDown; // 3*6857 = ~ 3 days
        maxCapMultiplier = maxCapM;
        validatorMaxStake = vMaxStake;
        require(validatorMaxStake >= DEFAULT_VALIDATOR_ENABLE_MIN_STAKE);

        validatorEnableMinStake = DEFAULT_VALIDATOR_ENABLE_MIN_STAKE;
        delegatorMinStake = DEFAULT_DELEGATOR_MIN_STAKE;

        _unpaused = true;

        CQT = IERC20Upgradeable(cqt);
        emit InitializedSemantics(cqt, vCoolDown, dCoolDown, rCoolDown, maxCapM, vMaxStake, validatorEnableMinStake, delegatorMinStake);
    }

    function setStakingManagerAddress(address newAddress) external onlyOwner {
        require(newAddress != address(0), "Invalid address");
        stakingManager = newAddress;
        emit StakingManagerChanged(newAddress);
    }

    /*
     * Transfer CQT from the owner to the contract for reward allocation
     */
    function depositRewardTokens(uint128 amount) external onlyOwner {
        require(amount > 0, "Amount is 0");
        rewardPool += amount;
        _transferToContract(msg.sender, amount);
        emit RewardTokensDeposited(amount);
    }

    /*
     * Transfer reward CQT from the contract to the owner
     */
    function takeOutRewardTokens(uint128 amount) external onlyOwner {
        require(amount > 0, "Amount is 0");
        require(amount <= rewardPool, "Reward pool is too small");
        rewardPool -= amount;
        emit AllocatedTokensTaken(amount);
        _transferFromContract(msg.sender, amount);
    }

    /*
     * Updates validator max cap multiplier that determines how many tokens can be delegated
     */
    function setMaxCapMultiplier(uint128 newMaxCapMultiplier) external onlyOwner {
        require(newMaxCapMultiplier > 0, "Must be greater than 0");
        maxCapMultiplier = newMaxCapMultiplier;
        emit MaxCapMultiplierChanged(newMaxCapMultiplier);
    }

    /*
     * Updates maximum number of tokens that a validator can stake
     */
    function setValidatorMaxStake(uint128 maxStake) external onlyOwner {
        require(maxStake > 0, "Provided max stake is 0");
        require(maxStake >= validatorEnableMinStake, "maxStake should be greater than validatorEnableMinStake");
        validatorMaxStake = maxStake;
        emit ValidatorMaxCapChanged(maxStake);
    }

    /*
     * Updates minimum number of tokens that a validator must self-stake before enabling
     */
    function setValidatorEnableMinStake(uint128 minStake) public onlyOwner {
        require(minStake <= validatorMaxStake, "minStake cannot be greater than validatorMaxStake");
        validatorEnableMinStake = minStake;
        emit ValidatorEnableMinStakeChanged(minStake);
    }

    /*
     * Updates minimum valid position threshold for per-delegator stake
     */
    function setDelegatorMinStake(uint128 minStake) public onlyOwner {
        require(minStake <= validatorMaxStake, "minStake cannot be greater than validatorMaxStake");
        delegatorMinStake = minStake;
        emit DelegatorMinStakeChanged(minStake);
    }

    /*
     * Updates the validator cool down period (in blocks)
     * Note: this doesn't effect the existing unstakes
     */
    function setValidatorCoolDown(uint128 coolDown) external onlyOwner {
        validatorCoolDown = coolDown;
        emit ValidatorUnstakeCooldownChanged(coolDown);
    }

    /*
     * Updates the delegator cool down period (in blocks)
     * Note: this doesn't effect the existing unstakes
     */
    function setDelegatorCoolDown(uint128 coolDown) external onlyOwner {
        delegatorCoolDown = coolDown;
        emit DelegatorUnstakeCooldownChanged(coolDown);
    }

    /*
     * Updates the delegator recover Unstaking cool down period (in blocks)
     * Note: this doesn't effect the existing unstakes
     */
    function setRecoverUnstakingCoolDown(uint128 coolDown) external onlyOwner {
        recoverUnstakingCoolDown = coolDown;
        emit RecoverUnstakeCooldownChanged(coolDown);
    }

    /*
     * Adds new validator instance
     */
    function addValidator(address validator, uint128 commissionRate) external onlyOwner whenNotPaused returns (uint256 id) {
        require(commissionRate < DIVIDER, "Rate must be less than 100%");
        require(validator != address(0), "Validator address is 0");
        require(validatorsN < 256, "Too many validators");
        Validator storage v = _validators[validatorsN]; // use current number of validators for the id of a new validator instance
        v._address = validator;
        v.exchangeRate = uint128(DIVIDER); // make it 1:1 initially
        v.commissionRate = commissionRate;
        v.disabledAtBlock = 1; // set it to 1 to indicate that the validator is disabled

        emit ValidatorAdded(validatorsN, commissionRate, validator);
        validatorsN += 1;

        return validatorsN - 1;
    }

    /*
     * Reward emission
     */
    function rewardValidators(uint128 rewardId, uint128[] calldata ids, uint128[] calldata amounts) external onlyStakingManager whenNotPaused {
        require(ids.length == amounts.length, "Given ids and amounts arrays must be of the same length");
        uint128 newRewardPool = rewardPool;
        uint128 amount;
        uint128 validatorId;
        uint128 commissionPaid;

        for (uint256 j = 0; j < ids.length; j++) {
            amount = amounts[j];
            validatorId = ids[j];
            // ensure each validator exists
            require(validatorId < validatorsN, "Invalid validatorId");

            // make sure there are enough tokens in the reward pool
            require(newRewardPool >= amount, "Reward pool is too small");

            Validator storage v = _validators[validatorId];

            if (v.frozen) {
                emit RewardFailedDueValidatorFrozen(validatorId, amount);
                continue;
            }

            if (v.disabledAtBlock != 0) {
                // validator became disabled (due to e.g. unstaking past base stake)
                // between proof submission and finalization
                emit RewardFailedDueValidatorDisabled(validatorId, amount);
                continue;
            }

            if (v.totalShares == 0) {
                // mathematically undefined -- no exchangeRate can turn zero into nonzero
                // (this condition is only possible in testing with minValidatorEnableStake == 0;
                //  in prod, validators with zero stake will always be disabled and so will trigger
                //  the above check, not this one)
                emit RewardFailedDueZeroStake(validatorId, amount);
                continue;
            }

            commissionPaid = uint128((uint256(amount) * uint256(v.commissionRate)) / DIVIDER);

            // distribute the tokens by increasing the exchange rate
            // div by zero impossible due to check above
            // (and in fact, presuming minValidatorEnableStake >= DIVIDER, v.totalShares will
            //  always be >= DIVIDER while validator is enabled)
            v.exchangeRate += uint128((uint256(amount - commissionPaid) * uint256(DIVIDER)) / v.totalShares);

            // commission is not compounded
            // commisison is distributed under the validator instance
            v.commissionAvailableToRedeem += commissionPaid;

            newRewardPool -= amount;
        }

        rewardPool = newRewardPool; // can never access these tokens anymore, reserved for validator rewards
        emit RewardsDisbursed(rewardId);
    }

    /*
     * Disables validator instance starting from the given block
     */
    function disableValidator(uint128 validatorId) external onlyStakingManagerOrOwner {
        require(validatorId < validatorsN, "Invalid validator");
        Validator storage v = _validators[validatorId];

        if (v.disabledAtBlock != 0) {
            // silently succeed
            return;
        }

        v.disabledAtBlock = block.number;
        emit ValidatorDisabled(validatorId, block.number);
    }

    /*
     * Enables validator instance by setting the disabledAtBlock to 0
     */
    function enableValidator(uint128 validatorId) external onlyStakingManagerOrOwner {
        require(validatorId < validatorsN, "Invalid validator");
        Validator storage v = _validators[validatorId];

        if (v.disabledAtBlock == 0) {
            // silently succeed
            return;
        }

        uint128 staked = _sharesToTokens(v.stakings[v._address].shares, v.exchangeRate);
        require(staked >= validatorEnableMinStake, "Validator is insufficiently staked");

        v.disabledAtBlock = 0;
        emit ValidatorEnabled(validatorId);
    }

    /*
     * Determines whether a validator is currently able to be used by operators
     */
    function isValidatorEnabled(uint128 validatorId) external view returns (bool) {
        require(validatorId < validatorsN, "Invalid validator");
        return _validators[validatorId].disabledAtBlock == 0;
    }

    /*
     * Updates validator comission rate
     * Commission rate is a number between 0 and 10^18 (0%-100%)
     */
    function setValidatorCommissionRate(uint128 validatorId, uint128 amount) external onlyOwner {
        require(validatorId < validatorsN, "Invalid validator");
        require(amount < DIVIDER, "Rate must be less than 100%");
        _validators[validatorId].commissionRate = amount;
        emit ValidatorCommissionRateChanged(validatorId, amount);
    }

    /*
     * Used to transfer CQT from delegators, validators, and the owner to the contract
     */
    function _transferToContract(address from, uint128 amount) internal {
        CQT.safeTransferFrom(from, address(this), amount);
    }

    /*
     * Used to transfer CQT from contract, for reward redemption or transferring out unstaked tokens
     */
    function _transferFromContract(address to, uint128 amount) internal {
        CQT.safeTransfer(to, amount);
    }

    /*
     * Used to convert validator shares to CQT
     */
    function _sharesToTokens(uint128 sharesN, uint128 rate) internal pure returns (uint128) {
        return uint128((uint256(sharesN) * uint256(rate)) / DIVIDER);
    }

    /*
     * Used to convert CQT to validator shares
     */
    function _tokensToShares(uint128 amount, uint128 rate) internal pure returns (uint128) {
        return uint128((uint256(amount) * DIVIDER) / uint256(rate)); // Rounding down from uint256 to uint128 leading to loss of precision for which checks are implemented in _redeemRewards and _unstake
    }

    /*
     * Delegates tokens under the provided validator
     */
    function stake(uint128 validatorId, uint128 amount) external whenNotPaused {
        _stake(validatorId, amount, true);
    }

    /*
     * withTransfer is set to false when delegators recover unstaked or redelegated tokens.
     * These tokens are already in the contract.
     */
    function _stake(uint128 validatorId, uint128 amount, bool withTransfer) internal {
        require(validatorId < validatorsN, "Invalid validator");
        require(amount >= DEFAULT_DELEGATOR_MIN_STAKE, "Stake amount is too small");
        Validator storage v = _validators[validatorId];
        bool isValidator = msg.sender == v._address;

        require(!v.frozen, "Validator is frozen");

        // validators should be able to stake if they are disabled.
        if (!isValidator) require(v.disabledAtBlock == 0, "Validator is disabled");

        Staking storage s = v.stakings[msg.sender];

        uint128 newStaked = s.staked + amount;

        require(newStaked >= delegatorMinStake, "Cannot stake to a position less than delegatorMinStake");

        uint128 sharesAdd = _tokensToShares(amount, v.exchangeRate);

        if (isValidator) {
            // compares with newStaked to ignore compounded rewards
            require(newStaked <= validatorMaxStake, "Validator max stake exceeded");
        } else {
            // cannot stake more than validator delegation max cap
            uint128 delegationMaxCap = v.stakings[v._address].staked * maxCapMultiplier;
            uint128 newDelegated = v.delegated + amount;
            require(newDelegated <= delegationMaxCap, "Validator max delegation exceeded");
            v.delegated = newDelegated;
        }

        // "buy/mint" shares
        v.totalShares += sharesAdd;
        s.shares += sharesAdd;

        // keep track of staked tokens
        s.staked = newStaked;
        if (withTransfer) _transferToContract(msg.sender, amount);
        emit Staked(validatorId, msg.sender, amount);
    }

    /*
     * Undelegates all staked tokens from the provided validator
     */
    function unstakeAll(uint128 validatorId) external whenNotPaused {
        _unstake(validatorId, 0); // pass 0 to request full amount
    }

    /*
     * Undelegates some number of tokens from the provided validator
     */
    function unstake(uint128 validatorId, uint128 amount) external whenNotPaused {
        require(amount > 0, "Amount is 0");
        _unstake(validatorId, amount);
    }

    /*
     * Undelegates tokens from the provided validator
     */
    function _unstake(uint128 validatorId, uint128 amount) internal {
        require(validatorId < validatorsN, "Invalid validator");

        Validator storage v = _validators[validatorId];
        Staking storage s = v.stakings[msg.sender];
        if (msg.sender == v._address) {
            require(!v.frozen, "Validator is frozen");
        }

        require(amount <= s.staked, "Cannot unstake amount greater than current stake");

        bool isUnstakingAll = amount == 0 || amount == s.staked;
        uint128 effectiveAmount = isUnstakingAll ? s.staked : amount;
        uint128 newStaked = s.staked - effectiveAmount;

        if (isUnstakingAll) {
            // enforce precondition for later math that effectiveAmount is always nonzero
            require(effectiveAmount > 0, "Already fully unstaked");
        } else {
            // to prevent buildup of Unstaking[] elements, do not allow user to repeatedly unstake trivial amounts
            // (but do allow removal of a trivial amount if it is the entire remaining stake)
            require(effectiveAmount >= REWARD_REDEEM_THRESHOLD, "Unstake amount is too small");

            // to prevent "spam" delegations, and runaway exchangeRate inflation from all-but-dust self-stake unstaking,
            // disallow unstaking that would result in a new stake below delegatorMinStake
            // (with the exception of an unstaking that takes the stake exactly to zero)
            require(newStaked >= delegatorMinStake, "Cannot unstake to a position below delegatorMinStake (except to zero)");
        }

        bool isValidator = msg.sender == v._address;

        // disable validator if they unstaked to below their required self-stake
        if (isValidator && validatorEnableMinStake > 0 && v.disabledAtBlock == 0 && newStaked < validatorEnableMinStake) {
            uint256 disabledAtBlock = block.number;
            v.disabledAtBlock = disabledAtBlock;
            emit ValidatorDisabled(validatorId, disabledAtBlock);
        }

        if (isValidator && v.disabledAtBlock == 0) {
            // validators will have to disable themselves if they want to unstake tokens below delegation max cap
            uint128 newValidatorMaxCap = newStaked * maxCapMultiplier;
            require(v.delegated <= newValidatorMaxCap, "Cannot decrease delegation max-cap below current delegation while validator is enabled");
        }
        if (!isValidator) {
            v.delegated -= effectiveAmount;
        }

        uint128 sharesToRemove = _tokensToShares(effectiveAmount, v.exchangeRate);

        // sometimes, due to conversion inconsistencies, sharesToRemove might end up larger than s.shares;
        // so we clamp sharesToRemove to s.shares (the redeemer unstakes trivially more tokens in this case)
        if (sharesToRemove > s.shares) sharesToRemove = s.shares;

        // sanity check: sharesToRemove should never be zero while amount is nonzero, as this would enable
        // infinite draining of funds
        require(sharesToRemove > 0, "Underflow error");

        if (uint256(sharesToRemove) * uint256(v.exchangeRate) < uint256(effectiveAmount) * uint256(DIVIDER)) {
            effectiveAmount = uint128((uint256(sharesToRemove) * uint256(v.exchangeRate)) / uint256(DIVIDER));
        }
        s.shares -= sharesToRemove;
        v.totalShares -= sharesToRemove;
        // remove staked tokens
        s.staked = newStaked;

        // create unstaking instance
        uint128 outCoolDownEnd = uint128(v.disabledAtBlock != 0 ? v.disabledAtBlock : block.number);
        uint128 recoverCoolDownEnd = outCoolDownEnd + recoverUnstakingCoolDown;
        outCoolDownEnd += (isValidator ? validatorCoolDown : delegatorCoolDown);
        uint128 unstakeId = uint128(v.unstakings[msg.sender].length);
        v.unstakings[msg.sender].push(Unstaking(outCoolDownEnd, recoverCoolDownEnd, effectiveAmount));
        emit Unstaked(validatorId, msg.sender, effectiveAmount, unstakeId);
    }

    /*
     * Restakes unstaked tokens (with the same validator)
     */
    function recoverUnstaking(uint128 amount, uint128 validatorId, uint128 unstakingId) external whenNotPaused {
        Validator storage v = _validators[validatorId];
        require(amount > 0, "Amount is 0");
        require(validatorId < validatorsN, "Invalid validator");
        require(!v.frozen, "Validator is frozen");
        require(_validators[validatorId].unstakings[msg.sender].length > unstakingId, "Unstaking does not exist");
        Unstaking storage us = _validators[validatorId].unstakings[msg.sender][unstakingId];
        require(us.amount >= amount, "Unstaking has less tokens");
        require(block.number > us.recoverCoolDownEnd, "recover cooldown not over");

        us.amount -= amount;
        // set cool down end to 0 to release gas if new unstaking amount is 0
        if (us.amount == 0) {
            us.recoverCoolDownEnd = 0;
            us.outCoolDownEnd = 0;
        }
        emit RecoveredUnstake(validatorId, msg.sender, amount, unstakingId);
        _stake(validatorId, amount, false);
    }

    /*
     * Transfers out unlocked unstaked tokens back to the delegator
     */
    function transferUnstakedOut(uint128 amount, uint128 validatorId, uint128 unstakingId) external whenNotPaused {
        Validator storage v = _validators[validatorId];
        require(amount > 0, "Amount is 0");
        require(validatorId < validatorsN, "Invalid validator");
        require(!v.frozen, "Validator is frozen");
        require(_validators[validatorId].unstakings[msg.sender].length > unstakingId, "Unstaking does not exist");
        Unstaking storage us = _validators[validatorId].unstakings[msg.sender][unstakingId];
        require(block.number > us.outCoolDownEnd, "Cooldown period has not ended");
        require(us.amount >= amount, "Amount is too high");
        us.amount -= amount;
        // set cool down end to 0 to release gas if new unstaking amount is 0
        if (us.amount == 0) {
            us.recoverCoolDownEnd = 0;
            us.outCoolDownEnd = 0;
        }
        emit UnstakeRedeemed(validatorId, msg.sender, unstakingId, amount);
        _transferFromContract(msg.sender, amount);
    }

    /*
     * Redeems all available rewards
     */
    function redeemAllRewards(uint128 validatorId, address beneficiary) external whenNotPaused {
        _redeemRewards(validatorId, beneficiary, 0); // pass 0 to request full amount
    }

    /*
     * Redeems partial rewards
     */
    function redeemRewards(uint128 validatorId, address beneficiary, uint128 amount) external whenNotPaused {
        require(amount > 0, "Amount is 0");
        _redeemRewards(validatorId, beneficiary, amount);
    }

    function _redeemRewards(uint128 validatorId, address beneficiary, uint128 amount) internal {
        require(validatorId < validatorsN, "Invalid validator");
        require(beneficiary != address(0x0), "Invalid beneficiary");
        Validator storage v = _validators[validatorId];
        Staking storage s = v.stakings[msg.sender];

        require(!v.frozen, "Validator is frozen");

        // how many tokens a delegator/validator has in total on the contract
        // include earned commission if the delegator is the validator
        uint128 totalValue = _sharesToTokens(s.shares, v.exchangeRate);

        // how many tokens a delegator/validator has "unlocked", free to be redeemed
        // (i.e. not staked or in unstaking cooldown)
        uint128 totalUnlockedValue = (totalValue < s.staked) ? 0 : (totalValue - s.staked);

        bool isRedeemingAll = (amount == 0 || amount == totalUnlockedValue); // amount is 0 when it's requested to redeem all rewards

        // make sure rewards exist
        // (note that this still works in the case where we're redeeming all! always doing this check saves a branch op)
        require(amount <= totalUnlockedValue, "Cannot redeem amount greater than held, unstaked rewards");

        uint128 effectiveAmount = isRedeemingAll ? totalUnlockedValue : amount;

        // can only redeem above redeem threshold
        require(effectiveAmount >= REWARD_REDEEM_THRESHOLD, "Requested amount must be higher than redeem threshold");
        // make sure rewardPool has funds to cover effective amount before transfer
        require(rewardPool >= effectiveAmount, "Requested amount is not available in the staking contract reward pool");

        uint128 sharesToBurn = _tokensToShares(effectiveAmount, v.exchangeRate);

        // sometimes, due to conversion inconsistencies, sharesToBurn might end up larger than s.shares;
        // so we clamp sharesToBurn to s.shares (the redeemer gets trivially more value out in this case)
        if (sharesToBurn > s.shares) sharesToBurn = s.shares;

        // sanity check: sharesToBurn should never be zero while effectiveAmount is nonzero, as this
        // would enable infinite draining of funds
        require(sharesToBurn > 0, "Underflow error");
        if (uint256(sharesToBurn) * uint256(v.exchangeRate) < uint256(effectiveAmount) * uint256(DIVIDER)) {
            effectiveAmount = uint128((uint256(sharesToBurn) * uint256(v.exchangeRate)) / uint256(DIVIDER));
        }
        v.totalShares -= sharesToBurn;
        s.shares -= sharesToBurn;

        emit RewardRedeemed(validatorId, beneficiary, effectiveAmount);
        _transferFromContract(beneficiary, effectiveAmount);
    }

    function redeemCommission(uint128 validatorId, address beneficiary, uint128 amount) public whenNotPaused {
        require(validatorId < validatorsN, "Invalid validator");
        require(beneficiary != address(0x0), "Invalid beneficiary");
        Validator storage v = _validators[validatorId];
        require(v._address == msg.sender, "The sender is not the validator");

        require(!v.frozen, "Validator is frozen");

        require(v.commissionAvailableToRedeem > 0, "No commission available to redeem");
        require(amount > 0, "The requested amount is 0");
        require(amount <= v.commissionAvailableToRedeem, "Requested amount is higher than commission available to redeem");
        // make sure rewardPool has funds to cover effective amount before transfer
        require(rewardPool >= amount, "Requested amount is not available in the staking contract reward pool");
        v.commissionAvailableToRedeem -= amount;

        _transferFromContract(beneficiary, amount);
        emit CommissionRewardRedeemed(validatorId, beneficiary, amount);
    }

    function redeemAllCommission(uint128 validatorId, address beneficiary) external whenNotPaused {
        redeemCommission(validatorId, beneficiary, _validators[validatorId].commissionAvailableToRedeem);
    }

    /*
     * Redelegates tokens to another validator if a validator got disabled.
     * First the tokens need to be unstaked
     */
    function redelegateUnstaked(uint128 amount, uint128 oldValidatorId, uint128 newValidatorId, uint128 unstakingId) external whenNotPaused {
        require(oldValidatorId < validatorsN, "Invalid validator");
        require(oldValidatorId != newValidatorId, "Old and new validators are the same");
        require(amount > 0, "Amount is 0");
        Validator storage vOld = _validators[oldValidatorId];
        Validator storage vNew = _validators[newValidatorId];
        // new staking should not be from same an address to same (new) validator to bypass cooldown
        require(vNew._address != msg.sender, "New Validator cannot be same as sender");
        // assets of delegators cannot be moved to a frozen validator
        require(!vNew.frozen, "Target validator is frozen");
        // assets of delegators cannot be moved to a disabled validator
        require(vNew.disabledAtBlock == 0, "Target validator is disabled");
        // assets of delegators cannot be moved while validator is frozen
        require(!vOld.frozen, "Validator is frozen");
        require(vOld.disabledAtBlock != 0, "Validator is not disabled");
        require(vOld._address != msg.sender, "Validator cannot redelegate");
        require(vOld.unstakings[msg.sender].length > unstakingId, "Unstaking does not exist");
        Unstaking storage us = vOld.unstakings[msg.sender][unstakingId];
        require(us.amount >= amount, "Unstaking has less tokens");
        require(block.number > us.recoverCoolDownEnd, "recover cooldown not over");

        // stake tokens back to the contract using new validator, set withTransfer to false since the tokens are already in the contract
        us.amount -= amount;

        // set cool down end to 0 to release gas if new unstaking amount is 0
        if (us.amount == 0) {
            us.recoverCoolDownEnd = 0;
            us.outCoolDownEnd = 0;
        }
        emit Redelegated(oldValidatorId, newValidatorId, msg.sender, amount, unstakingId);
        _stake(newValidatorId, amount, false);
    }

    /*
     * Changes the validator staking address, this will transfer validator staking data and optionally unstakings
     */
    function setValidatorAddress(uint128 validatorId, address newAddress) external whenNotPaused {
        Validator storage v = _validators[validatorId];
        // Check if the sender is the validator
        require(msg.sender == v._address, "Sender is not the validator");
        // Check if the new address is different from the current address
        require(newAddress != v._address, "The new address cannot be equal to the current validator address");
        require(newAddress != address(0), "Invalid validator address");
        // Check if the validatorId exists and is not frozen
        require(!v.frozen, "Validator is already frozen");

        // Check if the newAddress is already present as validator or delegator in the system
        require(!checkDelegatorExists(newAddress), "newAddress must not already exist in the system");

        // Transfer shares and staked amount from sender to the new address
        v.stakings[newAddress].shares += v.stakings[msg.sender].shares;
        v.stakings[newAddress].staked += v.stakings[msg.sender].staked;
        // New addresses total stake shold not exceed validatorMaxStake
        require(v.stakings[newAddress].staked <= validatorMaxStake, "Validator max stake exceeded");
        // Remove stakings of the sender
        delete v.stakings[msg.sender];
        // Transfer unstakings from sender to new address
        Unstaking[] storage oldUnstakings = v.unstakings[msg.sender];
        uint256 length = oldUnstakings.length;
        require(length <= 300, "Cannot transfer more than 300 unstakings");
        Unstaking[] storage newUnstakings = v.unstakings[newAddress];
        for (uint128 i = 0; i < length; ++i) {
            newUnstakings.push(oldUnstakings[i]);
        }
        // Remove unstakings of the sender
        delete v.unstakings[msg.sender];

        // Update validator address
        v._address = newAddress;
        emit ValidatorAddressChanged(validatorId, newAddress);
    }

    /*
     * Gets metadata
     */
    function getMetadata()
        external
        view
        returns (
            address CQTaddress,
            address _stakingManager,
            uint128 _validatorsN,
            uint128 _rewardPool,
            uint128 _validatorCoolDown,
            uint128 _delegatorCoolDown,
            uint128 _recoverUnstakingCoolDown,
            uint128 _maxCapMultiplier,
            uint128 _validatorMaxStake,
            uint128 _validatorEnableMinStake,
            uint128 _delegatorMinStake
        )
    {
        return (
            address(CQT),
            stakingManager,
            validatorsN,
            rewardPool,
            validatorCoolDown,
            delegatorCoolDown,
            recoverUnstakingCoolDown,
            maxCapMultiplier,
            validatorMaxStake,
            validatorEnableMinStake,
            delegatorMinStake
        );
    }

    /*
     * Returns validator metadata with how many tokens were staked and delegated excluding compounded rewards
     */
    function getValidatorMetadata(uint128 validatorId) public view returns (address _address, uint128 staked, uint128 delegated, uint128 commissionRate, uint256 disabledAtBlock) {
        require(validatorId < validatorsN, "Invalid validator");
        Validator storage v = _validators[validatorId];
        return (v._address, v.stakings[v._address].staked, v.delegated, v.commissionRate, v.disabledAtBlock);
    }

    /*
     * Returns metadata for each validator
     */
    function getAllValidatorsMetadata()
        external
        view
        returns (address[] memory addresses, uint128[] memory staked, uint128[] memory delegated, uint128[] memory commissionRates, uint256[] memory disabledAtBlocks)
    {
        return getValidatorsMetadata(0, validatorsN);
    }

    /*
     * Returns metadata for validators whose ids are between startId and endId exclusively
     */
    function getValidatorsMetadata(
        uint128 startId,
        uint128 endId
    ) public view returns (address[] memory addresses, uint128[] memory staked, uint128[] memory delegated, uint128[] memory commissionRates, uint256[] memory disabledAtBlocks) {
        require(endId <= validatorsN, "Invalid end id");
        require(startId < endId, "Start id must be less than end id");

        uint128 n = endId - startId;
        addresses = new address[](n);
        staked = new uint128[](n);
        delegated = new uint128[](n);
        commissionRates = new uint128[](n);
        disabledAtBlocks = new uint256[](n);

        uint128 i;
        for (uint128 id = startId; id < endId; ++id) {
            i = id - startId;
            (addresses[i], staked[i], delegated[i], commissionRates[i], disabledAtBlocks[i]) = getValidatorMetadata(id);
        }
        return (addresses, staked, delegated, commissionRates, disabledAtBlocks);
    }

    /*
     * Returns validator staked and delegated token amounts, excluding compounded rewards
     */
    function getValidatorStakingData(uint128 validatorId) external view returns (uint128 staked, uint128 delegated) {
        require(validatorId < validatorsN, "Invalid validator");
        Validator storage v = _validators[validatorId];
        return (v.stakings[v._address].staked, v.delegated);
    }

    /*
     * Returns validator staked and delegated token amounts, including compounded rewards
     */
    function getValidatorsCompoundedStakes() external view returns (uint128[] memory validatorIds, bool[] memory isEnableds, uint128[] memory cstaked) {
        validatorIds = new uint128[](validatorsN);
        isEnableds = new bool[](validatorsN);
        cstaked = new uint128[](validatorsN);
        for (uint128 i = 0; i < validatorsN; i++) {
            Validator storage v = _validators[i];
            validatorIds[i] = i;
            isEnableds[i] = v.disabledAtBlock == 0;
            cstaked[i] = _sharesToTokens(v.stakings[v._address].shares, v.exchangeRate);
        }

        return (validatorIds, isEnableds, cstaked);
    }

    /*
     * Returns validator staked and delegated token amounts, including compounded rewards
     */
    function getValidatorCompoundedStakingData(uint128 validatorId) external view returns (uint128 staked, uint128 delegated) {
        require(validatorId < validatorsN, "Invalid validator");
        Validator storage v = _validators[validatorId];
        // this includes staked + compounded rewards
        staked = _sharesToTokens(v.stakings[v._address].shares, v.exchangeRate);
        // this includes delegated + compounded rewards
        delegated = _sharesToTokens(v.totalShares, v.exchangeRate) - staked;
        return (staked, delegated);
    }

    /*
     * Returns the amount that's staked, earned by delegator plus unstaking information.
     * CommissionEarned is for validators
     */
    function getDelegatorMetadata(
        address delegator,
        uint128 validatorId
    ) external view returns (uint128 staked, uint128 rewards, uint128 commissionEarned, uint128[] memory unstakingAmounts, uint128[] memory unstakingsEndEpochs) {
        require(validatorId < validatorsN, "Invalid validator");
        Validator storage v = _validators[validatorId];
        Staking storage s = v.stakings[delegator];
        staked = s.staked;
        uint128 sharesValue = _sharesToTokens(s.shares, v.exchangeRate);
        if (sharesValue <= s.staked) rewards = 0;
        else rewards = sharesValue - s.staked;
        // if requested delegator is the requested validator
        if (v._address == delegator) commissionEarned = v.commissionAvailableToRedeem;
        Unstaking[] memory unstakings = v.unstakings[delegator];
        uint256 unstakingsN = unstakings.length;
        unstakingAmounts = new uint128[](unstakingsN);
        unstakingsEndEpochs = new uint128[](unstakingsN);
        for (uint256 i = 0; i < unstakingsN; i++) {
            unstakingAmounts[i] = unstakings[i].amount;
            unstakingsEndEpochs[i] = unstakings[i].outCoolDownEnd;
        }
        return (staked, rewards, commissionEarned, unstakingAmounts, unstakingsEndEpochs);
    }

    // function getDelegatorMetadataPaginated(
    //     address delegator,
    //     uint128 validatorId,
    //     uint128 start,
    //     uint128 end
    // )
    //     external
    //     view
    //     returns (uint128[] memory staked, uint128[] memory rewards, uint128[] memory commissionEarned, uint128[] memory unstakingAmounts, uint128[] memory unstakingsEndEpochs)
    // {
    //     require(validatorId < validatorsN, "Invalid validator");
    //     Validator storage v = _validators[validatorId];
    //     Staking storage s = v.stakings[delegator];
    //     staked = new uint128[](end - start + 1);
    //     rewards = new uint128[](end - start + 1);
    //     commissionEarned = new uint128[](end - start + 1);
    //     unstakingAmounts = new uint128[](end - start + 1);
    //     unstakingsEndEpochs = new uint128[](end - start + 1);

    //     for (uint256 i = start; i <= end; i++) {
    //         Unstaking memory u = v.unstakings[delegator][i];
    //         staked[i - start] = s.shares[u.shareIndex];
    //         if (s.shares[u.shareIndex] <= _sharesToTokens(s.shares[u.shareIndex], v.exchangeRate)) {
    //             rewards[i - start] = 0;
    //         } else {
    //             rewards[i - start] = _sharesToTokens(s.shares[u.shareIndex], v.exchangeRate) - s.shares[u.shareIndex];
    //         }
    //         if (v._address == delegator) {
    //             commissionEarned[i - start] = v.commissionAvailableToRedeem;
    //         } else {
    //             commissionEarned[i - start] = 0;
    //         }
    //         unstakingAmounts[i - start] = u.amount;
    //         unstakingsEndEpochs[i - start] = u.coolDownEnd;
    //     }

    //     return (staked, rewards, commissionEarned, unstakingAmounts, unstakingsEndEpochs);
    // }

    /*
     * Returns the total amount including compounded stake and unstaked tokens
     * CommissionEarned is also included (if delegator is a validator)
     */
    function getDelegatorTotalLocked(address delegator) external view returns (uint128 totalValueLocked) {
        for (uint128 i = 0; i < validatorsN; i++) {
            Validator storage v = _validators[i];
            Staking storage s = v.stakings[delegator];
            totalValueLocked += _sharesToTokens(s.shares, v.exchangeRate);
            if (v._address == delegator) totalValueLocked += v.commissionAvailableToRedeem;
            Unstaking[] memory unstakings = v.unstakings[delegator];
            uint256 unstakingsN = unstakings.length;
            for (uint256 j = 0; j < unstakingsN; j++) {
                totalValueLocked += unstakings[j].amount;
            }
        }

        return totalValueLocked;
    }

    function checkDelegatorExists(address newAddress) public view returns (bool) {
        for (uint128 i = 0; i < validatorsN; i++) {
            Validator storage v = _validators[i];
            if (v._address == newAddress) {
                return true;
            }

            Staking storage s = v.stakings[newAddress];
            if (s.staked > 0 || s.shares > 0) {
                return true;
            }

            if (v.unstakings[newAddress].length > 0) {
                return true;
            }
        }
        return false;
    }

    function pause() external onlyOwner whenNotPaused {
        _unpaused = false;
        emit Paused(_msgSender());
    }

    function unpause() external onlyOwner {
        require(!_unpaused, "must be paused");
        _unpaused = true;
        emit Unpaused(_msgSender());
    }

    function paused() external view returns (bool) {
        return !_unpaused;
    }

    function freezeValidator(uint128 validatorId, string memory reason) public onlyOwner {
        require(validatorId < validatorsN, "Invalid validator");
        Validator storage v = _validators[validatorId];

        require(!v.frozen, "Validator is already frozen");

        v.frozen = true;
        emit ValidatorFrozen(validatorId, reason);
    }

    function unfreezeValidator(uint128 validatorId) external onlyOwner {
        require(validatorId < validatorsN, "Invalid validator");
        Validator storage v = _validators[validatorId];

        require(v.frozen, "Validator not frozen");

        v.frozen = false;
        emit ValidatorUnfrozen(validatorId);
    }
}

File 2 of 8 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../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.
 *
 * By default, the owner account will be the one that deploys the contract. 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 {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @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) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 3 of 8 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @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 Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 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 functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _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 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _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() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @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 {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 4 of 8 : IERC20PermitUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20PermitUpgradeable {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 5 of 8 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 6 of 8 : SafeERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20Upgradeable.sol";
import "../extensions/IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20Upgradeable {
    using AddressUpgradeable for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20PermitUpgradeable token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));
    }
}

File 7 of 8 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 8 of 8 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)

pragma solidity ^0.8.0;
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;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"AllocatedTokensTaken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"CommissionRewardRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"DelegatorMinStakeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"DelegatorUnstakeCooldownChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cqt","type":"address"},{"indexed":false,"internalType":"uint128","name":"validatorCoolDown","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"delegatorCoolDown","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"recoverUnstakingCoolDown","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"maxCapMultiplier","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"validatorMaxStake","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"validatorEnableMinStake","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"delegatorMinStake","type":"uint128"}],"name":"InitializedSemantics","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newMaxCapMultiplier","type":"uint128"}],"name":"MaxCapMultiplierChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"RecoverUnstakeCooldownChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"unstakingId","type":"uint128"}],"name":"RecoveredUnstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"oldValidatorId","type":"uint128"},{"indexed":true,"internalType":"uint128","name":"newValidatorId","type":"uint128"},{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"unstakingId","type":"uint128"}],"name":"Redelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"RewardFailedDueValidatorDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"RewardFailedDueValidatorFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"RewardFailedDueZeroStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"RewardRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"RewardTokensDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"rewardId","type":"uint128"}],"name":"RewardsDisbursed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":false,"internalType":"address","name":"delegator","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operationalManager","type":"address"}],"name":"StakingManagerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint128","name":"unstakeId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"UnstakeRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"unstakeId","type":"uint128"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"id","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"commissionRate","type":"uint128"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"ValidatorAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"ValidatorCommissionRateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"ValidatorDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"ValidatorEnableMinStakeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"ValidatorEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"ValidatorFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"ValidatorMaxCapChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"ValidatorUnfrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"ValidatorUnstakeCooldownChanged","type":"event"},{"inputs":[],"name":"CQT","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_DELEGATOR_MIN_STAKE","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_VALIDATOR_ENABLE_MIN_STAKE","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DIVIDER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_REDEEM_THRESHOLD","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"uint128","name":"commissionRate","type":"uint128"}],"name":"addValidator","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"checkDelegatorExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegatorCoolDown","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegatorMinStake","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"depositRewardTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"disableValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"enableValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"string","name":"reason","type":"string"}],"name":"freezeValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllValidatorsMetadata","outputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"uint128[]","name":"staked","type":"uint128[]"},{"internalType":"uint128[]","name":"delegated","type":"uint128[]"},{"internalType":"uint128[]","name":"commissionRates","type":"uint128[]"},{"internalType":"uint256[]","name":"disabledAtBlocks","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"getDelegatorMetadata","outputs":[{"internalType":"uint128","name":"staked","type":"uint128"},{"internalType":"uint128","name":"rewards","type":"uint128"},{"internalType":"uint128","name":"commissionEarned","type":"uint128"},{"internalType":"uint128[]","name":"unstakingAmounts","type":"uint128[]"},{"internalType":"uint128[]","name":"unstakingsEndEpochs","type":"uint128[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"}],"name":"getDelegatorTotalLocked","outputs":[{"internalType":"uint128","name":"totalValueLocked","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMetadata","outputs":[{"internalType":"address","name":"CQTaddress","type":"address"},{"internalType":"address","name":"_stakingManager","type":"address"},{"internalType":"uint128","name":"_validatorsN","type":"uint128"},{"internalType":"uint128","name":"_rewardPool","type":"uint128"},{"internalType":"uint128","name":"_validatorCoolDown","type":"uint128"},{"internalType":"uint128","name":"_delegatorCoolDown","type":"uint128"},{"internalType":"uint128","name":"_recoverUnstakingCoolDown","type":"uint128"},{"internalType":"uint128","name":"_maxCapMultiplier","type":"uint128"},{"internalType":"uint128","name":"_validatorMaxStake","type":"uint128"},{"internalType":"uint128","name":"_validatorEnableMinStake","type":"uint128"},{"internalType":"uint128","name":"_delegatorMinStake","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"getValidatorCompoundedStakingData","outputs":[{"internalType":"uint128","name":"staked","type":"uint128"},{"internalType":"uint128","name":"delegated","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"getValidatorMetadata","outputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint128","name":"staked","type":"uint128"},{"internalType":"uint128","name":"delegated","type":"uint128"},{"internalType":"uint128","name":"commissionRate","type":"uint128"},{"internalType":"uint256","name":"disabledAtBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"getValidatorStakingData","outputs":[{"internalType":"uint128","name":"staked","type":"uint128"},{"internalType":"uint128","name":"delegated","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getValidatorsCompoundedStakes","outputs":[{"internalType":"uint128[]","name":"validatorIds","type":"uint128[]"},{"internalType":"bool[]","name":"isEnableds","type":"bool[]"},{"internalType":"uint128[]","name":"cstaked","type":"uint128[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"startId","type":"uint128"},{"internalType":"uint128","name":"endId","type":"uint128"}],"name":"getValidatorsMetadata","outputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"uint128[]","name":"staked","type":"uint128[]"},{"internalType":"uint128[]","name":"delegated","type":"uint128[]"},{"internalType":"uint128[]","name":"commissionRates","type":"uint128[]"},{"internalType":"uint256[]","name":"disabledAtBlocks","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cqt","type":"address"},{"internalType":"uint128","name":"dCoolDown","type":"uint128"},{"internalType":"uint128","name":"vCoolDown","type":"uint128"},{"internalType":"uint128","name":"rCoolDown","type":"uint128"},{"internalType":"uint128","name":"maxCapM","type":"uint128"},{"internalType":"uint128","name":"vMaxStake","type":"uint128"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"isValidatorEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxCapMultiplier","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"uint128","name":"unstakingId","type":"uint128"}],"name":"recoverUnstaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverUnstakingCoolDown","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"address","name":"beneficiary","type":"address"}],"name":"redeemAllCommission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"address","name":"beneficiary","type":"address"}],"name":"redeemAllRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"redeemCommission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"redeemRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"oldValidatorId","type":"uint128"},{"internalType":"uint128","name":"newValidatorId","type":"uint128"},{"internalType":"uint128","name":"unstakingId","type":"uint128"}],"name":"redelegateUnstaked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPool","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"rewardId","type":"uint128"},{"internalType":"uint128[]","name":"ids","type":"uint128[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"}],"name":"rewardValidators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"coolDown","type":"uint128"}],"name":"setDelegatorCoolDown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"minStake","type":"uint128"}],"name":"setDelegatorMinStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newMaxCapMultiplier","type":"uint128"}],"name":"setMaxCapMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"coolDown","type":"uint128"}],"name":"setRecoverUnstakingCoolDown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"setStakingManagerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"address","name":"newAddress","type":"address"}],"name":"setValidatorAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"setValidatorCommissionRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"coolDown","type":"uint128"}],"name":"setValidatorCoolDown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"minStake","type":"uint128"}],"name":"setValidatorEnableMinStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"maxStake","type":"uint128"}],"name":"setValidatorMaxStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"takeOutRewardTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"uint128","name":"unstakingId","type":"uint128"}],"name":"transferUnstakedOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"unfreezeValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"unstakeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"validatorCoolDown","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorEnableMinStake","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorMaxStake","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorsN","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102bf5760003560e01c806307fd8763146102c457806309991223146102d95780630b56a2bc146102fa5780630f04adfe1461031357806317c2b0a9146103335780632094423b1461034657806322828cc2146103595780632a019e6f1461036c57806337e15bce1461037f5780633a64440b146103925780633ace57ca146103a55780633b4e76c1146103bf5780633f4ba83a146103d257806340e7e9f0146103da578063429a481b146103ed57806342e45079146104105780634365c74f14610423578063445c81d7146104365780634c4a1709146104495780634e07a90a1461046a5780634e256b021461048157806353b74922146104945780635b216723146104ae5780635c975abb146104d25780635ed24cb7146104de57806362043bd8146104f15780636423bf1b1461050e5780636459db951461051f578063650de76b1461053257806366666aa9146105455780636c6dca5c146105585780636cb4ded31461056b5780637106aa841461057e578063715018a61461059157806378671e53146105995780637a5b4f59146105ac5780638456cb59146106475780638459ec681461064f57806385632db11461066257806387326a0c14610675578063884ef0aa146106c95780638a810324146106dc5780638b877db2146106ef5780638da5cb5b14610702578063905ac82f1461070a5780639099ac101461071d57806391609449146107305780639860fa25146107435780639ea05077146107565780639f10816f14610769578063a2e7e44114610783578063a3e89bac14610796578063abfd6fa9146107a9578063da7a9b6a146107b8578063dfc50f65146107d2578063eabc89d7146107e5578063edff4b61146107f8578063eead9d941461080b578063f1aa0c651461081e578063f2fde38b14610831578063f474c72814610844575b600080fd5b6102d76102d236600461532d565b610857565b005b6102e46305f5e10081565b6040516102f19190615360565b60405180910390f35b610302610892565b6040516102f19594939291906153e8565b606554610326906001600160a01b031681565b6040516102f19190615487565b6102d761034136600461532d565b6108cb565b6102d76103543660046154b2565b6109a0565b606954610326906001600160a01b031681565b6102d761037a366004615526565b610c23565b6102d761038d366004615569565b610c7e565b6102d76103a0366004615584565b610d18565b6067546102e490600160801b90046001600160801b031681565b6102d76103cd3660046155b0565b610fc7565b6102d7611025565b6102d76103e83660046155cb565b6110bd565b6104006103fb3660046155b0565b611534565b60405190151581526020016102f1565b6102d761041e3660046155b0565b611585565b6102d76104313660046155b0565b61165a565b6102d761044436600461561f565b6116ac565b61045c6104573660046155b0565b611b82565b6040516102f1929190615649565b610472611c45565b6040516102f193929190615663565b61040061048f366004615569565b611e60565b6066546102e490600160801b90046001600160801b031681565b6104c16104bc3660046156c3565b611f4f565b6040516102f19594939291906156df565b606d5460ff1615610400565b6102d76104ec3660046155b0565b612236565b610500670de0b6b3a764000081565b6040519081526020016102f1565b6102e46907695a92c20d6fe0000081565b6102d761052d36600461561f565b6122bf565b6068546102e4906001600160801b031681565b6066546102e4906001600160801b031681565b6102d76105663660046155b0565b612309565b6102d76105793660046155b0565b612336565b6102d761058c3660046155b0565b6123db565b6102d76124b8565b6102e46105a7366004615569565b6124cc565b606554606954606a54606654606754606854606c54604080516001600160a01b0398891681529790961660208801526001600160801b03948516958701959095528383166060870152600160801b928390048416608087015283821660a087015290829004831660c086015282811660e0860152819004821661010085015281831661012085015290910416610140820152610160016102f1565b6102d7612677565b6102d761065d36600461561f565b6126d2565b606c546102e4906001600160801b031681565b6106886106833660046155b0565b612700565b604080516001600160a01b0390961686526001600160801b03948516602087015292841692850192909252919091166060830152608082015260a0016102f1565b6102d76106d7366004615584565b61279d565b606a546102e4906001600160801b031681565b6102d76106fd3660046155b0565b6129f1565b610326612ad4565b6102d7610718366004615770565b612ae3565b6102d761072b3660046155b0565b612f47565b6102d761073e36600461532d565b612fcf565b61045c6107513660046155b0565b613024565b6102d76107643660046155b0565b6130a6565b6068546102e490600160801b90046001600160801b031681565b6105006107913660046156c3565b6131ca565b6103026107a436600461532d565b6133da565b6102e4670de0b6b3a764000081565b606c546102e490600160801b90046001600160801b031681565b6067546102e4906001600160801b031681565b6102d76107f3366004615526565b613755565b6102d76108063660046155b0565b613a68565b6102d7610819366004615806565b613bf5565b6102d761082c3660046155b0565b613cbf565b6102d761083f366004615569565b613d6b565b6102d76108523660046155b0565b613de1565b606d5460ff166108825760405162461bcd60e51b8152600401610879906158c7565b60405180910390fd5b61088e82826001613e33565b5050565b60608060608060606108ba6000606a60009054906101000a90046001600160801b03166133da565b945094509450945094509091929394565b6108d361426f565b606a546001600160801b03908116908316106109015760405162461bcd60e51b8152600401610879906158e7565b670de0b6b3a7640000816001600160801b0316106109315760405162461bcd60e51b815260040161087990615912565b6001600160801b038281166000818152606b60205260409081902060030180546001600160801b0319169385169390931790925590517f0f8cc456c84d934a2b1eb24d7b56c2304c9e61aed06c7e67aa5167ff06c0bc6590610994908490615360565b60405180910390a25050565b600054610100900460ff16158080156109c05750600054600160ff909116105b806109e157506109cf306142ce565b1580156109e1575060005460ff166001145b610a445760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610879565b6000805460ff191660011790558015610a67576000805461ff0019166101001790555b6001600160a01b038716610ab35760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420637174206164647265737360681b6044820152606401610879565b610abb6142dd565b606680546001600160801b03908116600160801b88831681029190911790925587811686821683021760675584811684821683021760688190556907695a92c20d6fe00000929004161015610b0f57600080fd5b6907695a92c20d6fe000006503782dace9d960921b01606c55606d8054600160ff19909116179055606580546001600160a01b0319166001600160a01b038916908117909155604080519182526001600160801b0387811660208401528881168383015286811660608401528581166080840152841660a08301526907695a92c20d6fe0000060c0830152670de0b6b3a764000060e0830152517f8dd9818f98c9407a99ad317beb9f15dd6263d23e15ac345e3fe18d4f597ea407918190036101000190a18015610c1a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b606d5460ff16610c455760405162461bcd60e51b8152600401610879906158c7565b6000816001600160801b031611610c6e5760405162461bcd60e51b815260040161087990615947565b610c7983838361430c565b505050565b610c8661426f565b6001600160a01b038116610cce5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606401610879565b606980546001600160a01b0319166001600160a01b0383169081179091556040517ff725afeae606c3f3c4c0ac3963e5c76a046bc4f386be98100c54e55bf5aeab3690600090a250565b606d5460ff16610d3a5760405162461bcd60e51b8152600401610879906158c7565b6001600160801b038083166000908152606b60205260409020908416610d725760405162461bcd60e51b815260040161087990615947565b606a546001600160801b0390811690841610610da05760405162461bcd60e51b8152600401610879906158e7565b600781015460ff1615610dc55760405162461bcd60e51b81526004016108799061596c565b6001600160801b038381166000908152606b6020908152604080832033845260060190915290205490831610610e0d5760405162461bcd60e51b815260040161087990615999565b6001600160801b038084166000908152606b602090815260408083203384526006019091528120805491929091908516908110610e4c57610e4c6159cb565b6000918252602090912060029091020180549091506001600160801b03164311610eb85760405162461bcd60e51b815260206004820152601d60248201527f436f6f6c646f776e20706572696f6420686173206e6f7420656e6465640000006044820152606401610879565b60018101546001600160801b0380871691161015610f0d5760405162461bcd60e51b8152602060048201526012602482015271082dadeeadce840d2e640e8dede40d0d2ced60731b6044820152606401610879565b600181018054869190600090610f2d9084906001600160801b03166159f7565b82546101009290920a6001600160801b038181021990931691831602179091556001830154166000039050610f6157600081555b826001600160801b0316336001600160a01b0316856001600160801b03167fa907b4e09e37315c70c013b1855950857585ae1efd206f344d5507f3b7a440d788604051610fae9190615360565b60405180910390a4610fc0338661475e565b5050505050565b610fcf61426f565b606780546001600160801b0319166001600160801b0383161790556040517f07e1dd3aeb6786f7e65f705157791b46bb0c3a23c63ce60f6bce52060addc8a79061101a908390615360565b60405180910390a150565b61102d61426f565b606d5460ff16156110715760405162461bcd60e51b815260206004820152600e60248201526d1b5d5cdd081899481c185d5cd95960921b6044820152606401610879565b606d805460ff191660011790557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6110a63390565b6040516110b39190615487565b60405180910390a1565b606d5460ff166110df5760405162461bcd60e51b8152600401610879906158c7565b606a546001600160801b039081169084161061110d5760405162461bcd60e51b8152600401610879906158e7565b816001600160801b0316836001600160801b03160361117a5760405162461bcd60e51b815260206004820152602360248201527f4f6c6420616e64206e65772076616c696461746f727320617265207468652073604482015262616d6560e81b6064820152608401610879565b6000846001600160801b0316116111a35760405162461bcd60e51b815260040161087990615947565b6001600160801b038381166000908152606b6020526040808220928516825290206001810154336001600160a01b03909116036112315760405162461bcd60e51b815260206004820152602660248201527f4e65772056616c696461746f722063616e6e6f742062652073616d652061732060448201526539b2b73232b960d11b6064820152608401610879565b600781015460ff16156112835760405162461bcd60e51b815260206004820152601a6024820152792a30b933b2ba103b30b634b230ba37b91034b990333937bd32b760311b6044820152606401610879565b6004810154156112d45760405162461bcd60e51b815260206004820152601c60248201527b15185c99d95d081d985b1a59185d1bdc881a5cc8191a5cd8589b195960221b6044820152606401610879565b600782015460ff16156112f95760405162461bcd60e51b81526004016108799061596c565b81600401546000036113495760405162461bcd60e51b815260206004820152601960248201527815985b1a59185d1bdc881a5cc81b9bdd08191a5cd8589b1959603a1b6044820152606401610879565b6001820154336001600160a01b03909116036113a55760405162461bcd60e51b815260206004820152601b60248201527a56616c696461746f722063616e6e6f7420726564656c656761746560281b6044820152606401610879565b3360009081526006830160205260409020546001600160801b038416106113de5760405162461bcd60e51b815260040161087990615999565b336000908152600683016020526040812080546001600160801b03861690811061140a5761140a6159cb565b6000918252602090912060029091020160018101549091506001600160801b038881169116101561144d5760405162461bcd60e51b815260040161087990615a1f565b8054600160801b90046001600160801b0316431161147d5760405162461bcd60e51b815260040161087990615a52565b60018101805488919060009061149d9084906001600160801b03166159f7565b82546101009290920a6001600160801b0381810219909316918316021790915560018301541660000390506114d157600081555b336001600160a01b0316856001600160801b0316876001600160801b03167fad667f96915cdefb4384b6fc59780e6f35a72cffecee152d5b83c2ec4bd16e3a8a88604051611520929190615649565b60405180910390a4610c1a85886000613e33565b606a546000906001600160801b03908116908316106115655760405162461bcd60e51b8152600401610879906158e7565b506001600160801b03166000908152606b60205260409020600401541590565b6069546001600160a01b03163314806115b657506115a1612ad4565b6001600160a01b0316336001600160a01b0316145b6115d25760405162461bcd60e51b815260040161087990615a85565b606a546001600160801b03908116908216106116005760405162461bcd60e51b8152600401610879906158e7565b6001600160801b0381166000908152606b60205260409020600481015415611626575050565b43600482018190556040519081526001600160801b03831690600080516020615e4483398151915290602001610994565b50565b61166261426f565b606680546001600160801b03808416600160801b0291161790556040517f975929c98e941a24cd7efdf9d3246bce86fae97c36c96865237dc361de5db2619061101a908390615360565b606d5460ff166116ce5760405162461bcd60e51b8152600401610879906158c7565b6001600160801b0382166000908152606b6020526040902060018101546001600160a01b031633146117405760405162461bcd60e51b815260206004820152601b60248201527a29b2b73232b91034b9903737ba103a3432903b30b634b230ba37b960291b6044820152606401610879565b60018101546001600160a01b03908116908316036117c8576040805162461bcd60e51b81526020600482015260248101919091527f546865206e657720616464726573732063616e6e6f7420626520657175616c2060448201527f746f207468652063757272656e742076616c696461746f7220616464726573736064820152608401610879565b6001600160a01b03821661181a5760405162461bcd60e51b8152602060048201526019602482015278496e76616c69642076616c696461746f72206164647265737360381b6044820152606401610879565b600781015460ff161561183f5760405162461bcd60e51b815260040161087990615aca565b61184882611e60565b156118ad5760405162461bcd60e51b815260206004820152602f60248201527f6e657741646472657373206d757374206e6f7420616c7265616479206578697360448201526e7420696e207468652073797374656d60881b6064820152608401610879565b336000908152600582016020526040808220546001600160a01b038516835290822080546001600160801b039283169391926118eb91859116615aff565b82546101009290920a6001600160801b03818102199093169183160217909155336000908152600584016020526040808220546001600160a01b038716835291208054600160801b9283900484169450909260109261194f92869291900416615aff565b82546101009290920a6001600160801b038181021990931691831602179091556068546001600160a01b0385166000908152600585016020526040902054600160801b918290048316919004909116111590506119be5760405162461bcd60e51b815260040161087990615b2a565b3360009081526005820160209081526040808320839055600684019091529020805461012c811115611a435760405162461bcd60e51b815260206004820152602860248201527f43616e6e6f74207472616e73666572206d6f7265207468616e2033303020756e6044820152677374616b696e677360c01b6064820152608401610879565b6001600160a01b03841660009081526006840160205260408120905b82816001600160801b03161015611b0b578184826001600160801b031681548110611a8c57611a8c6159cb565b6000918252602080832084546001818101875595855291909320600292830290930180549190920290920180546001600160801b03199081166001600160801b0394851690811783558354600160801b90819004861602178255918401549301805490911692909116919091179055611b0481615b60565b9050611a5f565b503360009081526006850160205260408120611b26916152ca565b6001840180546001600160a01b0319166001600160a01b0387169081179091556040516001600160801b038816907f440fb92be8d36802cfffb11ceda74bc13f38abab2e6f8675b9b1725787a6e52990600090a3505050505050565b606a5460009081906001600160801b0390811690841610611bb55760405162461bcd60e51b8152600401610879906158e7565b6001600160801b038084166000908152606b6020908152604080832060018101546001600160a01b03168452600581019092529091205481549192611c059291811691600160801b90041661477e565b600282015482549194508491611c33916001600160801b03600160801b91829004811692919091041661477e565b611c3d91906159f7565b915050915091565b606a54606090819081906001600160801b03166001600160401b03811115611c6f57611c6f6157f0565b604051908082528060200260200182016040528015611c98578160200160208202803683370190505b50606a549093506001600160801b03166001600160401b03811115611cbf57611cbf6157f0565b604051908082528060200260200182016040528015611ce8578160200160208202803683370190505b50606a549092506001600160801b03166001600160401b03811115611d0f57611d0f6157f0565b604051908082528060200260200182016040528015611d38578160200160208202803683370190505b50905060005b606a546001600160801b039081169082161015611e5a576001600160801b0381166000818152606b602052604090208551909183918791908110611d8457611d846159cb565b60200260200101906001600160801b031690816001600160801b031681525050806004015460001484836001600160801b031681518110611dc757611dc76159cb565b91151560209283029190910182015260018201546001600160a01b031660009081526005830190915260409020548154611e14916001600160801b0390811691600160801b90041661477e565b83836001600160801b031681518110611e2f57611e2f6159cb565b6001600160801b03909216602092830291909101909101525080611e5281615b60565b915050611d3e565b50909192565b6000805b606a546001600160801b039081169082161015611f46576001600160801b0381166000908152606b6020526040902060018101546001600160a01b03808616911603611eb4575060019392505050565b6001600160a01b038416600090815260058201602052604090208054600160801b90046001600160801b0316151580611ef6575080546001600160801b031615155b15611f0657506001949350505050565b6001600160a01b038516600090815260068301602052604090205415611f3157506001949350505050565b50508080611f3e90615b60565b915050611e64565b50600092915050565b606a546000908190819060609081906001600160801b0390811690871610611f895760405162461bcd60e51b8152600401610879906158e7565b6001600160801b038087166000908152606b602090815260408083206001600160a01b038c16845260058101909252822080548254600160801b80830487169b509395929493611fdf939283169291041661477e565b82549091506001600160801b03600160801b9091048116908216116120075760009650612026565b815461202390600160801b90046001600160801b0316826159f7565b96505b60018301546001600160a01b03808c1691160361204b5782546001600160801b031695505b6001600160a01b038a166000908152600684016020908152604080832080548251818502810185019093528083529192909190849084015b828210156120df576000848152602090819020604080516060810182526002860290920180546001600160801b038082168552600160801b90910481168486015260019182015416918301919091529083529092019101612083565b50508251929350829150506001600160401b03811115612101576121016157f0565b60405190808252806020026020018201604052801561212a578160200160208202803683370190505b509650806001600160401b03811115612145576121456157f0565b60405190808252806020026020018201604052801561216e578160200160208202803683370190505b50955060005b818110156122265782818151811061218e5761218e6159cb565b6020026020010151604001518882815181106121ac576121ac6159cb565b60200260200101906001600160801b031690816001600160801b0316815250508281815181106121de576121de6159cb565b6020026020010151600001518782815181106121fc576121fc6159cb565b6001600160801b03909216602092830291909101909101528061221e81615b8e565b915050612174565b5050505050509295509295909350565b61223e61426f565b6068546001600160801b03600160801b909104811690821611156122745760405162461bcd60e51b815260040161087990615ba7565b606c80546001600160801b0319166001600160801b0383161790556040517f96615934d2bb7b5a5040acb500498ac22e70b228607abe42d1c5fb66410306a59061101a908390615360565b606d5460ff166122e15760405162461bcd60e51b8152600401610879906158c7565b6001600160801b038083166000908152606b602052604090205461088e918491849116613755565b606d5460ff1661232b5760405162461bcd60e51b8152600401610879906158c7565b6116578160006147b0565b61233e61426f565b6000816001600160801b0316116123905760405162461bcd60e51b815260206004820152601660248201527504d7573742062652067726561746572207468616e20360541b6044820152606401610879565b606880546001600160801b0319166001600160801b0383161790556040517fbe85ebc47051eb40cf466cba324b4ceee119941ef0101ec0123999a5b67940999061101a908390615360565b6123e361426f565b606a546001600160801b03908116908216106124115760405162461bcd60e51b8152600401610879906158e7565b6001600160801b0381166000908152606b60205260409020600781015460ff166124745760405162461bcd60e51b81526020600482015260146024820152732b30b634b230ba37b9103737ba10333937bd32b760611b6044820152606401610879565b60078101805460ff191690556040516001600160801b038316907fea4a8e0f0ee4183a88d61c99c0c349b672a9931dca611802e7d489cac22ac70090600090a25050565b6124c061426f565b6124ca6000614efa565b565b6000805b606a546001600160801b039081169082161015612671576001600160801b038082166000908152606b602090815260408083206001600160a01b03881684526005810190925290912080548254929391926125379291821691600160801b9091041661477e565b6125419085615aff565b60018301549094506001600160a01b03808716911603612573578154612570906001600160801b031685615aff565b93505b6001600160a01b0385166000908152600683016020908152604080832080548251818502810185019093528083529192909190849084015b82821015612607576000848152602090819020604080516060810182526002860290920180546001600160801b038082168552600160801b909104811684860152600191820154169183019190915290835290920191016125ab565b5050825192935060009150505b818110156126595782818151811061262e5761262e6159cb565b602002602001015160400151876126459190615aff565b96508061265181615b8e565b915050612614565b5050505050808061266990615b60565b9150506124d0565b50919050565b61267f61426f565b606d5460ff166126a15760405162461bcd60e51b8152600401610879906158c7565b606d805460ff191690557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258336110a6565b606d5460ff166126f45760405162461bcd60e51b8152600401610879906158c7565b61088e8282600061430c565b606a5460009081908190819081906001600160801b03908116908716106127395760405162461bcd60e51b8152600401610879906158e7565b505050506001600160801b039182166000908152606b6020908152604080832060018101546001600160a01b031680855260058201909352922054600283015460038401546004909401549296600160801b90920486169590811694509290921691565b606d5460ff166127bf5760405162461bcd60e51b8152600401610879906158c7565b6001600160801b038083166000908152606b602052604090209084166127f75760405162461bcd60e51b815260040161087990615947565b606a546001600160801b03908116908416106128255760405162461bcd60e51b8152600401610879906158e7565b600781015460ff161561284a5760405162461bcd60e51b81526004016108799061596c565b6001600160801b038381166000908152606b60209081526040808320338452600601909152902054908316106128925760405162461bcd60e51b815260040161087990615999565b6001600160801b038084166000908152606b6020908152604080832033845260060190915281208054919290919085169081106128d1576128d16159cb565b6000918252602090912060029091020160018101549091506001600160801b03868116911610156129145760405162461bcd60e51b815260040161087990615a1f565b8054600160801b90046001600160801b031643116129445760405162461bcd60e51b815260040161087990615a52565b6001810180548691906000906129649084906001600160801b03166159f7565b82546101009290920a6001600160801b03818102199093169183160217909155600183015416600003905061299857600081555b336001600160a01b0316846001600160801b03167ff9087cb83487275bb1784df2905fb9038a38f2423637cba5910e5e638147b54687866040516129dd929190615649565b60405180910390a3610fc084866000613e33565b6129f961426f565b6000816001600160801b031611612a225760405162461bcd60e51b815260040161087990615947565b6066546001600160801b039081169082161115612a515760405162461bcd60e51b815260040161087990615bf8565b60668054829190600090612a6f9084906001600160801b03166159f7565b92506101000a8154816001600160801b0302191690836001600160801b031602179055507fb377d2221ae3ae0038f8a2593ce854d79cc6d598036b3acb67a2bed08557ee2e81604051612ac29190615360565b60405180910390a1611657338261475e565b6033546001600160a01b031690565b6069546001600160a01b03163314612b3c5760405162461bcd60e51b815260206004820152601c60248201527b21b0b63632b91034b9903737ba1039ba30b5b4b733a6b0b730b3b2b960211b6044820152606401610879565b606d5460ff16612b5e5760405162461bcd60e51b8152600401610879906158c7565b828114612bcd5760405162461bcd60e51b815260206004820152603760248201527f476976656e2069647320616e6420616d6f756e747320617272617973206d75736044820152760e840c4ca40decc40e8d0ca40e6c2daca40d8cadccee8d604b1b6064820152608401610879565b6066546001600160801b031660008080805b87811015612eee57868682818110612bf957612bf96159cb565b9050602002016020810190612c0e91906155b0565b9350888882818110612c2257612c226159cb565b9050602002016020810190612c3791906155b0565b606a549093506001600160801b0390811690841610612c8e5760405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a59081d985b1a59185d1bdc9259606a1b6044820152606401610879565b836001600160801b0316856001600160801b03161015612cc05760405162461bcd60e51b815260040161087990615bf8565b6001600160801b0383166000908152606b60205260409020600781015460ff1615612d2c57836001600160801b03167fc2bdf82af0e9f6a6a8f058a552be64fe1e51323a57e371f35ad21244fae47b1a86604051612d1e9190615360565b60405180910390a250612edc565b600481015415612d6f57836001600160801b03167f3f3428e3eab4bb899c776a5ee201ed7966fab0436396bb5fbf2d185f9af07c1f86604051612d1e9190615360565b6002810154600160801b90046001600160801b0316600003612dc457836001600160801b03167f7110409a3c69501d520618529eec9541a3d35ae7b4c5df2a4e5271438105cee386604051612d1e9190615360565b6003810154670de0b6b3a764000090612dea906001600160801b03908116908816615c2a565b612df49190615c49565b6002820154909350600160801b90046001600160801b0316670de0b6b3a7640000612e1f85886159f7565b6001600160801b0316612e329190615c2a565b612e3c9190615c49565b81548290601090612e5e908490600160801b90046001600160801b0316615aff565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550828160000160008282829054906101000a90046001600160801b0316612ea89190615aff565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508486612ed891906159f7565b9550505b80612ee681615b8e565b915050612bdf565b50606680546001600160801b0319166001600160801b0386811691909117909155604051908a16907f37350b4011f8bb2d43347fc9f306e558616b5d3705701e4a06348e58decfc12e90600090a2505050505050505050565b612f4f61426f565b6068546001600160801b03600160801b90910481169082161115612f855760405162461bcd60e51b815260040161087990615ba7565b606c80546001600160801b03808416600160801b0291161790556040517f159c54a1ee3a0b6b82a6af64b4ca254a0c24088fac62ae018204136aa590d3f99061101a908390615360565b606d5460ff16612ff15760405162461bcd60e51b8152600401610879906158c7565b6000816001600160801b03161161301a5760405162461bcd60e51b815260040161087990615947565b61088e82826147b0565b606a5460009081906001600160801b03908116908416106130575760405162461bcd60e51b8152600401610879906158e7565b50506001600160801b039081166000908152606b6020908152604080832060018101546001600160a01b031684526005810190925290912054600290910154600160801b909104821692911690565b6130ae61426f565b6000816001600160801b0316116131015760405162461bcd60e51b8152602060048201526017602482015276050726f7669646564206d6178207374616b65206973203604c1b6044820152606401610879565b606c546001600160801b0390811690821610156131805760405162461bcd60e51b815260206004820152603760248201527f6d61785374616b652073686f756c642062652067726561746572207468616e2060448201527676616c696461746f72456e61626c654d696e5374616b6560481b6064820152608401610879565b606880546001600160801b03808416600160801b0291161790556040517fc85c2d6ddb875b53634093f65fbea4ed8eba0b4efca26b87bc17ffedb66891649061101a908390615360565b60006131d461426f565b606d5460ff166131f65760405162461bcd60e51b8152600401610879906158c7565b670de0b6b3a7640000826001600160801b0316106132265760405162461bcd60e51b815260040161087990615912565b6001600160a01b0383166132755760405162461bcd60e51b8152602060048201526016602482015275056616c696461746f72206164647265737320697320360541b6044820152606401610879565b606a546101006001600160801b03909116106132c95760405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e792076616c696461746f727360681b6044820152606401610879565b606a80546001600160801b039081166000908152606b602052604090819020600180820180546001600160a01b0319166001600160a01b038a16908117909155825485166503782dace9d960921b1783556003830180546001600160801b03191689871617905560048301919091559354915190939291909116907f5a7dc0f8a1745e71f29bb12198638d3c7284ae1227928e679ab6bf3dc1f2861790613371908790615360565b60405180910390a3606a8054600191906000906133989084906001600160801b0316615aff565b82546101009290920a6001600160801b03818102199093169183160217909155606a546133c99250600191166159f7565b6001600160801b0316949350505050565b606a5460609081908190819081906001600160801b0390811690871611156134355760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908195b99081a5960921b6044820152606401610879565b856001600160801b0316876001600160801b0316106134a05760405162461bcd60e51b815260206004820152602160248201527f5374617274206964206d757374206265206c657373207468616e20656e6420696044820152601960fa1b6064820152608401610879565b60006134ac88886159f7565b9050806001600160801b03166001600160401b038111156134cf576134cf6157f0565b6040519080825280602002602001820160405280156134f8578160200160208202803683370190505b509550806001600160801b03166001600160401b0381111561351c5761351c6157f0565b604051908082528060200260200182016040528015613545578160200160208202803683370190505b509450806001600160801b03166001600160401b03811115613569576135696157f0565b604051908082528060200260200182016040528015613592578160200160208202803683370190505b509350806001600160801b03166001600160401b038111156135b6576135b66157f0565b6040519080825280602002602001820160405280156135df578160200160208202803683370190505b509250806001600160801b03166001600160401b03811115613603576136036157f0565b60405190808252806020026020018201604052801561362c578160200160208202803683370190505b5091506000885b886001600160801b0316816001600160801b03161015613748576136578a826159f7565b915061366281612700565b8c876001600160801b03168151811061367d5761367d6159cb565b602002602001018c886001600160801b03168151811061369f5761369f6159cb565b602002602001018c896001600160801b0316815181106136c1576136c16159cb565b602002602001018c8a6001600160801b0316815181106136e3576136e36159cb565b602002602001018c8b6001600160801b031681518110613705576137056159cb565b60209081029190910101949094526001600160801b03948516909352938316909152921690526001600160a01b03909116905261374181615b60565b9050613633565b5050509295509295909350565b606d5460ff166137775760405162461bcd60e51b8152600401610879906158c7565b606a546001600160801b03908116908416106137a55760405162461bcd60e51b8152600401610879906158e7565b6001600160a01b0382166137cb5760405162461bcd60e51b815260040161087990615c6b565b6001600160801b0383166000908152606b6020526040902060018101546001600160a01b0316331461383f5760405162461bcd60e51b815260206004820152601f60248201527f5468652073656e646572206973206e6f74207468652076616c696461746f72006044820152606401610879565b600781015460ff16156138645760405162461bcd60e51b81526004016108799061596c565b80546001600160801b03166138c55760405162461bcd60e51b815260206004820152602160248201527f4e6f20636f6d6d697373696f6e20617661696c61626c6520746f2072656465656044820152606d60f81b6064820152608401610879565b6000826001600160801b03161161391a5760405162461bcd60e51b815260206004820152601960248201527805468652072657175657374656420616d6f756e74206973203603c1b6044820152606401610879565b80546001600160801b03908116908316111561399e5760405162461bcd60e51b815260206004820152603e60248201527f52657175657374656420616d6f756e7420697320686967686572207468616e2060448201527f636f6d6d697373696f6e20617661696c61626c6520746f2072656465656d00006064820152608401610879565b6066546001600160801b03808416911610156139cc5760405162461bcd60e51b815260040161087990615c98565b8054829082906000906139e99084906001600160801b03166159f7565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550613a17838361475e565b826001600160a01b0316846001600160801b03167fca484c45ad2d2422ff409731d1783446054a9a6549f63f4e668f85d03513624c84604051613a5a9190615360565b60405180910390a350505050565b6069546001600160a01b0316331480613a995750613a84612ad4565b6001600160a01b0316336001600160a01b0316145b613ab55760405162461bcd60e51b815260040161087990615a85565b606a546001600160801b0390811690821610613ae35760405162461bcd60e51b8152600401610879906158e7565b6001600160801b0381166000908152606b602052604081206004810154909103613b0b575050565b60018101546001600160a01b031660009081526005820160205260408120548254613b49916001600160801b0390811691600160801b90041661477e565b606c549091506001600160801b039081169082161015613bb65760405162461bcd60e51b815260206004820152602260248201527f56616c696461746f7220697320696e73756666696369656e746c79207374616b604482015261195960f21b6064820152608401610879565b6000600483018190556040516001600160801b038516917f553b029ba5c74688a5da732136d246f722502db24ed6b4aaf1cdc9f2f9ef23ef91a2505050565b613bfd61426f565b606a546001600160801b0390811690831610613c2b5760405162461bcd60e51b8152600401610879906158e7565b6001600160801b0382166000908152606b60205260409020600781015460ff1615613c685760405162461bcd60e51b815260040161087990615aca565b60078101805460ff191660011790556040516001600160801b038416907fb1faebd90b927d5787302f4faf38c6007fc7f13f72dc6ab940882c4298fab0bc90613cb2908590615d2f565b60405180910390a2505050565b613cc761426f565b6000816001600160801b031611613cf05760405162461bcd60e51b815260040161087990615947565b60668054829190600090613d0e9084906001600160801b0316615aff565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550613d3c3382614f4c565b7f2db5044922a44e715fdfd31c569712694c5956bbd41e06011f1c8ed339f5ff8f8160405161101a9190615360565b613d7361426f565b6001600160a01b038116613dd85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610879565b61165781614efa565b613de961426f565b606780546001600160801b03808416600160801b0291161790556040517fec01665ba42d9d72c4959955f1efc84081c86e146ffe0c528d46a95834d988429061101a908390615360565b606a546001600160801b0390811690841610613e615760405162461bcd60e51b8152600401610879906158e7565b670de0b6b3a76400006001600160801b0383161015613ebe5760405162461bcd60e51b815260206004820152601960248201527814dd185ad948185b5bdd5b9d081a5cc81d1bdbc81cdb585b1b603a1b6044820152606401610879565b6001600160801b0383166000908152606b60205260409020600181015460078201546001600160a01b0390911633149060ff1615613f0e5760405162461bcd60e51b81526004016108799061596c565b80613f5d57600482015415613f5d5760405162461bcd60e51b815260206004820152601560248201527415985b1a59185d1bdc881a5cc8191a5cd8589b1959605a1b6044820152606401610879565b33600090815260058301602052604081208054909190613f8e908790600160801b90046001600160801b0316615aff565b606c549091506001600160801b03600160801b909104811690821610156140165760405162461bcd60e51b815260206004820152603660248201527f43616e6e6f74207374616b6520746f206120706f736974696f6e206c657373206044820152757468616e2064656c656761746f724d696e5374616b6560501b6064820152608401610879565b8354600090614036908890600160801b90046001600160801b0316614f6d565b90508315614079576068546001600160801b03600160801b909104811690831611156140745760405162461bcd60e51b815260040161087990615b2a565b61416c565b60685460018601546001600160a01b0316600090815260058701602052604081205490916140bb916001600160801b0391821691600160801b90910416615d62565b60028701549091506000906140da908a906001600160801b0316615aff565b9050816001600160801b0316816001600160801b031611156141485760405162461bcd60e51b815260206004820152602160248201527f56616c696461746f72206d61782064656c65676174696f6e20657863656564656044820152601960fa1b6064820152608401610879565b6002870180546001600160801b0319166001600160801b0392909216919091179055505b808560020160108282829054906101000a90046001600160801b03166141929190615aff565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550808360000160008282829054906101000a90046001600160801b03166141dc9190615aff565b82546001600160801b039182166101009390930a9283029282021916919091179091558454848216600160801b029116178455508515614220576142203388614f4c565b604080513381526001600160801b0389811660208301528a16917fc833924412a8727ace4d92945c637ad2d4b389e582bfd4a95cdee608eee9720a910160405180910390a25050505050505050565b33614278612ad4565b6001600160a01b0316146124ca5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610879565b6001600160a01b03163b151590565b600054610100900460ff166143045760405162461bcd60e51b815260040161087990615d91565b6124ca614f96565b606a546001600160801b039081169084161061433a5760405162461bcd60e51b8152600401610879906158e7565b6001600160a01b0382166143605760405162461bcd60e51b815260040161087990615c6b565b6001600160801b0383166000908152606b6020908152604080832033845260058101909252909120600782015460ff16156143ad5760405162461bcd60e51b81526004016108799061596c565b805482546000916143d2916001600160801b0391821691600160801b9091041661477e565b82549091506000906001600160801b03600160801b90910481169083161061441557825461441090600160801b90046001600160801b0316836159f7565b614418565b60005b905060006001600160801b03861615806144435750816001600160801b0316866001600160801b0316145b9050816001600160801b0316866001600160801b031611156144c85760405162461bcd60e51b815260206004820152603860248201527f43616e6e6f742072656465656d20616d6f756e742067726561746572207468616044820152776e2068656c642c20756e7374616b6564207265776172647360401b6064820152608401610879565b6000816144d557866144d7565b825b90506305f5e1006001600160801b03821610156145545760405162461bcd60e51b815260206004820152603560248201527f52657175657374656420616d6f756e74206d75737420626520686967686572206044820152741d1a185b881c995919595b481d1a1c995cda1bdb19605a1b6064820152608401610879565b6066546001600160801b03808316911610156145825760405162461bcd60e51b815260040161087990615c98565b85546000906145a2908390600160801b90046001600160801b0316614f6d565b86549091506001600160801b0390811690821611156145c8575084546001600160801b03165b6000816001600160801b0316116145f15760405162461bcd60e51b815260040161087990615ddc565b61460c670de0b6b3a76400006001600160801b038416615c2a565b875461462c906001600160801b03600160801b9091048116908416615c2a565b1015614669578654670de0b6b3a76400009061465c906001600160801b03600160801b9091048116908416615c2a565b6146669190615c49565b91505b808760020160108282829054906101000a90046001600160801b031661468f91906159f7565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550808660000160008282829054906101000a90046001600160801b03166146d991906159f7565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550886001600160a01b03168a6001600160801b03167fbf3f2aa111a63b63567f864e18723c486b9276b75fdadebb83f62cd228263e0c846040516147409190615360565b60405180910390a3614752898361475e565b50505050505050505050565b60655461088e906001600160a01b0316836001600160801b038416614fc6565b6000670de0b6b3a764000061479f6001600160801b03808516908616615c2a565b6147a99190615c49565b9392505050565b606a546001600160801b03908116908316106147de5760405162461bcd60e51b8152600401610879906158e7565b6001600160801b0382166000908152606b6020908152604080832033808552600582019093529220600183015490916001600160a01b03909116900361484357600782015460ff16156148435760405162461bcd60e51b81526004016108799061596c565b80546001600160801b03600160801b909104811690841611156148c15760405162461bcd60e51b815260206004820152603060248201527f43616e6e6f7420756e7374616b6520616d6f756e74206772656174657220746860448201526f616e2063757272656e74207374616b6560801b6064820152608401610879565b60006001600160801b03841615806148ec575081546001600160801b03858116600160801b90920416145b90506000816148fb578461490e565b8254600160801b90046001600160801b03165b8354909150600090614931908390600160801b90046001600160801b03166159f7565b90508215614990576000826001600160801b03161161498b5760405162461bcd60e51b8152602060048201526016602482015275105b1c9958591e48199d5b1b1e481d5b9cdd185ad95960521b6044820152606401610879565b614a85565b6305f5e1006001600160801b03831610156149eb5760405162461bcd60e51b815260206004820152601b60248201527a155b9cdd185ad948185b5bdd5b9d081a5cc81d1bdbc81cdb585b1b602a1b6044820152606401610879565b606c546001600160801b03600160801b90910481169082161015614a855760405162461bcd60e51b815260206004820152604560248201527f43616e6e6f7420756e7374616b6520746f206120706f736974696f6e2062656c60448201527f6f772064656c656761746f724d696e5374616b65202865786365707420746f206064820152647a65726f2960d81b608482015260a401610879565b60018501546001600160a01b03163314808015614aac5750606c546001600160801b031615155b8015614aba57506004860154155b8015614ad45750606c546001600160801b03908116908316105b15614b0f5743600487018190556040518181526001600160801b038a1690600080516020615e448339815191529060200160405180910390a2505b808015614b1e57506004860154155b15614be657606854600090614b3c906001600160801b031684615d62565b60028801549091506001600160801b0380831691161115614be45760405162461bcd60e51b815260206004820152605660248201527f43616e6e6f742064656372656173652064656c65676174696f6e206d61782d6360448201527f61702062656c6f772063757272656e742064656c65676174696f6e207768696c60648201527519481d985b1a59185d1bdc881a5cc8195b98589b195960521b608482015260a401610879565b505b80614c3057600286018054849190600090614c0b9084906001600160801b03166159f7565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b8554600090614c50908590600160801b90046001600160801b0316614f6d565b86549091506001600160801b039081169082161115614c76575084546001600160801b03165b6000816001600160801b031611614c9f5760405162461bcd60e51b815260040161087990615ddc565b614cba670de0b6b3a76400006001600160801b038616615c2a565b8754614cda906001600160801b03600160801b9091048116908416615c2a565b1015614d17578654670de0b6b3a764000090614d0a906001600160801b03600160801b9091048116908416615c2a565b614d149190615c49565b93505b855481908790600090614d349084906001600160801b03166159f7565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550808760020160108282829054906101000a90046001600160801b0316614d7e91906159f7565b82546001600160801b039182166101009390930a9283029282021916919091179091558754858216600160801b0291161787555060048701546000908103614dc65743614dcc565b87600401545b606754909150600090614def90600160801b90046001600160801b031683615aff565b905083614e07576067546001600160801b0316614e1b565b606654600160801b90046001600160801b03165b614e259083615aff565b33600081815260068c0160209081526040808320805482516060810184526001600160801b0380891682528981168287019081528f82168387019081526001808601875595895296909720915196518116600160801b02968116969096176002830290910190815593519390910180549385166001600160801b031994909416939093179092555193955092908e16907ffd593fe24ae9d02e348b533a8253aaf9904b266a7b65556ae6181dd5cc58703b90614ee4908b908690615649565b60405180910390a3505050505050505050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60655461088e906001600160a01b031683306001600160801b038516615029565b6000816001600160801b0316670de0b6b3a7640000846001600160801b031661479f9190615c2a565b600054610100900460ff16614fbd5760405162461bcd60e51b815260040161087990615d91565b6124ca33614efa565b6040516001600160a01b038316602482015260448101829052610c7990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152615067565b6040516001600160a01b03808516602483015283166044820152606481018290526150619085906323b872dd60e01b90608401614ff2565b50505050565b60006150bc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661513c9092919063ffffffff16565b90508051600014806150dd5750808060200190518101906150dd9190615e05565b610c795760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610879565b606061514b8484600085615153565b949350505050565b6060824710156151b45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610879565b600080866001600160a01b031685876040516151d09190615e27565b60006040518083038185875af1925050503d806000811461520d576040519150601f19603f3d011682016040523d82523d6000602084013e615212565b606091505b50915091506152238783838761522e565b979650505050505050565b6060831561529b57825160000361529457615248856142ce565b6152945760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610879565b508161514b565b61514b83838151156152b05781518083602001fd5b8060405162461bcd60e51b81526004016108799190615d2f565b508054600082556002029060005260206000209081019061165791905b8082111561530d57600081556001810180546001600160801b03191690556002016152e7565b5090565b80356001600160801b038116811461532857600080fd5b919050565b6000806040838503121561534057600080fd5b61534983615311565b915061535760208401615311565b90509250929050565b6001600160801b0391909116815260200190565b600081518084526020808501945080840160005b838110156153ad5781516001600160801b031687529582019590820190600101615388565b509495945050505050565b600081518084526020808501945080840160005b838110156153ad578151875295820195908201906001016153cc565b60a0808252865190820181905260009060209060c0840190828a01845b8281101561542a5781516001600160a01b031684529284019290840190600101615405565b5050508381038285015261543e8189615374565b91505082810360408401526154538187615374565b905082810360608401526154678186615374565b9050828103608084015261547b81856153b8565b98975050505050505050565b6001600160a01b0391909116815260200190565b80356001600160a01b038116811461532857600080fd5b60008060008060008060c087890312156154cb57600080fd5b6154d48761549b565b95506154e260208801615311565b94506154f060408801615311565b93506154fe60608801615311565b925061550c60808801615311565b915061551a60a08801615311565b90509295509295509295565b60008060006060848603121561553b57600080fd5b61554484615311565b92506155526020850161549b565b915061556060408501615311565b90509250925092565b60006020828403121561557b57600080fd5b6147a98261549b565b60008060006060848603121561559957600080fd5b6155a284615311565b925061555260208501615311565b6000602082840312156155c257600080fd5b6147a982615311565b600080600080608085870312156155e157600080fd5b6155ea85615311565b93506155f860208601615311565b925061560660408601615311565b915061561460608601615311565b905092959194509250565b6000806040838503121561563257600080fd5b61563b83615311565b91506153576020840161549b565b6001600160801b0392831681529116602082015260400190565b6060815260006156766060830186615374565b82810360208481019190915285518083528682019282019060005b818110156156af578451151583529383019391830191600101615691565b5050848103604086015261547b8187615374565b600080604083850312156156d657600080fd5b6153498361549b565b6001600160801b03868116825285811660208301528416604082015260a06060820181905260009061571390830185615374565b828103608084015261547b8185615374565b60008083601f84011261573757600080fd5b5081356001600160401b0381111561574e57600080fd5b6020830191508360208260051b850101111561576957600080fd5b9250929050565b60008060008060006060868803121561578857600080fd5b61579186615311565b945060208601356001600160401b03808211156157ad57600080fd5b6157b989838a01615725565b909650945060408801359150808211156157d257600080fd5b506157df88828901615725565b969995985093965092949392505050565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561581957600080fd5b61582283615311565b915060208301356001600160401b038082111561583e57600080fd5b818501915085601f83011261585257600080fd5b813581811115615864576158646157f0565b604051601f8201601f19908116603f0116810190838211818310171561588c5761588c6157f0565b816040528281528860208487010111156158a557600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6020808252600690820152651c185d5cd95960d21b604082015260600190565b60208082526011908201527024b73b30b634b2103b30b634b230ba37b960791b604082015260600190565b6020808252601b908201527a52617465206d757374206265206c657373207468616e203130302560281b604082015260600190565b6020808252600b908201526a0416d6f756e7420697320360ac1b604082015260600190565b6020808252601390820152722b30b634b230ba37b91034b990333937bd32b760691b604082015260600190565b602080825260189082015277155b9cdd185ada5b99c8191bd95cc81b9bdd08195e1a5cdd60421b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001600160801b0383811690831681811015615a1757615a176159e1565b039392505050565b602080825260199082015278556e7374616b696e6720686173206c65737320746f6b656e7360381b604082015260600190565b6020808252601990820152783932b1b7bb32b91031b7b7b63237bbb7103737ba1037bb32b960391b604082015260600190565b60208082526025908201527f43616c6c6572206973206e6f74207374616b696e674d616e61676572206f722060408201526437bbb732b960d91b606082015260800190565b6020808252601b908201527a2b30b634b230ba37b91034b99030b63932b0b23c90333937bd32b760291b604082015260600190565b60006001600160801b03828116848216808303821115615b2157615b216159e1565b01949350505050565b6020808252601c908201527b15985b1a59185d1bdc881b585e081cdd185ad948195e18d95959195960221b604082015260600190565b60006001600160801b038281166002600160801b03198101615b8457615b846159e1565b6001019392505050565b600060018201615ba057615ba06159e1565b5060010190565b60208082526031908201527f6d696e5374616b652063616e6e6f742062652067726561746572207468616e2060408201527076616c696461746f724d61785374616b6560781b606082015260800190565b60208082526018908201527714995dd85c99081c1bdbdb081a5cc81d1bdbc81cdb585b1b60421b604082015260600190565b6000816000190483118215151615615c4457615c446159e1565b500290565b600082615c6657634e487b7160e01b600052601260045260246000fd5b500490565b602080825260139082015272496e76616c69642062656e656669636961727960681b604082015260600190565b60208082526045908201527f52657175657374656420616d6f756e74206973206e6f7420617661696c61626c60408201527f6520696e20746865207374616b696e6720636f6e747261637420726577617264606082015264081c1bdbdb60da1b608082015260a00190565b60005b83811015615d1e578181015183820152602001615d06565b838111156150615750506000910152565b6020815260008251806020840152615d4e816040850160208701615d03565b601f01601f19169190910160400192915050565b60006001600160801b0382811684821681151582840482111615615d8857615d886159e1565b02949350505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020808252600f908201526e2ab73232b9333637bb9032b93937b960891b604082015260600190565b600060208284031215615e1757600080fd5b815180151581146147a957600080fd5b60008251615e39818460208701615d03565b919091019291505056fe890228cff135716fe461694a594a1308c48a00abf62b3fcff51a2fbabf234712a2646970667358221220edad977a5cef64a950fbe743b6201daa368225b3f7b9c19716219cb283e4545e64736f6c634300080d0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.