ETH Price: $2,522.96 (-0.11%)

Contract

0x571f39d351513146248AcafA9D0509319A327C4D
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw206343282024-08-29 12:45:5915 hrs ago1724935559IN
0x571f39d3...19A327C4D
0 ETH0.000405353.44990872
Withdraw Request206328762024-08-29 7:53:5920 hrs ago1724918039IN
0x571f39d3...19A327C4D
0 ETH0.000069771.39024626
Withdraw Request205954882024-08-24 2:30:116 days ago1724466611IN
0x571f39d3...19A327C4D
0 ETH0.000060131.19833808
Withdraw205859392024-08-22 18:28:597 days ago1724351339IN
0x571f39d3...19A327C4D
0 ETH0.000213561.94198525
Withdraw Request205835062024-08-22 10:19:357 days ago1724321975IN
0x571f39d3...19A327C4D
0 ETH0.000078761.56936279
Claim205630312024-08-19 13:40:3510 days ago1724074835IN
0x571f39d3...19A327C4D
0 ETH0.000104093.7791106
Claim205628162024-08-19 12:56:5910 days ago1724072219IN
0x571f39d3...19A327C4D
0 ETH0.00012464.52337506
Claim205626822024-08-19 12:29:4710 days ago1724070587IN
0x571f39d3...19A327C4D
0 ETH0.000068712.4947332
Withdraw Request205462842024-08-17 5:33:5912 days ago1723872839IN
0x571f39d3...19A327C4D
0 ETH0.000035271.06651276
Withdraw Request205359042024-08-15 18:45:5914 days ago1723747559IN
0x571f39d3...19A327C4D
0 ETH0.00023624.70620632
Withdraw Request205228102024-08-13 22:52:3516 days ago1723589555IN
0x571f39d3...19A327C4D
0 ETH0.000050171
Withdraw Request205070072024-08-11 17:57:4718 days ago1723399067IN
0x571f39d3...19A327C4D
0 ETH0.000099121.97554112
Withdraw205061972024-08-11 15:14:4718 days ago1723389287IN
0x571f39d3...19A327C4D
0 ETH0.00023632.14873299
Withdraw204639862024-08-05 17:54:1124 days ago1722880451IN
0x571f39d3...19A327C4D
0 ETH0.0027111910.89256646
Withdraw204627952024-08-05 13:54:4724 days ago1722866087IN
0x571f39d3...19A327C4D
0 ETH0.0077825870.76686043
Withdraw Request204558262024-08-04 14:35:3525 days ago1722782135IN
0x571f39d3...19A327C4D
0 ETH0.00013442.67849362
Withdraw204558232024-08-04 14:34:5925 days ago1722782099IN
0x571f39d3...19A327C4D
0 ETH0.000456432.68196787
Withdraw Request204529902024-08-04 5:06:5925 days ago1722748019IN
0x571f39d3...19A327C4D
0 ETH0.000061331.22231103
Withdraw204519852024-08-04 1:45:3526 days ago1722735935IN
0x571f39d3...19A327C4D
0 ETH0.000256892.02159642
Claim204332302024-08-01 10:54:2328 days ago1722509663IN
0x571f39d3...19A327C4D
0 ETH0.000148895.40527881
Withdraw204323602024-08-01 7:59:1128 days ago1722499151IN
0x571f39d3...19A327C4D
0 ETH0.00050834
Withdraw204307332024-08-01 2:32:3529 days ago1722479555IN
0x571f39d3...19A327C4D
0 ETH0.0214862204.29003874
Withdraw Request204228652024-07-31 0:11:2330 days ago1722384683IN
0x571f39d3...19A327C4D
0 ETH0.000114473.46090728
Withdraw Request204226592024-07-30 23:29:5930 days ago1722382199IN
0x571f39d3...19A327C4D
0 ETH0.000117083.53964312
Claim204183612024-07-30 9:03:5930 days ago1722330239IN
0x571f39d3...19A327C4D
0 ETH0.000120544.37596373
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
HATVaults

Compiler Version
v0.8.6+commit.11564f7e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 15 : HATVaults.sol
// SPDX-License-Identifier: MIT
// Disclaimer https://github.com/hats-finance/hats-contracts/blob/main/DISCLAIMER.md

pragma solidity 0.8.6;
import "./interfaces/ISwapRouter.sol";
import "openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "./HATMaster.sol";
import "./tokenlock/ITokenLockFactory.sol";
import "./Governable.sol";


contract  HATVaults is Governable, HATMaster {
    using SafeMath  for uint256;
    using SafeERC20 for IERC20;

    struct PendingApproval {
        address beneficiary;
        uint256 severity;
        address approver;
    }

    struct ClaimReward {
        uint256 hackerVestedReward;
        uint256 hackerReward;
        uint256 committeeReward;
        uint256 swapAndBurn;
        uint256 governanceHatReward;
        uint256 hackerHatReward;
    }

    struct PendingRewardsLevels {
        uint256 timestamp;
        uint256[] rewardsLevels;
    }

    struct GeneralParameters {
        uint256 hatVestingDuration;
        uint256 hatVestingPeriods;
        uint256 withdrawPeriod;
        uint256 safetyPeriod; //withdraw disable period in seconds
        uint256 setRewardsLevelsDelay;
        uint256 withdrawRequestEnablePeriod;
        uint256 withdrawRequestPendingPeriod;
        uint256 claimFee;  //claim fee in ETH
    }

    //pid -> committee address
    mapping(uint256=>address) public committees;
    mapping(address => uint256) public swapAndBurns;
    //hackerAddress ->(token->amount)
    mapping(address => mapping(address => uint256)) public hackersHatRewards;
    //token -> amount
    mapping(address => uint256) public governanceHatRewards;
    //pid -> PendingApproval
    mapping(uint256 => PendingApproval) public pendingApprovals;
    //poolId -> (address -> requestTime)
    mapping(uint256 => mapping(address => uint256)) public withdrawRequests;
    //poolId -> PendingRewardsLevels
    mapping(uint256 => PendingRewardsLevels) public pendingRewardsLevels;

    mapping(uint256 => bool) public poolDepositPause;

    GeneralParameters public generalParameters;

    uint256 internal constant REWARDS_LEVEL_DENOMINATOR = 10000;
    ITokenLockFactory public immutable tokenLockFactory;
    ISwapRouter public immutable uniSwapRouter;
    uint256 public constant MINIMUM_DEPOSIT = 1e6;

    modifier onlyCommittee(uint256 _pid) {
        require(committees[_pid] == msg.sender, "only committee");
        _;
    }

    modifier noPendingApproval(uint256 _pid) {
        require(pendingApprovals[_pid].beneficiary == address(0), "pending approval exist");
        _;
    }

    modifier noSafetyPeriod() {
      //disable withdraw for safetyPeriod (e.g 1 hour) each withdrawPeriod(e.g 11 hours)
      // solhint-disable-next-line not-rely-on-time
        require(block.timestamp % (generalParameters.withdrawPeriod + generalParameters.safetyPeriod) <
        generalParameters.withdrawPeriod,
        "safety period");
        _;
    }

    event SetCommittee(uint256 indexed _pid, address indexed _committee);

    event AddPool(uint256 indexed _pid,
                uint256 indexed _allocPoint,
                address indexed _lpToken,
                address _committee,
                string _descriptionHash,
                uint256[] _rewardsLevels,
                RewardsSplit _rewardsSplit,
                uint256 _rewardVestingDuration,
                uint256 _rewardVestingPeriods);

    event SetPool(uint256 indexed _pid, uint256 indexed _allocPoint, bool indexed _registered, string _descriptionHash);
    event Claim(address indexed _claimer, string _descriptionHash);
    event SetRewardsSplit(uint256 indexed _pid, RewardsSplit _rewardsSplit);
    event SetRewardsLevels(uint256 indexed _pid, uint256[] _rewardsLevels);
    event PendingRewardsLevelsLog(uint256 indexed _pid, uint256[] _rewardsLevels, uint256 _timeStamp);

    event SwapAndSend(uint256 indexed _pid,
                    address indexed _beneficiary,
                    uint256 indexed _amountSwaped,
                    uint256 _amountReceived,
                    address _tokenLock);

    event SwapAndBurn(uint256 indexed _pid, uint256 indexed _amountSwaped, uint256 indexed _amountBurned);
    event SetVestingParams(uint256 indexed _pid, uint256 indexed _duration, uint256 indexed _periods);
    event SetHatVestingParams(uint256 indexed _duration, uint256 indexed _periods);

    event ClaimApprove(address indexed _approver,
                    uint256 indexed _pid,
                    address indexed _beneficiary,
                    uint256 _severity,
                    address _tokenLock,
                    ClaimReward _claimReward);

    event PendingApprovalLog(uint256 indexed _pid,
                            address indexed _beneficiary,
                            uint256 indexed _severity,
                            address _approver);

    event WithdrawRequest(uint256 indexed _pid,
                        address indexed _beneficiary,
                        uint256 indexed _withdrawEnableTime);

    event SetWithdrawSafetyPeriod(uint256 indexed _withdrawPeriod, uint256 indexed _safetyPeriod);

    event RewardDepositors(uint256 indexed _pid, uint256 indexed _amount);

    /**
   * @dev constructor -
   * @param _rewardsToken the reward token address (HAT)
   * @param _rewardPerBlock the reward amount per block the contract will reward pools
   * @param _startBlock start block of of which the contract will start rewarding from.
   * @param _multiplierPeriod a fix period value. each period will have its own multiplier value.
   *        which set the reward for each period. e.g a value of 100000 means that each such period is 100000 blocks.
   * @param _hatGovernance the governance address.
   *        Some of the contracts functions are limited only to governance :
   *         addPool,setPool,dismissPendingApprovalClaim,approveClaim,
   *         setHatVestingParams,setVestingParams,setRewardsSplit
   * @param _uniSwapRouter uni swap v3 router to be used to swap tokens for HAT token.
   * @param _tokenLockFactory address of the token lock factory to be used
   *        to create a vesting contract for the approved claim reporter.
 */
    constructor(
        address _rewardsToken,
        uint256 _rewardPerBlock,
        uint256 _startBlock,
        uint256 _multiplierPeriod,
        address _hatGovernance,
        ISwapRouter _uniSwapRouter,
        ITokenLockFactory _tokenLockFactory
    // solhint-disable-next-line func-visibility
    ) HATMaster(HATToken(_rewardsToken), _rewardPerBlock, _startBlock, _multiplierPeriod) {
        Governable.initialize(_hatGovernance);
        uniSwapRouter = _uniSwapRouter;
        tokenLockFactory = _tokenLockFactory;
        generalParameters = GeneralParameters({
            hatVestingDuration: 90 days,
            hatVestingPeriods:90,
            withdrawPeriod: 11 hours,
            safetyPeriod: 1 hours,
            setRewardsLevelsDelay: 2 days,
            withdrawRequestEnablePeriod: 7 days,
            withdrawRequestPendingPeriod: 7 days,
            claimFee: 0
        });
    }

      /**
     * @dev pendingApprovalClaim - called by a committee to set a pending approval claim.
     * The pending approval need to be approved or dismissed  by the hats governance.
     * This function should be called only on a safety period, where withdrawn is disable.
     * Upon a call to this function by the committee the pool withdrawn will be disable
     * till governance will approve or dismiss this pending approval.
     * @param _pid pool id
     * @param _beneficiary the approval claim beneficiary
     * @param _severity approval claim severity
   */
    function pendingApprovalClaim(uint256 _pid, address _beneficiary, uint256 _severity)
    external
    onlyCommittee(_pid)
    noPendingApproval(_pid) {
        require(_beneficiary != address(0), "beneficiary is zero");
        // solhint-disable-next-line not-rely-on-time
        require(block.timestamp % (generalParameters.withdrawPeriod + generalParameters.safetyPeriod) >=
        generalParameters.withdrawPeriod,
        "none safety period");
        require(_severity < poolsRewards[_pid].rewardsLevels.length, "_severity is not in the range");

        pendingApprovals[_pid] = PendingApproval({
            beneficiary: _beneficiary,
            severity: _severity,
            approver: msg.sender
        });
        emit PendingApprovalLog(_pid, _beneficiary, _severity, msg.sender);
    }

    /**
     * @dev setWithdrawRequestParams - called by hats governance to set withdraw request params
     * @param _withdrawRequestPendingPeriod - the time period where the withdraw request is pending.
     * @param _withdrawRequestEnablePeriod - the time period where the withdraw is enable for a withdraw request.
    */
    function setWithdrawRequestParams(uint256 _withdrawRequestPendingPeriod, uint256  _withdrawRequestEnablePeriod)
    external
    onlyGovernance {
        generalParameters.withdrawRequestPendingPeriod = _withdrawRequestPendingPeriod;
        generalParameters.withdrawRequestEnablePeriod = _withdrawRequestEnablePeriod;
    }

  /**
   * @dev dismissPendingApprovalClaim - called by hats governance to dismiss a pending approval claim.
   * @param _pid pool id
  */
    function dismissPendingApprovalClaim(uint256 _pid) external onlyGovernance {
        delete pendingApprovals[_pid];
    }

    /**
   * @dev approveClaim - called by hats governance to approve a pending approval claim.
   * @param _pid pool id
 */
    function approveClaim(uint256 _pid) external onlyGovernance nonReentrant {
        require(pendingApprovals[_pid].beneficiary != address(0), "no pending approval");
        PoolReward storage poolReward = poolsRewards[_pid];
        PendingApproval memory pendingApproval = pendingApprovals[_pid];
        delete pendingApprovals[_pid];

        IERC20 lpToken = poolInfo[_pid].lpToken;
        ClaimReward memory claimRewards = calcClaimRewards(_pid, pendingApproval.severity);
        poolInfo[_pid].balance = poolInfo[_pid].balance.sub(
                            claimRewards.hackerReward
                            .add(claimRewards.hackerVestedReward)
                            .add(claimRewards.committeeReward)
                            .add(claimRewards.swapAndBurn)
                            .add(claimRewards.hackerHatReward)
                            .add(claimRewards.governanceHatReward));
        address tokenLock;
        if (claimRewards.hackerVestedReward > 0) {
        //hacker get its reward to a vesting contract
            tokenLock = tokenLockFactory.createTokenLock(
            address(lpToken),
            0x000000000000000000000000000000000000dEaD, //this address as owner, so it can do nothing.
            pendingApproval.beneficiary,
            claimRewards.hackerVestedReward,
            // solhint-disable-next-line not-rely-on-time
            block.timestamp, //start
            // solhint-disable-next-line not-rely-on-time
            block.timestamp + poolReward.vestingDuration, //end
            poolReward.vestingPeriods,
            0, //no release start
            0, //no cliff
            ITokenLock.Revocability.Disabled,
            false
        );
            lpToken.safeTransfer(tokenLock, claimRewards.hackerVestedReward);
        }
        lpToken.safeTransfer(pendingApproval.beneficiary, claimRewards.hackerReward);
        lpToken.safeTransfer(pendingApproval.approver, claimRewards.committeeReward);
        //storing the amount of token which can be swap and burned so it could be swapAndBurn in a seperate tx.
        swapAndBurns[address(lpToken)] = swapAndBurns[address(lpToken)].add(claimRewards.swapAndBurn);
        governanceHatRewards[address(lpToken)] =
        governanceHatRewards[address(lpToken)].add(claimRewards.governanceHatReward);
        hackersHatRewards[pendingApproval.beneficiary][address(lpToken)] =
        hackersHatRewards[pendingApproval.beneficiary][address(lpToken)].add(claimRewards.hackerHatReward);

        emit ClaimApprove(msg.sender,
                        _pid,
                        pendingApproval.beneficiary,
                        pendingApproval.severity,
                        tokenLock,
                        claimRewards);
        assert(poolInfo[_pid].balance > 0);
    }

    /**
     * @dev rewardDepositors - add funds to pool to reward depositors.
     * The funds will be given to depositors pro rata upon withdraw
     * @param _pid pool id
     * @param _amount amount to add
    */
    function rewardDepositors(uint256 _pid, uint256 _amount) external {
        require(poolInfo[_pid].balance.add(_amount).div(MINIMUM_DEPOSIT) < poolInfo[_pid].totalUsersAmount,
        "amount to reward is too big");
        poolInfo[_pid].lpToken.safeTransferFrom(msg.sender, address(this), _amount);
        poolInfo[_pid].balance = poolInfo[_pid].balance.add(_amount);
        emit RewardDepositors(_pid, _amount);
    }

    /**
     * @dev setClaimFee - called by hats governance to set claim fee
     * @param _fee claim fee in ETH
    */
    function setClaimFee(uint256 _fee) external onlyGovernance {
        generalParameters.claimFee = _fee;
    }

    /**
     * @dev setWithdrawSafetyPeriod - called by hats governance to set Withdraw Period
     * @param _withdrawPeriod withdraw enable period
     * @param _safetyPeriod withdraw disable period
    */
    function setWithdrawSafetyPeriod(uint256 _withdrawPeriod, uint256 _safetyPeriod) external onlyGovernance {
        generalParameters.withdrawPeriod = _withdrawPeriod;
        generalParameters.safetyPeriod = _safetyPeriod;
        emit SetWithdrawSafetyPeriod(generalParameters.withdrawPeriod, generalParameters.safetyPeriod);
    }

    //_descriptionHash - a hash of an ipfs encrypted file which describe the claim.
    // this can be use later on by the claimer to prove her claim
    function claim(string memory _descriptionHash) external payable {
        if (generalParameters.claimFee > 0) {
            require(msg.value >= generalParameters.claimFee, "not enough fee payed");
            // solhint-disable-next-line indent
            payable(governance()).transfer(msg.value);
        }
        emit Claim(msg.sender, _descriptionHash);
    }

    /**
   * @dev setVestingParams - set pool vesting params for rewarding claim reporter with the pool token
   * @param _pid pool id
   * @param _duration duration of the vesting period
   * @param _periods the vesting periods
 */
    function setVestingParams(uint256 _pid, uint256 _duration, uint256 _periods) external onlyGovernance {
        require(_duration < 120 days, "vesting duration is too long");
        require(_periods > 0, "vesting periods cannot be zero");
        require(_duration >= _periods, "vesting duration smaller than periods");
        poolsRewards[_pid].vestingDuration = _duration;
        poolsRewards[_pid].vestingPeriods = _periods;
        emit SetVestingParams(_pid, _duration, _periods);
    }

    /**
   * @dev setHatVestingParams - set HAT vesting params for rewarding claim reporter with HAT token
   * the function can be called only by governance.
   * @param _duration duration of the vesting period
   * @param _periods the vesting periods
 */
    function setHatVestingParams(uint256 _duration, uint256 _periods) external onlyGovernance {
        require(_duration < 180 days, "vesting duration is too long");
        require(_periods > 0, "vesting periods cannot be zero");
        require(_duration >= _periods, "vesting duration smaller than periods");
        generalParameters.hatVestingDuration = _duration;
        generalParameters.hatVestingPeriods = _periods;
        emit SetHatVestingParams(_duration, _periods);
    }

    /**
   * @dev setRewardsSplit - set the pool token rewards split upon an approval
   * the function can be called only by governance.
   * the sum of the rewards split should be less than 10000 (less than 100%)
   * @param _pid pool id
   * @param _rewardsSplit split
   * and sent to the hacker(claim reported)
 */
    function setRewardsSplit(uint256 _pid, RewardsSplit memory _rewardsSplit)
    external
    onlyGovernance noPendingApproval(_pid) noSafetyPeriod {
        validateSplit(_rewardsSplit);
        poolsRewards[_pid].rewardsSplit = _rewardsSplit;
        emit SetRewardsSplit(_pid, _rewardsSplit);
    }

    /**
   * @dev setRewardsLevelsDelay - set the timelock delay for setting rewars level
   * @param _delay time delay
 */
    function setRewardsLevelsDelay(uint256 _delay)
    external
    onlyGovernance {
        require(_delay >= 2 days, "delay is too short");
        generalParameters.setRewardsLevelsDelay = _delay;
    }

    /**
   * @dev setPendingRewardsLevels - set pending request to set pool token rewards level.
   * the reward level represent the percentage of the pool's token which will be split as a reward.
   * the function can be called only by the pool committee.
   * cannot be called if there already pending approval.
   * each level should be less than 10000
   * @param _pid pool id
   * @param _rewardsLevels the reward levels array
 */
    function setPendingRewardsLevels(uint256 _pid, uint256[] memory _rewardsLevels)
    external
    onlyCommittee(_pid) noPendingApproval(_pid) {
        pendingRewardsLevels[_pid].rewardsLevels = checkRewardsLevels(_rewardsLevels);
        // solhint-disable-next-line not-rely-on-time
        pendingRewardsLevels[_pid].timestamp = block.timestamp;
        emit PendingRewardsLevelsLog(_pid, _rewardsLevels, pendingRewardsLevels[_pid].timestamp);
    }

  /**
   * @dev setRewardsLevels - set the pool token rewards level of already pending set rewards level.
   * see pendingRewardsLevels
   * the reward level represent the percentage of the pool's token which will be split as a reward.
   * the function can be called only by the pool committee.
   * cannot be called if there already pending approval.
   * each level should be less than 10000
   * @param _pid pool id
 */
    function setRewardsLevels(uint256 _pid)
    external
    onlyCommittee(_pid) noPendingApproval(_pid) {
        require(pendingRewardsLevels[_pid].timestamp > 0, "no pending set rewards levels");
        // solhint-disable-next-line not-rely-on-time
        require(block.timestamp - pendingRewardsLevels[_pid].timestamp > generalParameters.setRewardsLevelsDelay,
        "cannot confirm setRewardsLevels at this time");
        poolsRewards[_pid].rewardsLevels = pendingRewardsLevels[_pid].rewardsLevels;
        delete pendingRewardsLevels[_pid];
        emit SetRewardsLevels(_pid, poolsRewards[_pid].rewardsLevels);
    }

    /**
   * @dev committeeCheckIn - committee check in.
   * deposit is enable only after committee check in
   * @param _pid pool id
 */
    function committeeCheckIn(uint256 _pid) external onlyCommittee(_pid) {
        poolsRewards[_pid].committeeCheckIn = true;
    }


    /**
   * @dev setCommittee - set new committee address.
   * @param _pid pool id
   * @param _committee new committee address
 */
    function setCommittee(uint256 _pid, address _committee)
    external {
        require(_committee != address(0), "committee is zero");
        //governance can update committee only if committee was not checked in yet.
        if (msg.sender == governance() && committees[_pid] != msg.sender) {
            require(!poolsRewards[_pid].committeeCheckIn, "Committee already checked in");
        } else {
            require(committees[_pid] == msg.sender, "Only committee");
        }

        committees[_pid] = _committee;

        emit SetCommittee(_pid, _committee);
    }

    /**
   * @dev addPool - only Governance
   * @param _allocPoint the pool allocation point
   * @param _lpToken pool token
   * @param _committee pool committee address
   * @param _rewardsLevels pool reward levels(sevirities)
     each level is a number between 0 and 10000.
   * @param _rewardsSplit pool reward split.
     each entry is a number between 0 and 10000.
     total splits should be equal to 10000
   * @param _descriptionHash the hash of the pool description.
   * @param _rewardVestingParams vesting params
   *        _rewardVestingParams[0] - vesting duration
   *        _rewardVestingParams[1] - vesting periods
 */
    function addPool(uint256 _allocPoint,
                    address _lpToken,
                    address _committee,
                    uint256[] memory _rewardsLevels,
                    RewardsSplit memory _rewardsSplit,
                    string memory _descriptionHash,
                    uint256[2] memory _rewardVestingParams)
    external
    onlyGovernance {
        require(_rewardVestingParams[0] < 120 days, "vesting duration is too long");
        require(_rewardVestingParams[1] > 0, "vesting periods cannot be zero");
        require(_rewardVestingParams[0] >= _rewardVestingParams[1], "vesting duration smaller than periods");
        require(_committee != address(0), "committee is zero");
        add(_allocPoint, IERC20(_lpToken));
        uint256 poolId = poolInfo.length-1;
        committees[poolId] = _committee;
        uint256[] memory rewardsLevels = checkRewardsLevels(_rewardsLevels);

        RewardsSplit memory rewardsSplit = (_rewardsSplit.hackerVestedReward == 0 && _rewardsSplit.hackerReward == 0) ?
        getDefaultRewardsSplit() : _rewardsSplit;

        validateSplit(rewardsSplit);
        poolsRewards[poolId] = PoolReward({
            rewardsLevels: rewardsLevels,
            rewardsSplit: rewardsSplit,
            committeeCheckIn: false,
            vestingDuration: _rewardVestingParams[0],
            vestingPeriods: _rewardVestingParams[1]
        });

        emit AddPool(poolId,
                    _allocPoint,
                    address(_lpToken),
                    _committee,
                    _descriptionHash,
                    rewardsLevels,
                    rewardsSplit,
                    _rewardVestingParams[0],
                    _rewardVestingParams[1]);
    }

    /**
   * @dev setPool
   * @param _pid the pool id
   * @param _allocPoint the pool allocation point
   * @param _registered does this pool is registered (default true).
   * @param _depositPause pause pool deposit (default false).
   * This parameter can be used by the UI to include or exclude the pool
   * @param _descriptionHash the hash of the pool description.
 */
    function setPool(uint256 _pid,
                    uint256 _allocPoint,
                    bool _registered,
                    bool _depositPause,
                    string memory _descriptionHash)
    external onlyGovernance {
        require(poolInfo[_pid].lpToken != IERC20(address(0)), "pool does not exist");
        set(_pid, _allocPoint);
        poolDepositPause[_pid] = _depositPause;
        emit SetPool(_pid, _allocPoint, _registered, _descriptionHash);
    }

    /**
    * @dev swapBurnSend swap lptoken to HAT.
    * send to beneficiary and governance its hats rewards .
    * burn the rest of HAT.
    * only governance are authorized to call this function.
    * @param _pid the pool id
    * @param _beneficiary beneficiary
    * @param _amountOutMinimum minimum output of HATs at swap
    * @param _fees the fees for the multi path swap
    **/
    function swapBurnSend(uint256 _pid,
                        address _beneficiary,
                        uint256 _amountOutMinimum,
                        uint24[2] memory _fees)
    external
    onlyGovernance {
        IERC20 token = poolInfo[_pid].lpToken;
        uint256 amountToSwapAndBurn = swapAndBurns[address(token)];
        uint256 amountForHackersHatRewards = hackersHatRewards[_beneficiary][address(token)];
        uint256 amount = amountToSwapAndBurn.add(amountForHackersHatRewards).add(governanceHatRewards[address(token)]);
        require(amount > 0, "amount is zero");
        swapAndBurns[address(token)] = 0;
        governanceHatRewards[address(token)] = 0;
        hackersHatRewards[_beneficiary][address(token)] = 0;
        uint256 hatsReceived = swapTokenForHAT(amount, token, _fees, _amountOutMinimum);
        uint256 burntHats = hatsReceived.mul(amountToSwapAndBurn).div(amount);
        if (burntHats > 0) {
            HAT.burn(burntHats);
        }
        emit SwapAndBurn(_pid, amount, burntHats);
        address tokenLock;
        uint256 hackerReward = hatsReceived.mul(amountForHackersHatRewards).div(amount);
        if (hackerReward > 0) {
           //hacker get its reward via vesting contract
            tokenLock = tokenLockFactory.createTokenLock(
                address(HAT),
                0x000000000000000000000000000000000000dEaD, //this address as owner, so it can do nothing.
                _beneficiary,
                hackerReward,
                // solhint-disable-next-line not-rely-on-time
                block.timestamp, //start
                // solhint-disable-next-line not-rely-on-time
                block.timestamp + generalParameters.hatVestingDuration, //end
                generalParameters.hatVestingPeriods,
                0, //no release start
                0, //no cliff
                ITokenLock.Revocability.Disabled,
                true
            );
            HAT.transfer(tokenLock, hackerReward);
        }
        emit SwapAndSend(_pid, _beneficiary, amount, hackerReward, tokenLock);
        HAT.transfer(governance(), hatsReceived.sub(hackerReward).sub(burntHats));
    }

    /**
    * @dev withdrawRequest submit a withdraw request
    * @param _pid the pool id
    **/
    function withdrawRequest(uint256 _pid) external {
      // solhint-disable-next-line not-rely-on-time
        require(block.timestamp > withdrawRequests[_pid][msg.sender] + generalParameters.withdrawRequestEnablePeriod,
        "pending withdraw request exist");
        // solhint-disable-next-line not-rely-on-time
        withdrawRequests[_pid][msg.sender] = block.timestamp + generalParameters.withdrawRequestPendingPeriod;
        emit WithdrawRequest(_pid, msg.sender, withdrawRequests[_pid][msg.sender]);
    }

    /**
    * @dev deposit deposit to pool
    * @param _pid the pool id
    * @param _amount amount of pool's token to deposit
    **/
    function deposit(uint256 _pid, uint256 _amount) external {
        require(!poolDepositPause[_pid], "deposit paused");
        require(_amount >= MINIMUM_DEPOSIT, "amount less than 1e6");
        //clear withdraw request
        withdrawRequests[_pid][msg.sender] = 0;
        _deposit(_pid, _amount);
    }

    /**
    * @dev withdraw  - withdraw user's pool share.
    * user need first to submit a withdraw request.
    * @param _pid the pool id
    * @param _shares amount of shares user wants to withdraw
    **/
    function withdraw(uint256 _pid, uint256 _shares) external {
        checkWithdrawRequest(_pid);
        _withdraw(_pid, _shares);
    }

    /**
    * @dev emergencyWithdraw withdraw all user's pool share without claim for reward.
    * user need first to submit a withdraw request.
    * @param _pid the pool id
    **/
    function emergencyWithdraw(uint256 _pid) external {
        checkWithdrawRequest(_pid);
        _emergencyWithdraw(_pid);
    }

    function getPoolRewardsLevels(uint256 _pid) external view returns(uint256[] memory) {
        return poolsRewards[_pid].rewardsLevels;
    }

    function getPoolRewards(uint256 _pid) external view returns(PoolReward memory) {
        return poolsRewards[_pid];
    }

    // GET INFO for UI
    /**
    * @dev getRewardPerBlock return the current pool reward per block
    * @param _pid1 the pool id.
    *        if _pid1 = 0 , it return the current block reward for whole pools.
    *        otherwise it return the current block reward for _pid1-1.
    * @return rewardPerBlock
    **/
    function getRewardPerBlock(uint256 _pid1) external view returns (uint256) {
        if (_pid1 == 0) {
            return getRewardForBlocksRange(block.number-1, block.number, 1, 1);
        } else {
            return getRewardForBlocksRange(block.number-1,
                                        block.number,
                                        poolInfo[_pid1 - 1].allocPoint,
                                        globalPoolUpdates[globalPoolUpdates.length-1].totalAllocPoint);
        }
    }

    function pendingReward(uint256 _pid, address _user) external view returns (uint256) {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][_user];
        uint256 rewardPerShare = pool.rewardPerShare;

        if (block.number > pool.lastRewardBlock && pool.totalUsersAmount > 0) {
            uint256 reward = calcPoolReward(_pid, pool.lastRewardBlock, globalPoolUpdates.length-1);
            rewardPerShare = rewardPerShare.add(reward.mul(1e12).div(pool.totalUsersAmount));
        }
        return user.amount.mul(rewardPerShare).div(1e12).sub(user.rewardDebt);
    }

    function getGlobalPoolUpdatesLength() external view returns (uint256) {
        return globalPoolUpdates.length;
    }

    function getStakedAmount(uint _pid, address _user) external view returns (uint256) {
        UserInfo storage user = userInfo[_pid][_user];
        return  user.amount;
    }

    function poolLength() external view returns (uint256) {
        return poolInfo.length;
    }

    function calcClaimRewards(uint256 _pid, uint256 _severity)
    public
    view
    returns(ClaimReward memory claimRewards) {
        uint256 totalSupply = poolInfo[_pid].balance;
        require(totalSupply > 0, "totalSupply is zero");
        require(_severity < poolsRewards[_pid].rewardsLevels.length, "_severity is not in the range");
        //hackingRewardAmount
        uint256 claimRewardAmount =
        totalSupply.mul(poolsRewards[_pid].rewardsLevels[_severity]);
        claimRewards.hackerVestedReward =
        claimRewardAmount.mul(poolsRewards[_pid].rewardsSplit.hackerVestedReward)
        .div(REWARDS_LEVEL_DENOMINATOR*REWARDS_LEVEL_DENOMINATOR);
        claimRewards.hackerReward =
        claimRewardAmount.mul(poolsRewards[_pid].rewardsSplit.hackerReward)
        .div(REWARDS_LEVEL_DENOMINATOR*REWARDS_LEVEL_DENOMINATOR);
        claimRewards.committeeReward =
        claimRewardAmount.mul(poolsRewards[_pid].rewardsSplit.committeeReward)
        .div(REWARDS_LEVEL_DENOMINATOR*REWARDS_LEVEL_DENOMINATOR);
        claimRewards.swapAndBurn =
        claimRewardAmount.mul(poolsRewards[_pid].rewardsSplit.swapAndBurn)
        .div(REWARDS_LEVEL_DENOMINATOR*REWARDS_LEVEL_DENOMINATOR);
        claimRewards.governanceHatReward =
        claimRewardAmount.mul(poolsRewards[_pid].rewardsSplit.governanceHatReward)
        .div(REWARDS_LEVEL_DENOMINATOR*REWARDS_LEVEL_DENOMINATOR);
        claimRewards.hackerHatReward =
        claimRewardAmount.mul(poolsRewards[_pid].rewardsSplit.hackerHatReward)
        .div(REWARDS_LEVEL_DENOMINATOR*REWARDS_LEVEL_DENOMINATOR);
    }

    function getDefaultRewardsSplit() public pure returns (RewardsSplit memory) {
        return RewardsSplit({
            hackerVestedReward: 6000,
            hackerReward: 2000,
            committeeReward: 500,
            swapAndBurn: 0,
            governanceHatReward: 1000,
            hackerHatReward: 500
        });
    }

    function validateSplit(RewardsSplit memory _rewardsSplit) internal pure {
        require(_rewardsSplit.hackerVestedReward
            .add(_rewardsSplit.hackerReward)
            .add(_rewardsSplit.committeeReward)
            .add(_rewardsSplit.swapAndBurn)
            .add(_rewardsSplit.governanceHatReward)
            .add(_rewardsSplit.hackerHatReward) == REWARDS_LEVEL_DENOMINATOR,
        "total split % should be 10000");
    }

    function checkWithdrawRequest(uint256 _pid) internal noPendingApproval(_pid) noSafetyPeriod {
      // solhint-disable-next-line not-rely-on-time
        require(block.timestamp > withdrawRequests[_pid][msg.sender] &&
      // solhint-disable-next-line not-rely-on-time
                block.timestamp < withdrawRequests[_pid][msg.sender] + generalParameters.withdrawRequestEnablePeriod,
                "withdraw request not valid");
        withdrawRequests[_pid][msg.sender] = 0;
    }

    function swapTokenForHAT(uint256 _amount,
                            IERC20 _token,
                            uint24[2] memory _fees,
                            uint256 _amountOutMinimum)
    internal
    returns (uint256 hatsReceived)
    {
        if (address(_token) == address(HAT)) {
            return _amount;
        }
        require(_token.approve(address(uniSwapRouter), _amount), "token approve failed");
        uint256 hatBalanceBefore = HAT.balanceOf(address(this));
        address weth = uniSwapRouter.WETH9();
        bytes memory path;
        if (address(_token) == weth) {
            path = abi.encodePacked(address(_token), _fees[0], address(HAT));
        } else {
            path = abi.encodePacked(address(_token), _fees[0], weth, _fees[1], address(HAT));
        }
        hatsReceived = uniSwapRouter.exactInput(ISwapRouter.ExactInputParams({
            path: path,
            recipient: address(this),
            // solhint-disable-next-line not-rely-on-time
            deadline: block.timestamp,
            amountIn: _amount,
            amountOutMinimum: _amountOutMinimum
        }));
        require(HAT.balanceOf(address(this)) - hatBalanceBefore >= _amountOutMinimum, "wrong amount received");
    }

    /**
   * @dev checkRewardsLevels - check rewards levels.
   * each level should be less than 10000
   * if _rewardsLevels length is 0 a default reward levels will be return
   * default reward levels = [2000, 4000, 6000, 8000]
   * @param _rewardsLevels the reward levels array
   * @return rewardsLevels
 */
    function checkRewardsLevels(uint256[] memory _rewardsLevels)
    private
    pure
    returns (uint256[] memory rewardsLevels) {

        uint256 i;
        if (_rewardsLevels.length == 0) {
            rewardsLevels = new uint256[](4);
            for (i; i < 4; i++) {
              //defaultRewardLevels = [2000, 4000, 6000, 8000];
                rewardsLevels[i] = 2000*(i+1);
            }
        } else {
            for (i; i < _rewardsLevels.length; i++) {
                require(_rewardsLevels[i] < REWARDS_LEVEL_DENOMINATOR, "reward level can not be more than 10000");
            }
            rewardsLevels = _rewardsLevels;
        }
    }
}

File 2 of 15 : ISwapRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
    }
    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);

    // solhint-disable-next-line func-name-mixedcase
    function WETH9() external pure returns (address);
}

File 3 of 15 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.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 SafeERC20 {
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 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(IERC20 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'
        // solhint-disable-next-line max-line-length
        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));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @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(IERC20 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");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 4 of 15 : ERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The defaut value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        _approve(sender, _msgSender(), currentAllowance - amount);

        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        _approve(_msgSender(), spender, currentAllowance - subtractedValue);

        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        _balances[sender] = senderBalance - amount;
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        _balances[account] = accountBalance - amount;
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}

File 5 of 15 : HATMaster.sol
// SPDX-License-Identifier: MIT
// Disclaimer https://github.com/hats-finance/hats-contracts/blob/main/DISCLAIMER.md

pragma solidity 0.8.6;


import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol";
import "openzeppelin-solidity/contracts/utils/math/SafeMath.sol";
import "./HATToken.sol";
import "openzeppelin-solidity/contracts/security/ReentrancyGuard.sol";


contract HATMaster is ReentrancyGuard {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    struct UserInfo {
        uint256 amount;     // The user share of the pool based on the amount of lpToken the user has provided.
        uint256 rewardDebt; // Reward debt. See explanation below.
      //
      // We do some fancy math here. Basically, any point in time, the amount of HATs
      // entitled to a user but is pending to be distributed is:
      //
      //   pending reward = (user.amount * pool.rewardPerShare) - user.rewardDebt
      //
      // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
      //   1. The pool's `rewardPerShare` (and `lastRewardBlock`) gets updated.
      //   2. User receives the pending reward sent to his/her address.
      //   3. User's `amount` gets updated.
      //   4. User's `rewardDebt` gets updated.
    }

    struct PoolUpdate {
        uint256 blockNumber;// update blocknumber
        uint256 totalAllocPoint; //totalAllocPoint
    }

    struct RewardsSplit {
        //the percentage of the total reward to reward the hacker via vesting contract(claim reported)
        uint256 hackerVestedReward;
        //the percentage of the total reward to reward the hacker(claim reported)
        uint256 hackerReward;
        // the percentage of the total reward to be sent to the committee
        uint256 committeeReward;
        // the percentage of the total reward to be swap to HAT and to be burned
        uint256 swapAndBurn;
        // the percentage of the total reward to be swap to HAT and sent to governance
        uint256 governanceHatReward;
        // the percentage of the total reward to be swap to HAT and sent to the hacker
        uint256 hackerHatReward;
    }

    // Info of each pool.
    struct PoolInfo {
        IERC20 lpToken;
        uint256 allocPoint;
        uint256 lastRewardBlock;
        uint256 rewardPerShare;
        uint256 totalUsersAmount;
        uint256 lastProcessedTotalAllocPoint;
        uint256 balance;
    }

    // Info of each pool.
    struct PoolReward {
        RewardsSplit rewardsSplit;
        uint256[]  rewardsLevels;
        bool committeeCheckIn;
        uint256 vestingDuration;
        uint256 vestingPeriods;
    }

    HATToken public immutable HAT;
    uint256 public immutable REWARD_PER_BLOCK;
    uint256 public immutable START_BLOCK;
    uint256 public immutable MULTIPLIER_PERIOD;

    // Info of each pool.
    PoolInfo[] public poolInfo;
    PoolUpdate[] public globalPoolUpdates;
    mapping(address => uint256) public poolId1; // poolId1 count from 1, subtraction 1 before using with poolInfo
    // Info of each user that stakes LP tokens. pid => user address => info
    mapping (uint256 => mapping (address => UserInfo)) public userInfo;
    //pid -> PoolReward
    mapping (uint256=>PoolReward) internal poolsRewards;

    event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
    event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
    event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
    event SendReward(address indexed user, uint256 indexed pid, uint256 amount, uint256 requestedAmount);
    event MassUpdatePools(uint256 _fromPid, uint256 _toPid);

    constructor(
        HATToken _hat,
        uint256 _rewardPerBlock,
        uint256 _startBlock,
        uint256 _multiplierPeriod
    // solhint-disable-next-line func-visibility
    ) {
        HAT = _hat;
        REWARD_PER_BLOCK = _rewardPerBlock;
        START_BLOCK = _startBlock;
        MULTIPLIER_PERIOD = _multiplierPeriod;
    }

  /**
   * @dev massUpdatePools - Update reward variables for all pools
   * Be careful of gas spending!
   * @param _fromPid update pools range from this pool id
   * @param _toPid update pools range to this pool id
   */
    function massUpdatePools(uint256 _fromPid, uint256 _toPid) external {
        require(_toPid <= poolInfo.length, "pool range is too big");
        require(_fromPid <= _toPid, "invalid pool range");
        for (uint256 pid = _fromPid; pid < _toPid; ++pid) {
            updatePool(pid);
        }
        emit MassUpdatePools(_fromPid, _toPid);
    }

    function claimReward(uint256 _pid) external {
        _deposit(_pid, 0);
    }

    function updatePool(uint256 _pid) public {
        PoolInfo storage pool = poolInfo[_pid];
        uint256 lastRewardBlock = pool.lastRewardBlock;
        if (block.number <= lastRewardBlock) {
            return;
        }
        uint256 totalUsersAmount = pool.totalUsersAmount;
        uint256 lastPoolUpdate = globalPoolUpdates.length-1;
        if (totalUsersAmount == 0) {
            pool.lastRewardBlock = block.number;
            pool.lastProcessedTotalAllocPoint = lastPoolUpdate;
            return;
        }
        uint256 reward = calcPoolReward(_pid, lastRewardBlock, lastPoolUpdate);
        uint256 amountCanMint = HAT.minters(address(this));
        reward = amountCanMint < reward ? amountCanMint : reward;
        if (reward > 0) {
            HAT.mint(address(this), reward);
        }
        pool.rewardPerShare = pool.rewardPerShare.add(reward.mul(1e12).div(totalUsersAmount));
        pool.lastRewardBlock = block.number;
        pool.lastProcessedTotalAllocPoint = lastPoolUpdate;
    }

    /**
     * @dev getMultiplier - multiply blocks with relevant multiplier for specific range
     * @param _from range's from block
     * @param _to range's to block
     * will revert if from < START_BLOCK or _to < _from
     */
    function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256 result) {
        uint256[25] memory rewardMultipliers = [uint256(4413), 4413, 8825, 7788, 6873, 6065,
                                            5353, 4724, 4169, 3679, 3247, 2865,
                                            2528, 2231, 1969, 1738, 1534, 1353,
                                            1194, 1054, 930, 821, 724, 639, 0];
        uint256 max = rewardMultipliers.length;
        uint256 i = (_from - START_BLOCK) / MULTIPLIER_PERIOD + 1;
        for (; i < max; i++) {
            uint256 endBlock = MULTIPLIER_PERIOD * i + START_BLOCK;
            if (_to <= endBlock) {
                break;
            }
            result += (endBlock - _from) * rewardMultipliers[i-1];
            _from = endBlock;
        }
        result += (_to - _from) * rewardMultipliers[i > max ? (max-1) : (i-1)];
    }

    function getRewardForBlocksRange(uint256 _from, uint256 _to, uint256 _allocPoint, uint256 _totalAllocPoint)
    public
    view
    returns (uint256 reward) {
        if (_totalAllocPoint > 0) {
            reward = getMultiplier(_from, _to).mul(REWARD_PER_BLOCK).mul(_allocPoint).div(_totalAllocPoint).div(100);
        }
    }

    /**
     * @dev calcPoolReward -
     * calculate rewards for a pool by iterating over the history of totalAllocPoints updates.
     * and sum up all rewards periods from pool.lastRewardBlock till current block number.
     * @param _pid pool id
     * @param _from block starting calculation
     * @param _lastPoolUpdate lastPoolUpdate
     * @return reward
     */
    function calcPoolReward(uint256 _pid, uint256 _from, uint256 _lastPoolUpdate) public view returns(uint256 reward) {
        uint256 poolAllocPoint = poolInfo[_pid].allocPoint;
        uint256 i = poolInfo[_pid].lastProcessedTotalAllocPoint;
        for (; i < _lastPoolUpdate; i++) {
            uint256 nextUpdateBlock = globalPoolUpdates[i+1].blockNumber;
            reward =
            reward.add(getRewardForBlocksRange(_from,
                                            nextUpdateBlock,
                                            poolAllocPoint,
                                            globalPoolUpdates[i].totalAllocPoint));
            _from = nextUpdateBlock;
        }
        return reward.add(getRewardForBlocksRange(_from,
                                                block.number,
                                                poolAllocPoint,
                                                globalPoolUpdates[i].totalAllocPoint));
    }

    function _deposit(uint256 _pid, uint256 _amount) internal nonReentrant {
        require(poolsRewards[_pid].committeeCheckIn, "committee not checked in yet");
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        updatePool(_pid);
        if (user.amount > 0) {
            uint256 pending = user.amount.mul(pool.rewardPerShare).div(1e12).sub(user.rewardDebt);
            if (pending > 0) {
                safeTransferReward(msg.sender, pending, _pid);
            }
        }
        if (_amount > 0) {
            uint256 lpSupply = pool.balance;
            pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
            pool.balance = pool.balance.add(_amount);
            uint256 factoredAmount = _amount;
            if (pool.totalUsersAmount > 0) {
                factoredAmount = pool.totalUsersAmount.mul(_amount).div(lpSupply);
            }
            user.amount = user.amount.add(factoredAmount);
            pool.totalUsersAmount = pool.totalUsersAmount.add(factoredAmount);
        }
        user.rewardDebt = user.amount.mul(pool.rewardPerShare).div(1e12);
        emit Deposit(msg.sender, _pid, _amount);
    }

    function _withdraw(uint256 _pid, uint256 _amount) internal nonReentrant {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.amount >= _amount, "withdraw: not enough user balance");

        updatePool(_pid);
        uint256 pending = user.amount.mul(pool.rewardPerShare).div(1e12).sub(user.rewardDebt);
        if (pending > 0) {
            safeTransferReward(msg.sender, pending, _pid);
        }
        if (_amount > 0) {
            user.amount = user.amount.sub(_amount);
            uint256 amountToWithdraw = _amount.mul(pool.balance).div(pool.totalUsersAmount);
            pool.balance = pool.balance.sub(amountToWithdraw);
            pool.lpToken.safeTransfer(msg.sender, amountToWithdraw);
            pool.totalUsersAmount = pool.totalUsersAmount.sub(_amount);
        }
        user.rewardDebt = user.amount.mul(pool.rewardPerShare).div(1e12);
        emit Withdraw(msg.sender, _pid, _amount);
    }

    // Withdraw without caring about rewards. EMERGENCY ONLY.
    function _emergencyWithdraw(uint256 _pid) internal {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.amount > 0, "user.amount = 0");
        uint256 factoredBalance = user.amount.mul(pool.balance).div(pool.totalUsersAmount);
        pool.totalUsersAmount = pool.totalUsersAmount.sub(user.amount);
        user.amount = 0;
        user.rewardDebt = 0;
        pool.balance = pool.balance.sub(factoredBalance);
        pool.lpToken.safeTransfer(msg.sender, factoredBalance);
        emit EmergencyWithdraw(msg.sender, _pid, factoredBalance);
    }

    // -------- For manage pool ---------
    function add(uint256 _allocPoint, IERC20 _lpToken) internal {
        require(poolId1[address(_lpToken)] == 0, "HATMaster::add: lpToken is already in pool");
        poolId1[address(_lpToken)] = poolInfo.length + 1;
        uint256 lastRewardBlock = block.number > START_BLOCK ? block.number : START_BLOCK;
        uint256 totalAllocPoint = (globalPoolUpdates.length == 0) ? _allocPoint :
        globalPoolUpdates[globalPoolUpdates.length-1].totalAllocPoint.add(_allocPoint);

        if (globalPoolUpdates.length > 0 &&
            globalPoolUpdates[globalPoolUpdates.length-1].blockNumber == block.number) {
           //already update in this block
            globalPoolUpdates[globalPoolUpdates.length-1].totalAllocPoint = totalAllocPoint;
        } else {
            globalPoolUpdates.push(PoolUpdate({
                blockNumber: block.number,
                totalAllocPoint: totalAllocPoint
            }));
        }

        poolInfo.push(PoolInfo({
            lpToken: _lpToken,
            allocPoint: _allocPoint,
            lastRewardBlock: lastRewardBlock,
            rewardPerShare: 0,
            totalUsersAmount: 0,
            lastProcessedTotalAllocPoint: globalPoolUpdates.length-1,
            balance: 0
        }));
    }

    function set(uint256 _pid, uint256 _allocPoint) internal {
        updatePool(_pid);
        uint256 totalAllocPoint =
        globalPoolUpdates[globalPoolUpdates.length-1].totalAllocPoint
        .sub(poolInfo[_pid].allocPoint).add(_allocPoint);

        if (globalPoolUpdates[globalPoolUpdates.length-1].blockNumber == block.number) {
           //already update in this block
            globalPoolUpdates[globalPoolUpdates.length-1].totalAllocPoint = totalAllocPoint;
        } else {
            globalPoolUpdates.push(PoolUpdate({
                blockNumber: block.number,
                totalAllocPoint: totalAllocPoint
            }));
        }
        poolInfo[_pid].allocPoint = _allocPoint;
    }

    // Safe HAT transfer function, just in case if rounding error causes pool to not have enough HATs.
    function safeTransferReward(address _to, uint256 _amount, uint256 _pid) internal {
        uint256 hatBalance = HAT.balanceOf(address(this));
        if (_amount > hatBalance) {
            HAT.transfer(_to, hatBalance);
            emit SendReward(_to, _pid, hatBalance, _amount);
        } else {
            HAT.transfer(_to, _amount);
            emit SendReward(_to, _pid, _amount, _amount);
        }
    }
}

File 6 of 15 : ITokenLockFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;

import "./ITokenLock.sol";

interface ITokenLockFactory {
    // -- Factory --
    function setMasterCopy(address _masterCopy) external;

    function createTokenLock(
        address _token,
        address _owner,
        address _beneficiary,
        uint256 _managedAmount,
        uint256 _startTime,
        uint256 _endTime,
        uint256 _periods,
        uint256 _releaseStartTime,
        uint256 _vestingCliffTime,
        ITokenLock.Revocability _revocable,
        bool _canDelegate
    ) external returns(address contractAddress);
}

File 7 of 15 : Governable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.6;


/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an governance) that can be granted exclusive access to
 * specific functions.
 *
 * The governance account will be passed on initialization of the contract. This
 * can later be changed with {setPendingGovernance and then transferGovernorship  after 2 days}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyGovernance`, which can be applied to your functions to restrict their use to
 * the governance.
 */
contract Governable {
    address private _governance;
    address public governancePending;
    uint256 public setGovernancePendingAt;
    uint256 public constant TIME_LOCK_DELAY = 2 days;


    /// @notice An event thats emitted when a new governance address is set
    event GovernorshipTransferred(address indexed _previousGovernance, address indexed _newGovernance);
    /// @notice An event thats emitted when a new governance address is pending
    event GovernancePending(address indexed _previousGovernance, address indexed _newGovernance, uint256 _at);

    /**
     * @dev Throws if called by any account other than the governance.
     */
    modifier onlyGovernance() {
        require(msg.sender == _governance, "only governance");
        _;
    }

    /**
     * @dev setPendingGovernance set a pending governance address.
     * NOTE: transferGovernorship can be called after a time delay of 2 days.
     */
    function setPendingGovernance(address _newGovernance) external  onlyGovernance {
        require(_newGovernance != address(0), "Governable:new governance is the zero address");
        governancePending = _newGovernance;
        // solhint-disable-next-line not-rely-on-time
        setGovernancePendingAt = block.timestamp;
        emit GovernancePending(_governance, _newGovernance, setGovernancePendingAt);
    }

    /**
     * @dev transferGovernorship transfer governorship to the pending governance address.
     * NOTE: transferGovernorship can be called after a time delay of 2 days from the latest setPendingGovernance.
     */
    function transferGovernorship() external onlyGovernance {
        require(setGovernancePendingAt > 0, "Governable: no pending governance");
        // solhint-disable-next-line not-rely-on-time
        require(block.timestamp - setGovernancePendingAt > TIME_LOCK_DELAY,
        "Governable: cannot confirm governance at this time");
        emit GovernorshipTransferred(_governance, governancePending);
        _governance = governancePending;
        setGovernancePendingAt = 0;
    }

    /**
     * @dev Returns the address of the current governance.
     */
    function governance() public view returns (address) {
        return _governance;
    }

    /**
     * @dev Initializes the contract setting the initial governance.
     */
    function initialize(address _initialGovernance) internal {
        _governance = _initialGovernance;
        emit GovernorshipTransferred(address(0), _initialGovernance);
    }
}

File 8 of 15 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);

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

File 9 of 15 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 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://diligence.consensys.net/posts/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.5.11/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");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(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) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // 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

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 10 of 15 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 11 of 15 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/*
 * @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 Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 12 of 15 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 13 of 15 : HATToken.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;
import "openzeppelin-solidity/contracts/utils/math/SafeMath.sol";
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";


contract HATToken is IERC20 {

    struct PendingMinter {
        uint256 seedAmount;
        uint256 setMinterPendingAt;
    }

    /// @notice A checkpoint for marking number of votes from a given block
    struct Checkpoint {
        uint32 fromBlock;
        uint96 votes;
    }

    /// @notice EIP-20 token name for this token
    // solhint-disable-next-line const-name-snakecase
    string public constant name = "hats.finance";

    /// @notice EIP-20 token symbol for this token
    // solhint-disable-next-line const-name-snakecase
    string public constant symbol = "HAT";

    /// @notice EIP-20 token decimals for this token
    // solhint-disable-next-line const-name-snakecase
    uint8 public constant decimals = 18;

    /// @notice Total number of tokens in circulation
    uint public override totalSupply;

    address public governance;
    address public governancePending;
    uint256 public setGovernancePendingAt;
    uint256 public immutable timeLockDelay;
    uint256 public constant CAP = 10000000e18;

    /// @notice Address which may mint new tokens
    /// minter -> minting seedAmount
    mapping (address => uint256) public minters;

    /// @notice Address which may mint new tokens
    /// minter -> minting seedAmount
    mapping (address => PendingMinter) public pendingMinters;

    // @notice Allowance amounts on behalf of others
    mapping (address => mapping (address => uint96)) internal allowances;

    // @notice Official record of token balances for each account
    mapping (address => uint96) internal balances;

    /// @notice A record of each accounts delegate
    mapping (address => address) public delegates;

    /// @notice A record of votes checkpoints for each account, by index
    mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;

    /// @notice The number of checkpoints for each account
    mapping (address => uint32) public numCheckpoints;

    /// @notice A record of states for signing / validating signatures
    mapping (address => uint) public nonces;

    /// @notice The EIP-712 typehash for the contract's domain
    bytes32 public constant DOMAIN_TYPEHASH =
    keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");

    /// @notice The EIP-712 typehash for the delegation struct used by the contract
    bytes32 public constant DELEGATION_TYPEHASH =
    keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

    /// @notice The EIP-712 typehash for the permit struct used by the contract
    bytes32 public constant PERMIT_TYPEHASH =
    keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    /// @notice An event thats emitted when a new minter address is pending
    event MinterPending(address indexed minter, uint256 seedAmount, uint256 at);
    /// @notice An event thats emitted when the minter address is changed
    event MinterChanged(address indexed minter, uint256 seedAmount);
    /// @notice An event thats emitted when a new governance address is pending
    event GovernancePending(address indexed oldGovernance, address indexed newGovernance, uint256 at);
    /// @notice An event thats emitted when a new governance address is set
    event GovernanceChanged(address indexed oldGovernance, address indexed newGovernance);
    /// @notice An event thats emitted when an account changes its delegate
    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
    /// @notice An event thats emitted when a delegate account's vote balance changes
    event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);

    /**
     * @notice Construct a new HAT token
     */
    // solhint-disable-next-line func-visibility
    constructor(address _governance, uint256 _timeLockDelay) {
        governance = _governance;
        timeLockDelay = _timeLockDelay;
    }

    function setPendingGovernance(address _governance) external {
        require(msg.sender == governance, "HAT:!governance");
        require(_governance != address(0), "HAT:!_governance");
        governancePending = _governance;
        // solhint-disable-next-line not-rely-on-time
        setGovernancePendingAt = block.timestamp;
        emit GovernancePending(governance, _governance, setGovernancePendingAt);
    }

    function confirmGovernance() external {
        require(msg.sender == governance, "HAT:!governance");
        require(setGovernancePendingAt > 0, "HAT:!governancePending");
        // solhint-disable-next-line not-rely-on-time
        require(block.timestamp - setGovernancePendingAt > timeLockDelay,
        "HAT: cannot confirm governance at this time");
        emit GovernanceChanged(governance, governancePending);
        governance = governancePending;
        setGovernancePendingAt = 0;
    }

    function setPendingMinter(address _minter, uint256 _cap) external {
        require(msg.sender == governance, "HAT::!governance");
        pendingMinters[_minter].seedAmount = _cap;
        // solhint-disable-next-line not-rely-on-time
        pendingMinters[_minter].setMinterPendingAt = block.timestamp;
        emit MinterPending(_minter, _cap, pendingMinters[_minter].setMinterPendingAt);
    }

    function confirmMinter(address _minter) external {
        require(msg.sender == governance, "HAT::mint: only the governance can confirm minter");
        require(pendingMinters[_minter].setMinterPendingAt > 0, "HAT:: no pending minter was set");
        // solhint-disable-next-line not-rely-on-time
        require(block.timestamp - pendingMinters[_minter].setMinterPendingAt > timeLockDelay,
        "HATToken: cannot confirm at this time");
        minters[_minter] = pendingMinters[_minter].seedAmount;
        pendingMinters[_minter].setMinterPendingAt = 0;
        emit MinterChanged(_minter, pendingMinters[_minter].seedAmount);
    }

    function burn(uint256 _amount) external {
        return _burn(msg.sender, _amount);
    }

    function mint(address _account, uint _amount) external {
        require(minters[msg.sender] >= _amount, "HATToken: amount greater than limitation");
        minters[msg.sender] = SafeMath.sub(minters[msg.sender], _amount);
        _mint(_account, _amount);
    }

    /**
     * @notice Get the number of tokens `spender` is approved to spend on behalf of `account`
     * @param account The address of the account holding the funds
     * @param spender The address of the account spending the funds
     * @return The number of tokens approved
     */
    function allowance(address account, address spender) external override view returns (uint) {
        return allowances[account][spender];
    }

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
     * @param spender The address of the account which may transfer tokens
     * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
     * @return Whether or not the approval succeeded
     */
    function approve(address spender, uint rawAmount) external override returns (bool) {
        uint96 amount;
        if (rawAmount == type(uint256).max) {
            amount = type(uint96).max;
        } else {
            amount = safe96(rawAmount, "HAT::approve: amount exceeds 96 bits");
        }

        allowances[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint addedValue) external virtual returns (bool) {
        require(spender != address(0), "HAT: increaseAllowance to the zero address");
        uint96 valueToAdd = safe96(addedValue, "HAT::increaseAllowance: addedValue exceeds 96 bits");
        allowances[msg.sender][spender] =
        add96(allowances[msg.sender][spender], valueToAdd, "HAT::increaseAllowance: overflows");
        emit Approval(msg.sender, spender, allowances[msg.sender][spender]);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint subtractedValue) external virtual returns (bool) {
        require(spender != address(0), "HAT: decreaseAllowance to the zero address");
        uint96 valueTosubtract = safe96(subtractedValue, "HAT::decreaseAllowance: subtractedValue exceeds 96 bits");
        allowances[msg.sender][spender] = sub96(allowances[msg.sender][spender], valueTosubtract,
        "HAT::decreaseAllowance: spender allowance is less than subtractedValue");
        emit Approval(msg.sender, spender, allowances[msg.sender][spender]);
        return true;
    }

    /**
     * @notice Triggers an approval from owner to spends
     * @param owner The address to approve from
     * @param spender The address to be approved
     * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
     * @param deadline The time at which to expire the signature
     * @param v The recovery byte of the signature
     * @param r Half of the ECDSA signature pair
     * @param s Half of the ECDSA signature pair
     */
    function permit(address owner, address spender, uint rawAmount, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
        uint96 amount;
        if (rawAmount == type(uint256).max) {
            amount = type(uint96).max;
        } else {
            amount = safe96(rawAmount, "HAT::permit: amount exceeds 96 bits");
        }

        bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));
        bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, rawAmount, nonces[owner]++, deadline));
        bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
        address signatory = ecrecover(digest, v, r, s);
        require(signatory != address(0), "HAT::permit: invalid signature");
        require(signatory == owner, "HAT::permit: unauthorized");
        // solhint-disable-next-line not-rely-on-time
        require(block.timestamp <= deadline, "HAT::permit: signature expired");

        allowances[owner][spender] = amount;

        emit Approval(owner, spender, amount);
    }

    /**
     * @notice Get the number of tokens held by the `account`
     * @param account The address of the account to get the balance of
     * @return The number of tokens held
     */
    function balanceOf(address account) external view override returns (uint) {
        return balances[account];
    }

    /**
     * @notice Transfer `amount` tokens from `msg.sender` to `dst`
     * @param dst The address of the destination account
     * @param rawAmount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transfer(address dst, uint rawAmount) external override returns (bool) {
        uint96 amount = safe96(rawAmount, "HAT::transfer: amount exceeds 96 bits");
        _transferTokens(msg.sender, dst, amount);
        return true;
    }

    /**
     * @notice Transfer `amount` tokens from `src` to `dst`
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param rawAmount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferFrom(address src, address dst, uint rawAmount) external override returns (bool) {
        address spender = msg.sender;
        uint96 spenderAllowance = allowances[src][spender];
        uint96 amount = safe96(rawAmount, "HAT::approve: amount exceeds 96 bits");

        if (spender != src && spenderAllowance != type(uint96).max) {
            uint96 newAllowance = sub96(spenderAllowance, amount,
            "HAT::transferFrom: transfer amount exceeds spender allowance");
            allowances[src][spender] = newAllowance;

            emit Approval(src, spender, newAllowance);
        }

        _transferTokens(src, dst, amount);
        return true;
    }

    /**
     * @notice Delegate votes from `msg.sender` to `delegatee`
     * @param delegatee The address to delegate votes to
     */
    function delegate(address delegatee) external {
        return _delegate(msg.sender, delegatee);
    }

    /**
     * @notice Delegates votes from signatory to `delegatee`
     * @param delegatee The address to delegate votes to
     * @param nonce The contract state required to match the signature
     * @param expiry The time at which to expire the signature
     * @param v The recovery byte of the signature
     * @param r Half of the ECDSA signature pair
     * @param s Half of the ECDSA signature pair
     */
    function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) external {
        bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));
        bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));
        bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
        address signatory = ecrecover(digest, v, r, s);
        require(signatory != address(0), "HAT::delegateBySig: invalid signature");
        require(nonce == nonces[signatory]++, "HAT::delegateBySig: invalid nonce");
        // solhint-disable-next-line not-rely-on-time
        require(block.timestamp <= expiry, "HAT::delegateBySig: signature expired");
        return _delegate(signatory, delegatee);
    }

    /**
     * @notice Gets the current votes balance for `account`
     * @param account The address to get votes balance
     * @return The number of current votes for `account`
     */
    function getCurrentVotes(address account) external view returns (uint96) {
        uint32 nCheckpoints = numCheckpoints[account];
        return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
    }

    /**
     * @notice Determine the prior number of votes for an account as of a block number
     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
     * @param account The address of the account to check
     * @param blockNumber The block number to get the vote balance at
     * @return The number of votes the account had as of the given block
     */
    function getPriorVotes(address account, uint blockNumber) external view returns (uint96) {
        require(blockNumber < block.number, "HAT::getPriorVotes: not yet determined");

        uint32 nCheckpoints = numCheckpoints[account];
        if (nCheckpoints == 0) {
            return 0;
        }

        // First check most recent balance
        if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
            return checkpoints[account][nCheckpoints - 1].votes;
        }

        // Next check implicit zero balance
        if (checkpoints[account][0].fromBlock > blockNumber) {
            return 0;
        }

        uint32 lower = 0;
        uint32 upper = nCheckpoints - 1;
        while (upper > lower) {
            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            Checkpoint memory cp = checkpoints[account][center];
            if (cp.fromBlock == blockNumber) {
                return cp.votes;
            } else if (cp.fromBlock < blockNumber) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return checkpoints[account][lower].votes;
    }

    /**
     * @notice Mint new tokens
     * @param dst The address of the destination account
     * @param rawAmount The number of tokens to be minted
     */
    function _mint(address dst, uint rawAmount) internal {
        require(dst != address(0), "HAT::mint: cannot transfer to the zero address");
        require(SafeMath.add(totalSupply, rawAmount) <= CAP, "ERC20Capped: CAP exceeded");

        // mint the amount
        uint96 amount = safe96(rawAmount, "HAT::mint: amount exceeds 96 bits");
        totalSupply = safe96(SafeMath.add(totalSupply, amount), "HAT::mint: totalSupply exceeds 96 bits");

        // transfer the amount to the recipient
        balances[dst] = add96(balances[dst], amount, "HAT::mint: transfer amount overflows");
        emit Transfer(address(0), dst, amount);

        // move delegates
        _moveDelegates(address(0), delegates[dst], amount);
    }

    /**
     * Burn tokens
     * @param src The address of the source account
     * @param rawAmount The number of tokens to be burned
     */
    function _burn(address src, uint rawAmount) internal {
        require(src != address(0), "HAT::burn: cannot burn to the zero address");

        // burn the amount
        uint96 amount = safe96(rawAmount, "HAT::burn: amount exceeds 96 bits");
        totalSupply = safe96(SafeMath.sub(totalSupply, amount), "HAT::mint: totalSupply exceeds 96 bits");

        // reduce the amount from src address
        balances[src] = sub96(balances[src], amount, "HAT::burn: burn amount exceeds balance");
        emit Transfer(src, address(0), amount);

        // move delegates
        _moveDelegates(delegates[src], address(0), amount);
    }

    function _delegate(address delegator, address delegatee) internal {
        address currentDelegate = delegates[delegator];
        uint96 delegatorBalance = balances[delegator];
        delegates[delegator] = delegatee;

        emit DelegateChanged(delegator, currentDelegate, delegatee);

        _moveDelegates(currentDelegate, delegatee, delegatorBalance);
    }

    function _transferTokens(address src, address dst, uint96 amount) internal {
        require(src != address(0), "HAT::_transferTokens: cannot transfer from the zero address");
        require(dst != address(0), "HAT::_transferTokens: cannot transfer to the zero address");

        balances[src] = sub96(balances[src], amount, "HAT::_transferTokens: transfer amount exceeds balance");
        balances[dst] = add96(balances[dst], amount, "HAT::_transferTokens: transfer amount overflows");
        emit Transfer(src, dst, amount);

        _moveDelegates(delegates[src], delegates[dst], amount);
    }

    function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal {
        if (srcRep != dstRep && amount > 0) {
            if (srcRep != address(0)) {
                uint32 srcRepNum = numCheckpoints[srcRep];
                uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                uint96 srcRepNew = sub96(srcRepOld, amount, "HAT::_moveVotes: vote amount underflows");
                _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
            }

            if (dstRep != address(0)) {
                uint32 dstRepNum = numCheckpoints[dstRep];
                uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                uint96 dstRepNew = add96(dstRepOld, amount, "HAT::_moveVotes: vote amount overflows");
                _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
            }
        }
    }

    function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {
        uint32 blockNumber = safe32(block.number, "HAT::_writeCheckpoint: block number exceeds 32 bits");

        if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
            checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
        } else {
            checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
            numCheckpoints[delegatee] = nCheckpoints + 1;
        }

        emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
    }

    function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function safe96(uint n, string memory errorMessage) internal pure returns (uint96) {
        require(n < 2**96, errorMessage);
        return uint96(n);
    }

    function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
        uint96 c = a + b;
        require(c >= a, errorMessage);
        return c;
    }

    function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
        require(b <= a, errorMessage);
        return a - b;
    }

    function getChainId() internal view returns (uint) {
        uint256 chainId;
        // solhint-disable-next-line no-inline-assembly
        assembly { chainId := chainid() }
        return chainId;
    }
}

File 14 of 15 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 15 of 15 : ITokenLock.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.6;
pragma experimental ABIEncoderV2;

import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";

interface ITokenLock {
    enum Revocability { NotSet, Enabled, Disabled }

    // -- Balances --

    function currentBalance() external view returns (uint256);

    // -- Time & Periods --

    function currentTime() external view returns (uint256);

    function duration() external view returns (uint256);

    function sinceStartTime() external view returns (uint256);

    function amountPerPeriod() external view returns (uint256);

    function periodDuration() external view returns (uint256);

    function currentPeriod() external view returns (uint256);

    function passedPeriods() external view returns (uint256);

    // -- Locking & Release Schedule --

    function availableAmount() external view returns (uint256);

    function vestedAmount() external view returns (uint256);

    function releasableAmount() external view returns (uint256);

    function totalOutstandingAmount() external view returns (uint256);

    function surplusAmount() external view returns (uint256);

    // -- Value Transfer --

    function release() external;

    function withdrawSurplus(uint256 _amount) external;

    function revoke() external;
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"},{"internalType":"uint256","name":"_rewardPerBlock","type":"uint256"},{"internalType":"uint256","name":"_startBlock","type":"uint256"},{"internalType":"uint256","name":"_multiplierPeriod","type":"uint256"},{"internalType":"address","name":"_hatGovernance","type":"address"},{"internalType":"contract ISwapRouter","name":"_uniSwapRouter","type":"address"},{"internalType":"contract ITokenLockFactory","name":"_tokenLockFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"indexed":true,"internalType":"address","name":"_lpToken","type":"address"},{"indexed":false,"internalType":"address","name":"_committee","type":"address"},{"indexed":false,"internalType":"string","name":"_descriptionHash","type":"string"},{"indexed":false,"internalType":"uint256[]","name":"_rewardsLevels","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"hackerVestedReward","type":"uint256"},{"internalType":"uint256","name":"hackerReward","type":"uint256"},{"internalType":"uint256","name":"committeeReward","type":"uint256"},{"internalType":"uint256","name":"swapAndBurn","type":"uint256"},{"internalType":"uint256","name":"governanceHatReward","type":"uint256"},{"internalType":"uint256","name":"hackerHatReward","type":"uint256"}],"indexed":false,"internalType":"struct HATMaster.RewardsSplit","name":"_rewardsSplit","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"_rewardVestingDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_rewardVestingPeriods","type":"uint256"}],"name":"AddPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_claimer","type":"address"},{"indexed":false,"internalType":"string","name":"_descriptionHash","type":"string"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_approver","type":"address"},{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":true,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"_severity","type":"uint256"},{"indexed":false,"internalType":"address","name":"_tokenLock","type":"address"},{"components":[{"internalType":"uint256","name":"hackerVestedReward","type":"uint256"},{"internalType":"uint256","name":"hackerReward","type":"uint256"},{"internalType":"uint256","name":"committeeReward","type":"uint256"},{"internalType":"uint256","name":"swapAndBurn","type":"uint256"},{"internalType":"uint256","name":"governanceHatReward","type":"uint256"},{"internalType":"uint256","name":"hackerHatReward","type":"uint256"}],"indexed":false,"internalType":"struct HATVaults.ClaimReward","name":"_claimReward","type":"tuple"}],"name":"ClaimApprove","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"_newGovernance","type":"address"},{"indexed":false,"internalType":"uint256","name":"_at","type":"uint256"}],"name":"GovernancePending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"_newGovernance","type":"address"}],"name":"GovernorshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromPid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toPid","type":"uint256"}],"name":"MassUpdatePools","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":true,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":true,"internalType":"uint256","name":"_severity","type":"uint256"},{"indexed":false,"internalType":"address","name":"_approver","type":"address"}],"name":"PendingApprovalLog","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"_rewardsLevels","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"_timeStamp","type":"uint256"}],"name":"PendingRewardsLevelsLog","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"RewardDepositors","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestedAmount","type":"uint256"}],"name":"SendReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":true,"internalType":"address","name":"_committee","type":"address"}],"name":"SetCommittee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_duration","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_periods","type":"uint256"}],"name":"SetHatVestingParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"indexed":true,"internalType":"bool","name":"_registered","type":"bool"},{"indexed":false,"internalType":"string","name":"_descriptionHash","type":"string"}],"name":"SetPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"_rewardsLevels","type":"uint256[]"}],"name":"SetRewardsLevels","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"components":[{"internalType":"uint256","name":"hackerVestedReward","type":"uint256"},{"internalType":"uint256","name":"hackerReward","type":"uint256"},{"internalType":"uint256","name":"committeeReward","type":"uint256"},{"internalType":"uint256","name":"swapAndBurn","type":"uint256"},{"internalType":"uint256","name":"governanceHatReward","type":"uint256"},{"internalType":"uint256","name":"hackerHatReward","type":"uint256"}],"indexed":false,"internalType":"struct HATMaster.RewardsSplit","name":"_rewardsSplit","type":"tuple"}],"name":"SetRewardsSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_duration","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_periods","type":"uint256"}],"name":"SetVestingParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_withdrawPeriod","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_safetyPeriod","type":"uint256"}],"name":"SetWithdrawSafetyPeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_amountSwaped","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_amountBurned","type":"uint256"}],"name":"SwapAndBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":true,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amountSwaped","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountReceived","type":"uint256"},{"indexed":false,"internalType":"address","name":"_tokenLock","type":"address"}],"name":"SwapAndSend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_pid","type":"uint256"},{"indexed":true,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":true,"internalType":"uint256","name":"_withdrawEnableTime","type":"uint256"}],"name":"WithdrawRequest","type":"event"},{"inputs":[],"name":"HAT","outputs":[{"internalType":"contract HATToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_DEPOSIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MULTIPLIER_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_PER_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"START_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIME_LOCK_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"address","name":"_lpToken","type":"address"},{"internalType":"address","name":"_committee","type":"address"},{"internalType":"uint256[]","name":"_rewardsLevels","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"hackerVestedReward","type":"uint256"},{"internalType":"uint256","name":"hackerReward","type":"uint256"},{"internalType":"uint256","name":"committeeReward","type":"uint256"},{"internalType":"uint256","name":"swapAndBurn","type":"uint256"},{"internalType":"uint256","name":"governanceHatReward","type":"uint256"},{"internalType":"uint256","name":"hackerHatReward","type":"uint256"}],"internalType":"struct HATMaster.RewardsSplit","name":"_rewardsSplit","type":"tuple"},{"internalType":"string","name":"_descriptionHash","type":"string"},{"internalType":"uint256[2]","name":"_rewardVestingParams","type":"uint256[2]"}],"name":"addPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"approveClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_severity","type":"uint256"}],"name":"calcClaimRewards","outputs":[{"components":[{"internalType":"uint256","name":"hackerVestedReward","type":"uint256"},{"internalType":"uint256","name":"hackerReward","type":"uint256"},{"internalType":"uint256","name":"committeeReward","type":"uint256"},{"internalType":"uint256","name":"swapAndBurn","type":"uint256"},{"internalType":"uint256","name":"governanceHatReward","type":"uint256"},{"internalType":"uint256","name":"hackerHatReward","type":"uint256"}],"internalType":"struct HATVaults.ClaimReward","name":"claimRewards","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_lastPoolUpdate","type":"uint256"}],"name":"calcPoolReward","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_descriptionHash","type":"string"}],"name":"claim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"claimReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"committeeCheckIn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"committees","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"dismissPendingApprovalClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"generalParameters","outputs":[{"internalType":"uint256","name":"hatVestingDuration","type":"uint256"},{"internalType":"uint256","name":"hatVestingPeriods","type":"uint256"},{"internalType":"uint256","name":"withdrawPeriod","type":"uint256"},{"internalType":"uint256","name":"safetyPeriod","type":"uint256"},{"internalType":"uint256","name":"setRewardsLevelsDelay","type":"uint256"},{"internalType":"uint256","name":"withdrawRequestEnablePeriod","type":"uint256"},{"internalType":"uint256","name":"withdrawRequestPendingPeriod","type":"uint256"},{"internalType":"uint256","name":"claimFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDefaultRewardsSplit","outputs":[{"components":[{"internalType":"uint256","name":"hackerVestedReward","type":"uint256"},{"internalType":"uint256","name":"hackerReward","type":"uint256"},{"internalType":"uint256","name":"committeeReward","type":"uint256"},{"internalType":"uint256","name":"swapAndBurn","type":"uint256"},{"internalType":"uint256","name":"governanceHatReward","type":"uint256"},{"internalType":"uint256","name":"hackerHatReward","type":"uint256"}],"internalType":"struct HATMaster.RewardsSplit","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getGlobalPoolUpdatesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_to","type":"uint256"}],"name":"getMultiplier","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"getPoolRewards","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"hackerVestedReward","type":"uint256"},{"internalType":"uint256","name":"hackerReward","type":"uint256"},{"internalType":"uint256","name":"committeeReward","type":"uint256"},{"internalType":"uint256","name":"swapAndBurn","type":"uint256"},{"internalType":"uint256","name":"governanceHatReward","type":"uint256"},{"internalType":"uint256","name":"hackerHatReward","type":"uint256"}],"internalType":"struct HATMaster.RewardsSplit","name":"rewardsSplit","type":"tuple"},{"internalType":"uint256[]","name":"rewardsLevels","type":"uint256[]"},{"internalType":"bool","name":"committeeCheckIn","type":"bool"},{"internalType":"uint256","name":"vestingDuration","type":"uint256"},{"internalType":"uint256","name":"vestingPeriods","type":"uint256"}],"internalType":"struct HATMaster.PoolReward","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"getPoolRewardsLevels","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_to","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"uint256","name":"_totalAllocPoint","type":"uint256"}],"name":"getRewardForBlocksRange","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid1","type":"uint256"}],"name":"getRewardPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getStakedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"globalPoolUpdates","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"totalAllocPoint","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"governanceHatRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governancePending","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"hackersHatRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fromPid","type":"uint256"},{"internalType":"uint256","name":"_toPid","type":"uint256"}],"name":"massUpdatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"uint256","name":"_severity","type":"uint256"}],"name":"pendingApprovalClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingApprovals","outputs":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"severity","type":"uint256"},{"internalType":"address","name":"approver","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingRewardsLevels","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolDepositPause","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"poolId1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfo","outputs":[{"internalType":"contract IERC20","name":"lpToken","type":"address"},{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"uint256","name":"lastRewardBlock","type":"uint256"},{"internalType":"uint256","name":"rewardPerShare","type":"uint256"},{"internalType":"uint256","name":"totalUsersAmount","type":"uint256"},{"internalType":"uint256","name":"lastProcessedTotalAllocPoint","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"rewardDepositors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setClaimFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_committee","type":"address"}],"name":"setCommittee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setGovernancePendingAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"uint256","name":"_periods","type":"uint256"}],"name":"setHatVestingParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernance","type":"address"}],"name":"setPendingGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256[]","name":"_rewardsLevels","type":"uint256[]"}],"name":"setPendingRewardsLevels","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"bool","name":"_registered","type":"bool"},{"internalType":"bool","name":"_depositPause","type":"bool"},{"internalType":"string","name":"_descriptionHash","type":"string"}],"name":"setPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"setRewardsLevels","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setRewardsLevelsDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"components":[{"internalType":"uint256","name":"hackerVestedReward","type":"uint256"},{"internalType":"uint256","name":"hackerReward","type":"uint256"},{"internalType":"uint256","name":"committeeReward","type":"uint256"},{"internalType":"uint256","name":"swapAndBurn","type":"uint256"},{"internalType":"uint256","name":"governanceHatReward","type":"uint256"},{"internalType":"uint256","name":"hackerHatReward","type":"uint256"}],"internalType":"struct HATMaster.RewardsSplit","name":"_rewardsSplit","type":"tuple"}],"name":"setRewardsSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"uint256","name":"_periods","type":"uint256"}],"name":"setVestingParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_withdrawRequestPendingPeriod","type":"uint256"},{"internalType":"uint256","name":"_withdrawRequestEnablePeriod","type":"uint256"}],"name":"setWithdrawRequestParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_withdrawPeriod","type":"uint256"},{"internalType":"uint256","name":"_safetyPeriod","type":"uint256"}],"name":"setWithdrawSafetyPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"swapAndBurns","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"uint256","name":"_amountOutMinimum","type":"uint256"},{"internalType":"uint24[2]","name":"_fees","type":"uint24[2]"}],"name":"swapBurnSend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenLockFactory","outputs":[{"internalType":"contract ITokenLockFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transferGovernorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniSwapRouter","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"updatePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"withdrawRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"withdrawRequests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

6101406040523480156200001257600080fd5b506040516200618538038062006185833981016040819052620000359162000162565b6001600355606087901b6001600160601b03191660805260a086905260c085905260e0849052620000728362000117602090811b620039a817901c565b6001600160601b0319606092831b81166101205290821b166101009081526040805191820181526276a700808352605a60208401819052619ab0928401839052610e109484018590526202a3006080850181905262093a8060a0860181905260c08601819052600060e0909601869052601193909355601291909155601392909255601493909355601555601682905560179190915560185550620002039350505050565b600080546001600160a01b0319166001600160a01b03831690811782556040519091907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a350565b600080600080600080600060e0888a0312156200017e57600080fd5b87516200018b81620001ea565b809750506020880151955060408801519450606088015193506080880151620001b481620001ea565b60a0890151909350620001c781620001ea565b60c0890151909250620001da81620001ea565b8091505092959891949750929550565b6001600160a01b03811681146200020057600080fd5b50565b60805160601c60a05160c05160e0516101005160601c6101205160601c615e73620003126000396000818161080f015281816147db015281816149490152614b3e01526000818161048a01528181611b170152612fb6015260008181610dac0152818161288601526129180152600081816106bd015281816128aa015281816128f301528181613e590152613e80015260008181610a22015261372e01526000818161063c015281816120e50152818161219401528181612f0701528181612fe5015281816130cb015281816131a401528181614785015281816148c101528181614a2d01528181614ac501528181614be801528181614cd501528181614d870152614e750152615e736000f3fe6080604052600436106103c35760003560e01c806382b0617d116101f2578063cbd42a701161010d578063eabcff2c116100a0578063f3fe12c91161006f578063f3fe12c914610d51578063f5e820fd14610d64578063f7cd531914610d9a578063fcecc73814610dce57600080fd5b8063eabcff2c14610cda578063ebb6bc7214610cfa578063f19451d814610d1a578063f26ae82714610d3157600080fd5b8063dd072f03116100dc578063dd072f0314610bf4578063df1b1ebe14610c14578063e02ff8f214610c82578063e2bbb15814610cba57600080fd5b8063cbd42a7014610b71578063ce2529c914610b91578063d2369c6514610bbe578063da42757814610bd457600080fd5b806399f9b05a11610185578063b2e629c711610154578063b2e629c714610af1578063b9a4bdb414610b11578063be75e74f14610b31578063c7b5184a14610b5157600080fd5b806399f9b05a14610a645780639c2a7a6d14610a9c578063aa0cd25c14610abc578063ae169a5014610ad157600080fd5b806393f1a40b116101c157806393f1a40b1461098f57806395fec613146109e3578063975532dc14610a1057806398969e8214610a4457600080fd5b806382b0617d1461090257806383867c1b1461092f57806384fcf8e51461094f5780638dbb1e3a1461096f57600080fd5b8063398488eb116102e2578063520a924d11610275578063686b656e11610244578063686b656e146108315780636e419506146108a257806374899a7e146108c25780637b550bc9146108e257600080fd5b8063520a924d1461079f5780635312ea8e146107bf5780635aa6e675146107df5780635d01ff3d146107fd57600080fd5b8063441a3e70116102b1578063441a3e701461071f57806346e301351461073f5780634f8d45ee1461075f57806351eb05a61461077f57600080fd5b8063398488eb1461068b57806339b3e826146106ab5780633a71ede8146106df5780633d8a0906146106ff57600080fd5b80631d46446a1161035a5780633207b103116103295780633207b103146105d057806334333058146105fd5780633449a8651461062a57806335bbf3161461065e57600080fd5b80631d46446a146105435780632a5ad7d0146105635780632b2f4d84146105905780632e75ab50146105b057600080fd5b80630d2edde2116103965780630d2edde21461046357806311c2aae31461047857806313401551146104c45780631526fe27146104e457600080fd5b8063081e3eda146103c85780630abb6035146103ec5780630af937f21461040e5780630b346a9e1461044e575b600080fd5b3480156103d457600080fd5b506004545b6040519081526020015b60405180910390f35b3480156103f857600080fd5b5061040c6104073660046153a8565b610de5565b005b34801561041a57600080fd5b5061043e61042936600461546d565b60106020526000908152604090205460ff1681565b60405190151581526020016103e3565b34801561045a57600080fd5b506005546103d9565b34801561046f57600080fd5b5061040c610eee565b34801561048457600080fd5b506104ac7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016103e3565b3480156104d057600080fd5b506001546104ac906001600160a01b031681565b3480156104f057600080fd5b506105046104ff36600461546d565b611052565b604080516001600160a01b0390981688526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016103e3565b34801561054f57600080fd5b5061040c61055e3660046155c8565b6110ab565b34801561056f57600080fd5b506103d961057e3660046153a8565b600c6020526000908152604090205481565b34801561059c57600080fd5b5061040c6105ab3660046157ac565b6112c7565b3480156105bc57600080fd5b5061040c6105cb36600461546d565b6113a1565b3480156105dc57600080fd5b506105f06105eb36600461546d565b6113d0565b6040516103e391906159b6565b34801561060957600080fd5b5061061d610618366004615714565b611435565b6040516103e39190615bb0565b34801561063657600080fd5b506104ac7f000000000000000000000000000000000000000000000000000000000000000081565b34801561066a57600080fd5b506103d961067936600461546d565b600f6020526000908152604090205481565b34801561069757600080fd5b5061040c6106a6366004615714565b6116b0565b3480156106b757600080fd5b506103d97f000000000000000000000000000000000000000000000000000000000000000081565b3480156106eb57600080fd5b506103d96106fa36600461549f565b6116e5565b34801561070b57600080fd5b5061040c61071a36600461546d565b61170f565b34801561072b57600080fd5b5061040c61073a366004615714565b6118f9565b34801561074b57600080fd5b5061040c61075a36600461546d565b611910565b34801561076b57600080fd5b5061040c61077a3660046154c4565b611d96565b34801561078b57600080fd5b5061040c61079a36600461546d565b612049565b3480156107ab57600080fd5b5061040c6107ba366004615714565b612235565b3480156107cb57600080fd5b5061040c6107da36600461546d565b61229a565b3480156107eb57600080fd5b506000546001600160a01b03166104ac565b34801561080957600080fd5b506104ac7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083d57600080fd5b5061087861084c36600461546d565b600d602052600090815260409020805460018201546002909201546001600160a01b0391821692911683565b604080516001600160a01b03948516815260208101939093529216918101919091526060016103e3565b3480156108ae57600080fd5b5061040c6108bd366004615714565b6122af565b3480156108ce57600080fd5b5061040c6108dd36600461546d565b61240b565b3480156108ee57600080fd5b506103d96108fd36600461546d565b6124d6565b34801561090e57600080fd5b5061092261091d36600461546d565b61256d565b6040516103e39190615c16565b34801561093b57600080fd5b5061040c61094a36600461546d565b612651565b34801561095b57600080fd5b5061040c61096a3660046156a0565b6126a8565b34801561097b57600080fd5b506103d961098a366004615714565b61279e565b34801561099b57600080fd5b506109ce6109aa36600461549f565b60076020908152600092835260408084209091529082529020805460019091015482565b604080519283526020830191909152016103e3565b3480156109ef57600080fd5b506103d96109fe3660046153a8565b600a6020526000908152604090205481565b348015610a1c57600080fd5b506103d97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a5057600080fd5b506103d9610a5f36600461549f565b612a0b565b348015610a7057600080fd5b506103d9610a7f3660046153e2565b600b60209081526000928352604080842090915290825290205481565b348015610aa857600080fd5b5061040c610ab73660046156e7565b612af0565b348015610ac857600080fd5b5061061d612c28565b348015610add57600080fd5b5061040c610aec36600461546d565b612c9e565b348015610afd57600080fd5b5061040c610b0c366004615736565b612ca9565b348015610b1d57600080fd5b5061040c610b2c366004615600565b612dab565b348015610b3d57600080fd5b5061040c610b4c36600461549f565b61327e565b348015610b5d57600080fd5b5061040c610b6c36600461546d565b613415565b348015610b7d57600080fd5b506109ce610b8c36600461546d565b613471565b348015610b9d57600080fd5b506103d9610bac3660046153a8565b60066020526000908152604090205481565b348015610bca57600080fd5b506103d960025481565b348015610be057600080fd5b5061040c610bef366004615714565b61349f565b348015610c0057600080fd5b5061040c610c0f366004615714565b61358f565b348015610c2057600080fd5b50601154601254601354601454601554601654601754601854610c47979695949392919088565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e0820152610100016103e3565b348015610c8e57600080fd5b506103d9610c9d36600461549f565b600e60209081526000928352604080842090915290825290205481565b348015610cc657600080fd5b5061040c610cd5366004615714565b613656565b348015610ce657600080fd5b506103d9610cf53660046157d8565b613714565b348015610d0657600080fd5b5061040c610d1536600461546d565b613768565b348015610d2657600080fd5b506103d9620f424081565b348015610d3d57600080fd5b506103d9610d4c3660046157ac565b6137df565b61040c610d5f366004615438565b6138d7565b348015610d7057600080fd5b506104ac610d7f36600461546d565b6009602052600090815260409020546001600160a01b031681565b348015610da657600080fd5b506103d97f000000000000000000000000000000000000000000000000000000000000000081565b348015610dda57600080fd5b506103d96202a30081565b6000546001600160a01b03163314610e185760405162461bcd60e51b8152600401610e0f90615aa4565b60405180910390fd5b6001600160a01b038116610e845760405162461bcd60e51b815260206004820152602d60248201527f476f7665726e61626c653a6e657720676f7665726e616e63652069732074686560448201526c207a65726f206164647265737360981b6064820152608401610e0f565b600180546001600160a01b038084166001600160a01b03199092168217909255426002819055600054604051929316917f6dedeac5137d4e7301332bf2cbe80d9997406cff0e2b3634c9f8c47a49989ba991610ee39190815260200190565b60405180910390a350565b6000546001600160a01b03163314610f185760405162461bcd60e51b8152600401610e0f90615aa4565b600060025411610f745760405162461bcd60e51b815260206004820152602160248201527f476f7665726e61626c653a206e6f2070656e64696e6720676f7665726e616e636044820152606560f81b6064820152608401610e0f565b6202a30060025442610f869190615d3a565b11610fee5760405162461bcd60e51b815260206004820152603260248201527f476f7665726e61626c653a2063616e6e6f7420636f6e6669726d20676f7665726044820152716e616e636520617420746869732074696d6560701b6064820152608401610e0f565b600154600080546040516001600160a01b0393841693909116917fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a91a3600154600080546001600160a01b0319166001600160a01b03909216919091178155600255565b6004818154811061106257600080fd5b600091825260209091206007909102018054600182015460028301546003840154600485015460058601546006909601546001600160a01b039095169650929491939092919087565b60008381526009602052604090205483906001600160a01b031633146110e35760405162461bcd60e51b8152600401610e0f90615a45565b6000848152600d602052604090205484906001600160a01b03161561111a5760405162461bcd60e51b8152600401610e0f90615acd565b6001600160a01b0384166111665760405162461bcd60e51b815260206004820152601360248201527262656e6566696369617279206973207a65726f60681b6044820152606401610e0f565b6013546014546111769082615cef565b6111809042615d98565b10156111c35760405162461bcd60e51b81526020600482015260126024820152711b9bdb99481cd859995d1e481c195c9a5bd960721b6044820152606401610e0f565b60008581526008602052604090206006015483106112235760405162461bcd60e51b815260206004820152601d60248201527f5f7365766572697479206973206e6f7420696e207468652072616e67650000006044820152606401610e0f565b604080516060810182526001600160a01b0386811680835260208084018881523385870181815260008d8152600d8552889020965187549087166001600160a01b0319918216178855925160018801555160029096018054969095169590911694909417909255925191825285929188917fd878c70cbed9605353e23b13b6475a2e1ef3c7d976f8495f233a1a7f4bc6811c91015b60405180910390a45050505050565b6000546001600160a01b031633146112f15760405162461bcd60e51b8152600401610e0f90615aa4565b629e340082106113135760405162461bcd60e51b8152600401610e0f90615afd565b600081116113335760405162461bcd60e51b8152600401610e0f90615a6d565b808210156113535760405162461bcd60e51b8152600401610e0f90615b34565b60008381526008602081905260408083209182018590556009909101839055518291849186917fb2c473651bf0d98b7935f0a45d2e04d804b1d00c3131bf824fb1944ff9ae8e3c91a4505050565b6000546001600160a01b031633146113cb5760405162461bcd60e51b8152600401610e0f90615aa4565b601855565b60008181526008602090815260409182902060060180548351818402810184019094528084526060939283018282801561142957602002820191906000526020600020905b815481526020019060010190808311611415575b50505050509050919050565b61146e6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60006004848154811061148357611483615dee565b9060005260206000209060070201600601549050600081116114dd5760405162461bcd60e51b8152602060048201526013602482015272746f74616c537570706c79206973207a65726f60681b6044820152606401610e0f565b600084815260086020526040902060060154831061153d5760405162461bcd60e51b815260206004820152601d60248201527f5f7365766572697479206973206e6f7420696e207468652072616e67650000006044820152606401610e0f565b6000848152600860205260408120600601805461157f91908690811061156557611565615dee565b9060005260206000200154836139f390919063ffffffff16565b90506115b061159061271080615d1b565b6000878152600860205260409020546115aa9084906139f3565b906139ff565b83526115de6115c161271080615d1b565b6000878152600860205260409020600101546115aa9084906139f3565b602084015261160f6115f261271080615d1b565b6000878152600860205260409020600201546115aa9084906139f3565b604084015261164061162361271080615d1b565b6000878152600860205260409020600301546115aa9084906139f3565b606084015261167161165461271080615d1b565b6000878152600860205260409020600401546115aa9084906139f3565b60808401526116a261168561271080615d1b565b6000878152600860205260409020600501546115aa9084906139f3565b60a084015250909392505050565b6000546001600160a01b031633146116da5760405162461bcd60e51b8152600401610e0f90615aa4565b601791909155601655565b60008281526007602090815260408083206001600160a01b03851684529091529020545b92915050565b60008181526009602052604090205481906001600160a01b031633146117475760405162461bcd60e51b8152600401610e0f90615a45565b6000828152600d602052604090205482906001600160a01b03161561177e5760405162461bcd60e51b8152600401610e0f90615acd565b6000838152600f60205260409020546117d95760405162461bcd60e51b815260206004820152601d60248201527f6e6f2070656e64696e67207365742072657761726473206c6576656c730000006044820152606401610e0f565b6015546000848152600f60205260409020546117f59042615d3a565b116118575760405162461bcd60e51b815260206004820152602c60248201527f63616e6e6f7420636f6e6669726d20736574526577617264734c6576656c732060448201526b617420746869732074696d6560a01b6064820152608401610e0f565b6000838152600f60209081526040808320600890925290912060019091018054611885926006019190615112565b506000838152600f60205260408120818155906118a56001830182615162565b5050827f37234a2297757e81787ddd776e23606f74b9ecc8562ba691b9dde3adef5089cd600860008681526020019081526020016000206006016040516118ec91906159eb565b60405180910390a2505050565b61190282613a0b565b61190c8282613b4f565b5050565b6000546001600160a01b0316331461193a5760405162461bcd60e51b8152600401610e0f90615aa4565b6002600354141561195d5760405162461bcd60e51b8152600401610e0f90615b79565b60026003556000818152600d60205260409020546001600160a01b03166119bc5760405162461bcd60e51b81526020600482015260136024820152721b9bc81c195b991a5b99c8185c1c1c9bdd985b606a1b6044820152606401610e0f565b6000818152600860209081526040808320600d808452828520835160608101855281546001600160a01b038082168352600184018054848a0152600285018054928316988501989098528a8a52949097526001600160a01b0319908116909255918690559093169091556004805491939185908110611a3d57611a3d615dee565b60009182526020808320600790920290910154908401516001600160a01b039091169250611a6c908690611435565b9050611ae5611ab28260800151611aac8460a00151611aac8660600151611aac8860400151611aac8a600001518b60200151613d3490919063ffffffff16565b90613d34565b60048781548110611ac557611ac5615dee565b906000526020600020906007020160060154613d4090919063ffffffff16565b60048681548110611af857611af8615dee565b60009182526020822060066007909202010191909155815115611c02577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e95cd0518461dead87600001518660000151428b6008015442611b639190615cef565b8c60090154600080600260006040518c63ffffffff1660e01b8152600401611b959b9a999897969594939291906158c7565b602060405180830381600087803b158015611baf57600080fd5b505af1158015611bc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be791906153c5565b8251909150611c02906001600160a01b038516908390613d4c565b83516020830151611c1d916001600160a01b03861691613d4c565b60408085015190830151611c3b916001600160a01b03861691613d4c565b60608201516001600160a01b0384166000908152600a6020526040902054611c6291613d34565b6001600160a01b0384166000908152600a60209081526040808320939093556080850151600c90915291902054611c9891613d34565b6001600160a01b038085166000818152600c602090815260408083209590955560a087015189519094168252600b8152848220928252919091529190912054611ce091613d34565b84516001600160a01b039081166000908152600b6020908152604080832088851684528252918290209390935586519287015190519290911691889133917fb34d89b43b53d2ebac4aa01c9ab4b64aca3ca9612c3f79a58c6d2528e414775291611d4d9187908990615c71565b60405180910390a4600060048781548110611d6a57611d6a615dee565b90600052602060002090600702016006015411611d8957611d89615dac565b5050600160035550505050565b6000546001600160a01b03163314611dc05760405162461bcd60e51b8152600401610e0f90615aa4565b8051629e340011611de35760405162461bcd60e51b8152600401610e0f90615afd565b6020810151611e045760405162461bcd60e51b8152600401610e0f90615a6d565b602081015181511015611e295760405162461bcd60e51b8152600401610e0f90615b34565b6001600160a01b038516611e735760405162461bcd60e51b8152602060048201526011602482015270636f6d6d6974746565206973207a65726f60781b6044820152606401610e0f565b611e7d8787613db4565b600454600090611e8f90600190615d3a565b600081815260096020526040812080546001600160a01b0319166001600160a01b038a16179055909150611ec2866140cc565b8551909150600090158015611ed957506020860151155b611ee35785611eeb565b611eeb612c28565b9050611ef6816141ef565b6040518060a0016040528082815260200183815260200160001515815260200185600060028110611f2957611f29615dee565b6020020151815260200185600160028110611f4657611f46615dee565b60209081029190910151909152600085815260088252604090819020835180518255808401516001830155918201516002820155606082015160038201556080820151600482015560a09091015160058201558282015180519192611fb392600685019290910190615180565b50604082015160078201805460ff1916911515919091179055606082015160088201556080909101516009909101556001600160a01b0389168a847f101333dd96212851804793a854aef45352029659781cb05bddccb6815bd86dc78b8987878b600060200201518c6001602002015160405161203596959493929190615957565b60405180910390a450505050505050505050565b60006004828154811061205e5761205e615dee565b9060005260206000209060070201905060008160020154905080431161208357505050565b600482015460055460009061209a90600190615d3a565b9050816120b557436002850155600590930192909255505050565b60006120c28685846137df565b604051633d1bb33160e21b81523060048201529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f46eccc49060240160206040518083038186803b15801561212757600080fd5b505afa15801561213b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215f9190615486565b905081811061216e5781612170565b805b915081156121f9576040516340c10f1960e01b8152306004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906340c10f1990604401600060405180830381600087803b1580156121e057600080fd5b505af11580156121f4573d6000803e3d6000fd5b505050505b61221a61220f856115aa8564e8d4a510006139f3565b600388015490613d34565b60038701555050436002850155600590930192909255505050565b6000546001600160a01b0316331461225f5760405162461bcd60e51b8152600401610e0f90615aa4565b60138290556014819055604051819083907f47c8a5b15f6172a5053bfac488642484dd38e9c0f3073c23c5d822c4cbab530990600090a35050565b6122a381613a0b565b6122ac8161427a565b50565b600482815481106122c2576122c2615dee565b906000526020600020906007020160040154612312620f42406115aa84600487815481106122f2576122f2615dee565b906000526020600020906007020160060154613d3490919063ffffffff16565b1061235f5760405162461bcd60e51b815260206004820152601b60248201527f616d6f756e7420746f2072657761726420697320746f6f2062696700000000006044820152606401610e0f565b61239a3330836004868154811061237857612378615dee565b60009182526020909120600790910201546001600160a01b03169291906143a9565b6123b181600484815481106122f2576122f2615dee565b600483815481106123c4576123c4615dee565b90600052602060002090600702016006018190555080827f66a9deaf092dcf4f0e1ca57edbef82d4eb4df8fdd6501dc30018338a4b8f625a60405160405180910390a35050565b6016546000828152600e602090815260408083203384529091529020546124329190615cef565b42116124805760405162461bcd60e51b815260206004820152601e60248201527f70656e64696e67207769746864726177207265717565737420657869737400006044820152606401610e0f565b60175461248d9042615cef565b6000828152600e6020908152604080832033808552925280832084905551909184917f13be99dfb4b71705ce15b8b7b83d0b8aa95b5ffb84bb2830a7e2b6b858c7218e9190a450565b6000816124f4576117096124eb600143615d3a565b43600180613714565b611709612502600143615d3a565b436004612510600187615d3a565b8154811061252057612520615dee565b906000526020600020906007020160010154600560016005805490506125469190615d3a565b8154811061255657612556615dee565b906000526020600020906002020160010154613714565b6125756151bb565b600082815260086020908152604091829020825161016081018452815460a08201908152600183015460c0830152600283015460e083015260038301546101008301526004830154610120830152600583015461014083015281526006820180548551818602810186019096528086529194929385810193929083018282801561261e57602002820191906000526020600020905b81548152602001906001019080831161260a575b5050509183525050600782015460ff16151560208201526008820154604082015260099091015460609091015292915050565b60008181526009602052604090205481906001600160a01b031633146126895760405162461bcd60e51b8152600401610e0f90615a45565b506000908152600860205260409020600701805460ff19166001179055565b60008281526009602052604090205482906001600160a01b031633146126e05760405162461bcd60e51b8152600401610e0f90615a45565b6000838152600d602052604090205483906001600160a01b0316156127175760405162461bcd60e51b8152600401610e0f90615acd565b612720836140cc565b600f60008681526020019081526020016000206001019080519060200190612749929190615180565b506000848152600f6020526040908190204290819055905185917f58f0d300eb5324931fe020560b51830bc4ead10b19467f5d56af8083eed98d48916127909187916159c9565b60405180910390a250505050565b604080516103208101825261113d808252602082015261227991810191909152611e6c6060820152611ad960808201526117b160a08201526114e960c082015261127460e0820152611049610100820152610e5f610120820152610caf610140820152610b316101608201526109e06101808201526108b76101a08201526107b16101c08201526106ca6101e08201526105fe6102008201526105496102208201526104aa61024082015261041e6102608201526103a26102808201526103356102a08201526102d46102c082015261027f6102e082015260006103008201819052906019827f00000000000000000000000000000000000000000000000000000000000000006128cf7f000000000000000000000000000000000000000000000000000000000000000088615d3a565b6128d99190615d07565b6128e4906001615cef565b90505b818110156129ab5760007f000000000000000000000000000000000000000000000000000000000000000061293c837f0000000000000000000000000000000000000000000000000000000000000000615d1b565b6129469190615cef565b905080861161295557506129ab565b83612961600184615d3a565b6019811061297157612971615dee565b60200201516129808883615d3a565b61298a9190615d1b565b6129949086615cef565b9096509350806129a381615d7d565b9150506128e7565b828282116129c3576129be600183615d3a565b6129ce565b6129ce600184615d3a565b601981106129de576129de615dee565b60200201516129ed8787615d3a565b6129f79190615d1b565b612a019085615cef565b9695505050505050565b60008060048481548110612a2157612a21615dee565b60009182526020808320878452600780835260408086206001600160a01b038a168752909352919093209102909101600381015460028201549193509043118015612a70575060008360040154115b15612ac2576000612a928785600201546001600580549050610d4c9190615d3a565b9050612abe612ab785600401546115aa64e8d4a51000856139f390919063ffffffff16565b8390613d34565b9150505b612a018260010154612aea64e8d4a510006115aa8587600001546139f390919063ffffffff16565b90613d40565b6000546001600160a01b03163314612b1a5760405162461bcd60e51b8152600401610e0f90615aa4565b6000828152600d602052604090205482906001600160a01b031615612b515760405162461bcd60e51b8152600401610e0f90615acd565b601354601454612b619082615cef565b612b6b9042615d98565b10612ba85760405162461bcd60e51b815260206004820152600d60248201526c1cd859995d1e481c195c9a5bd9609a1b6044820152606401610e0f565b612bb1826141ef565b60008381526008602090815260409182902084518155908401516001820155818401516002820155606084015160038201556080840151600482015560a08401516005909101555183907fe0fe09d9a25d5360154efb63f8f8c43a9cf25b0e4715d7f9ee42b362d99c941f906118ec908590615bb0565b612c616040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060c0016040528061177081526020016107d081526020016101f48152602001600081526020016103e881526020016101f4815250905090565b6122ac8160006143e7565b6000546001600160a01b03163314612cd35760405162461bcd60e51b8152600401610e0f90615aa4565b60006001600160a01b031660048681548110612cf157612cf1615dee565b60009182526020909120600790910201546001600160a01b03161415612d4f5760405162461bcd60e51b81526020600482015260136024820152721c1bdbdb08191bd95cc81b9bdd08195e1a5cdd606a1b6044820152606401610e0f565b612d5985856145e7565b60008581526010602052604090819020805460ff19168415151790555183151590859087907fd01a08be7ba6451f751cf523b54675f30a2c5ea6fa6bd909c2fd57f296fef0b5906112b8908690615a32565b6000546001600160a01b03163314612dd55760405162461bcd60e51b8152600401610e0f90615aa4565b600060048581548110612dea57612dea615dee565b600091825260208083206007909202909101546001600160a01b03908116808452600a83526040808520549289168552600b8452808520828652845280852054600c909452842054909450909290612e4690611aac8585613d34565b905060008111612e895760405162461bcd60e51b815260206004820152600e60248201526d616d6f756e74206973207a65726f60901b6044820152606401610e0f565b6001600160a01b038085166000818152600a60209081526040808320839055600c8252808320839055938b168252600b815283822092825291909152908120819055612ed78286888a614781565b90506000612ee9836115aa84886139f3565b90508015612f6c57604051630852cd8d60e31b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b158015612f5357600080fd5b505af1158015612f67573d6000803e3d6000fd5b505050505b80838b7f4f255c8cf5a84786ddc35d528b4df336f3aad1b61d63615fd8b228a39548cc9360405160405180910390a4600080612fac856115aa86896139f3565b9050801561314b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e95cd0517f000000000000000000000000000000000000000000000000000000000000000061dead8e85426011600001544261301b9190615cef565b6012546040516001600160e01b031960e08a901b168152613050979695949392919060009081906002906001906004016158c7565b602060405180830381600087803b15801561306a57600080fd5b505af115801561307e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a291906153c5565b60405163a9059cbb60e01b81526001600160a01b038083166004830152602482018490529193507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b15801561311157600080fd5b505af1158015613125573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613149919061541b565b505b848b6001600160a01b03168d7f5130497d6ba2833abd6dbfb4eb1a4bfa30540ea493ee0f3c811e44ff829697dc848660405161319a9291909182526001600160a01b0316602082015260400190565b60405180910390a47f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6131e36000546001600160a01b031690565b6131f186612aea8987613d40565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b15801561323757600080fd5b505af115801561324b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326f919061541b565b50505050505050505050505050565b6001600160a01b0381166132c85760405162461bcd60e51b8152602060048201526011602482015270636f6d6d6974746565206973207a65726f60781b6044820152606401610e0f565b6000546001600160a01b0316331480156132f957506000828152600960205260409020546001600160a01b03163314155b156133655760008281526008602052604090206007015460ff16156133605760405162461bcd60e51b815260206004820152601c60248201527f436f6d6d697474656520616c726561647920636865636b656420696e000000006044820152606401610e0f565b6133bc565b6000828152600960205260409020546001600160a01b031633146133bc5760405162461bcd60e51b815260206004820152600e60248201526d4f6e6c7920636f6d6d697474656560901b6044820152606401610e0f565b60008281526009602052604080822080546001600160a01b0319166001600160a01b0385169081179091559051909184917f2d56897538f0fc982e13469f511616bed63e0c8f65a75270ba4346266b50f2a59190a35050565b6000546001600160a01b0316331461343f5760405162461bcd60e51b8152600401610e0f90615aa4565b6000908152600d6020526040812080546001600160a01b03199081168255600182019290925560020180549091169055565b6005818154811061348157600080fd5b60009182526020909120600290910201805460019091015490915082565b6004548111156134e95760405162461bcd60e51b8152602060048201526015602482015274706f6f6c2072616e676520697320746f6f2062696760581b6044820152606401610e0f565b8082111561352e5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420706f6f6c2072616e676560701b6044820152606401610e0f565b815b818110156135515761354181612049565b61354a81615d7d565b9050613530565b5060408051838152602081018390527fd3f7645e6170879584cabe5bb42b1c424830ab0646a05d1d90bf6f641dc2e3d8910160405180910390a15050565b6000546001600160a01b031633146135b95760405162461bcd60e51b8152600401610e0f90615aa4565b62ed4e0082106135db5760405162461bcd60e51b8152600401610e0f90615afd565b600081116135fb5760405162461bcd60e51b8152600401610e0f90615a6d565b8082101561361b5760405162461bcd60e51b8152600401610e0f90615b34565b60118290556012819055604051819083907fa3d5527033c65a7e5eda0ffec2fe75b8bfc358a419914452e5e29993f531136d90600090a35050565b60008281526010602052604090205460ff16156136a65760405162461bcd60e51b815260206004820152600e60248201526d19195c1bdcda5d081c185d5cd95960921b6044820152606401610e0f565b620f42408110156136f05760405162461bcd60e51b815260206004820152601460248201527330b6b7bab73a103632b9b9903a3430b71018b29b60611b6044820152606401610e0f565b6000828152600e6020908152604080832033845290915281205561190c82826143e7565b600081156137605761375d60646115aa846115aa876137577f00000000000000000000000000000000000000000000000000000000000000006137578d8d61279e565b906139f3565b90505b949350505050565b6000546001600160a01b031633146137925760405162461bcd60e51b8152600401610e0f90615aa4565b6202a3008110156137da5760405162461bcd60e51b815260206004820152601260248201527119195b185e481a5cc81d1bdbc81cda1bdc9d60721b6044820152606401610e0f565b601555565b600080600485815481106137f5576137f5615dee565b906000526020600020906007020160010154905060006004868154811061381e5761381e615dee565b90600052602060002090600702016005015490505b838110156138a8576000600561384a836001615cef565b8154811061385a5761385a615dee565b906000526020600020906002020160000154905061389161388a8783866005878154811061255657612556615dee565b8590613d34565b9095509250806138a081615d7d565b915050613833565b6138cb6138c48643856005868154811061255657612556615dee565b8490613d34565b925050505b9392505050565b60185415613964576018543410156139285760405162461bcd60e51b81526020600482015260146024820152731b9bdd08195b9bdd59da08199959481c185e595960621b6044820152606401610e0f565b600080546040516001600160a01b03909116913480156108fc02929091818181858888f19350505050158015613962573d6000803e3d6000fd5b505b336001600160a01b03167fc8fdf13a4b928b8811a082d6f49538b13d9279cc130d1312406e8fa8742997358260405161399d9190615a32565b60405180910390a250565b600080546001600160a01b0319166001600160a01b03831690811782556040519091907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a350565b60006138d08284615d1b565b60006138d08284615d07565b6000818152600d602052604090205481906001600160a01b031615613a425760405162461bcd60e51b8152600401610e0f90615acd565b601354601454613a529082615cef565b613a5c9042615d98565b10613a995760405162461bcd60e51b815260206004820152600d60248201526c1cd859995d1e481c195c9a5bd9609a1b6044820152606401610e0f565b6000828152600e6020908152604080832033845290915290205442118015613ae657506016546000838152600e60209081526040808320338452909152902054613ae39190615cef565b42105b613b325760405162461bcd60e51b815260206004820152601a60248201527f77697468647261772072657175657374206e6f742076616c69640000000000006044820152606401610e0f565b506000908152600e60209081526040808320338452909152812055565b60026003541415613b725760405162461bcd60e51b8152600401610e0f90615b79565b6002600381905550600060048381548110613b8f57613b8f615dee565b6000918252602080832086845260078083526040808620338752909352919093208054929091029092019250831115613c145760405162461bcd60e51b815260206004820152602160248201527f77697468647261773a206e6f7420656e6f75676820757365722062616c616e636044820152606560f81b6064820152608401610e0f565b613c1d84612049565b6000613c4b8260010154612aea64e8d4a510006115aa876003015487600001546139f390919063ffffffff16565b90508015613c5e57613c5e338287614cbd565b8315613cd1578154613c709085613d40565b825560048301546006840154600091613c8e916115aa9088906139f3565b6006850154909150613ca09082613d40565b60068501558354613cbb906001600160a01b03163383613d4c565b6004840154613cca9086613d40565b6004850155505b60038301548254613cec9164e8d4a51000916115aa916139f3565b6001830155604051848152859033907ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689060200160405180910390a350506001600355505050565b60006138d08284615cef565b60006138d08284615d3a565b6040516001600160a01b038316602482015260448101829052613daf90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614f35565b505050565b6001600160a01b03811660009081526006602052604090205415613e2d5760405162461bcd60e51b815260206004820152602a60248201527f4841544d61737465723a3a6164643a206c70546f6b656e20697320616c726561604482015269191e481a5b881c1bdbdb60b21b6064820152608401610e0f565b600454613e3b906001615cef565b6001600160a01b0382166000908152600660205260408120919091557f00000000000000000000000000000000000000000000000000000000000000004311613ea4577f0000000000000000000000000000000000000000000000000000000000000000613ea6565b435b60055490915060009015613eff5760058054613efa918691613eca90600190615d3a565b81548110613eda57613eda615dee565b906000526020600020906002020160010154613d3490919063ffffffff16565b613f01565b835b60055490915015801590613f47575060058054439190613f2390600190615d3a565b81548110613f3357613f33615dee565b906000526020600020906002020160000154145b15613f895760058054829190613f5f90600190615d3a565b81548110613f6f57613f6f615dee565b906000526020600020906002020160010181905550614000565b60408051808201909152438152602081018281526005805460018101825560009190915291517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0600290930292830155517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db1909101555b60046040518060e00160405280856001600160a01b03168152602001868152602001848152602001600081526020016000815260200160016005805490506140489190615d3a565b81526000602091820181905283546001808201865594825290829020835160079092020180546001600160a01b0319166001600160a01b03909216919091178155908201519281019290925560408101516002830155606081015160038301556080810151600483015560a0810151600583015560c0015160069091015550505050565b606060008251600014156141505760408051600480825260a0820190925290602082016080803683370190505091505b600481101561414b57614110816001615cef565b61411c906107d0615d1b565b82828151811061412e5761412e615dee565b60209081029190910101528061414381615d7d565b9150506140fc565b6141e9565b82518110156141e55761271083828151811061416e5761416e615dee565b6020026020010151106141d35760405162461bcd60e51b815260206004820152602760248201527f726577617264206c6576656c2063616e206e6f74206265206d6f72652074686160448201526606e2031303030360cc1b6064820152608401610e0f565b806141dd81615d7d565b915050614150565b8291505b50919050565b61271061422d8260a00151611aac8460800151611aac8660600151611aac8860400151611aac8a602001518b60000151613d3490919063ffffffff16565b146122ac5760405162461bcd60e51b815260206004820152601d60248201527f746f74616c2073706c697420252073686f756c642062652031303030300000006044820152606401610e0f565b60006004828154811061428f5761428f615dee565b60009182526020808320858452600780835260408086203387529093529190932080549290910290920192506142f95760405162461bcd60e51b815260206004820152600f60248201526e0757365722e616d6f756e74203d203608c1b6044820152606401610e0f565b600061431e83600401546115aa856006015485600001546139f390919063ffffffff16565b825460048501549192506143329190613d40565b60048401556000808355600183015560068301546143509082613d40565b6006840155825461436b906001600160a01b03163383613d4c565b604051818152849033907fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595906020015b60405180910390a350505050565b6040516001600160a01b03808516602483015283166044820152606481018290526143e19085906323b872dd60e01b90608401613d78565b50505050565b6002600354141561440a5760405162461bcd60e51b8152600401610e0f90615b79565b600260035560008281526008602052604090206007015460ff166144705760405162461bcd60e51b815260206004820152601c60248201527f636f6d6d6974746565206e6f7420636865636b656420696e20796574000000006044820152606401610e0f565b60006004838154811061448557614485615dee565b600091825260208083208684526007808352604080862033875290935291909320910290910191506144b684612049565b8054156145005760006144eb8260010154612aea64e8d4a510006115aa876003015487600001546139f390919063ffffffff16565b905080156144fe576144fe338287614cbd565b505b82156145855760068201548254614522906001600160a01b03163330876143a9565b60068301546145319085613d34565b600684015560048301548490156145605761455d826115aa8787600401546139f390919063ffffffff16565b90505b825461456c9082613d34565b8355600484015461457d9082613d34565b600485015550505b600382015481546145a09164e8d4a51000916115aa916139f3565b6001820155604051838152849033907f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159060200160405180910390a3505060016003555050565b6145f082612049565b600061466282611aac6004868154811061460c5761460c615dee565b906000526020600020906007020160010154600560016005805490506146329190615d3a565b8154811061464257614642615dee565b906000526020600020906002020160010154613d4090919063ffffffff16565b60058054919250439161467790600190615d3a565b8154811061468757614687615dee565b90600052602060002090600202016000015414156146dc57600580548291906146b290600190615d3a565b815481106146c2576146c2615dee565b906000526020600020906002020160010181905550614753565b60408051808201909152438152602081018281526005805460018101825560009190915291517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0600290930292830155517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db1909101555b816004848154811061476757614767615dee565b906000526020600020906007020160010181905550505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614156147c4575083613760565b60405163095ea7b360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905285169063095ea7b390604401602060405180830381600087803b15801561482e57600080fd5b505af1158015614842573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614866919061541b565b6148a95760405162461bcd60e51b81526020600482015260146024820152731d1bdad95b88185c1c1c9bdd994819985a5b195960621b6044820152606401610e0f565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561490b57600080fd5b505afa15801561491f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149439190615486565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634aa4a4fc6040518163ffffffff1660e01b815260040160206040518083038186803b1580156149a057600080fd5b505afa1580156149b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149d891906153c5565b90506060816001600160a01b0316876001600160a01b03161415614a6f578551604051606089811b6bffffffffffffffffffffffff19908116602084015260e89390931b6001600160e81b03191660348301527f0000000000000000000000000000000000000000000000000000000000000000901b9091166037820152604b016040516020818303038152906040529050614b02565b855160208088015160405160608b811b6bffffffffffffffffffffffff199081169483019490945260e894851b6001600160e81b0319908116603484015287821b851660378401529290941b909116604b8201527f000000000000000000000000000000000000000000000000000000000000000090921b16604e82015260620160405160208183030381529060405290505b6040805160a0810182528281523060208201524281830152606081018a905260808101879052905163c04b8d5960e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163c04b8d5991614b729190600401615bbe565b602060405180830381600087803b158015614b8c57600080fd5b505af1158015614ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bc49190615486565b6040516370a0823160e01b8152306004820152909450859084906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b158015614c2a57600080fd5b505afa158015614c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c629190615486565b614c6c9190615d3a565b1015614cb25760405162461bcd60e51b81526020600482015260156024820152741ddc9bdb99c8185b5bdd5b9d081c9958d95a5d9959605a1b6044820152606401610e0f565b505050949350505050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015614d1f57600080fd5b505afa158015614d33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d579190615486565b905080831115614e4f5760405163a9059cbb60e01b81526001600160a01b038581166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015614dcb57600080fd5b505af1158015614ddf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e03919061541b565b50604080518281526020810185905283916001600160a01b038716917fee9cbb749817d7aa2d7b761a12c7789e3f9ac46e77f63c47e4f5f21da5e7cf0b910160405180910390a36143e1565b60405163a9059cbb60e01b81526001600160a01b038581166004830152602482018590527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015614eb957600080fd5b505af1158015614ecd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ef1919061541b565b50604080518481526020810185905283916001600160a01b038716917fee9cbb749817d7aa2d7b761a12c7789e3f9ac46e77f63c47e4f5f21da5e7cf0b910161439b565b6000614f8a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166150079092919063ffffffff16565b805190915015613daf5780806020019051810190614fa8919061541b565b613daf5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610e0f565b6060613760848460008585843b6150605760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610e0f565b600080866001600160a01b0316858760405161507c91906158ab565b60006040518083038185875af1925050503d80600081146150b9576040519150601f19603f3d011682016040523d82523d6000602084013e6150be565b606091505b50915091506150ce8282866150d9565b979650505050505050565b606083156150e85750816138d0565b8251156150f85782518084602001fd5b8160405162461bcd60e51b8152600401610e0f9190615a32565b8280548282559060005260206000209081019282156151525760005260206000209182015b82811115615152578254825591600101919060010190615137565b5061515e929150615223565b5090565b50805460008255906000526020600020908101906122ac9190615223565b828054828255906000526020600020908101928215615152579160200282015b828111156151525782518255916020019190600101906151a0565b6040518060a001604052806151ff6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b81526020016060815260200160001515815260200160008152602001600081525090565b5b8082111561515e5760008155600101615224565b600082601f83011261524957600080fd5b8135602067ffffffffffffffff82111561526557615265615e04565b8160051b615274828201615cbe565b83815282810190868401838801850189101561528f57600080fd5b600093505b858410156152b2578035835260019390930192918401918401615294565b50979650505050505050565b600082601f8301126152cf57600080fd5b813567ffffffffffffffff8111156152e9576152e9615e04565b6152fc601f8201601f1916602001615cbe565b81815284602083860101111561531157600080fd5b816020850160208301376000918101602001919091529392505050565b600060c0828403121561534057600080fd5b60405160c0810181811067ffffffffffffffff8211171561536357615363615e04565b8060405250809150823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a08201525092915050565b6000602082840312156153ba57600080fd5b81356138d081615e1a565b6000602082840312156153d757600080fd5b81516138d081615e1a565b600080604083850312156153f557600080fd5b823561540081615e1a565b9150602083013561541081615e1a565b809150509250929050565b60006020828403121561542d57600080fd5b81516138d081615e2f565b60006020828403121561544a57600080fd5b813567ffffffffffffffff81111561546157600080fd5b613760848285016152be565b60006020828403121561547f57600080fd5b5035919050565b60006020828403121561549857600080fd5b5051919050565b600080604083850312156154b257600080fd5b82359150602083013561541081615e1a565b60008060008060008060006101a080898b0312156154e157600080fd5b883597506020808a01356154f481615e1a565b975060408a013561550481615e1a565b965060608a013567ffffffffffffffff8082111561552157600080fd5b61552d8d838e01615238565b975061553c8d60808e0161532e565b96506101408c013591508082111561555357600080fd5b506155608c828d016152be565b9450508a61017f8b011261557357600080fd5b61557b615c95565b806101608c018d858e01111561559057600080fd5b600094505b60028510156155b4578035835260019490940193918301918301615595565b508094505050505092959891949750929550565b6000806000606084860312156155dd57600080fd5b8335925060208401356155ef81615e1a565b929592945050506040919091013590565b60008060008060a0858703121561561657600080fd5b8435935060208086013561562981615e1a565b935060408601359250607f8601871361564157600080fd5b615649615c95565b80606088018960a08a01111561565e57600080fd5b6000805b600281101561568f57823562ffffff8116811461567d578283fd5b85529385019391850191600101615662565b50979a969950949750955050505050565b600080604083850312156156b357600080fd5b82359150602083013567ffffffffffffffff8111156156d157600080fd5b6156dd85828601615238565b9150509250929050565b60008060e083850312156156fa57600080fd5b8235915061570b846020850161532e565b90509250929050565b6000806040838503121561572757600080fd5b50508035926020909101359150565b600080600080600060a0868803121561574e57600080fd5b8535945060208601359350604086013561576781615e2f565b9250606086013561577781615e2f565b9150608086013567ffffffffffffffff81111561579357600080fd5b61579f888289016152be565b9150509295509295909350565b6000806000606084860312156157c157600080fd5b505081359360208301359350604090920135919050565b600080600080608085870312156157ee57600080fd5b5050823594602084013594506040840135936060013592509050565b600081518084526020808501945080840160005b8381101561583a5781518752958201959082019060010161581e565b509495945050505050565b6000815180845261585d816020860160208601615d51565b601f01601f19169290920160200192915050565b805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a08301525050565b600082516158bd818460208701615d51565b9190910192915050565b6001600160a01b038c811682528b811660208301528a166040820152606081018990526080810188905260a0810187905260c0810186905260e08101859052610100810184905261016081016003841061593157634e487b7160e01b600052602160045260246000fd5b8361012083015261594761014083018415159052565b9c9b505050505050505050505050565b6001600160a01b03871681526101606020820181905260009061597c83820189615845565b90508281036040840152615990818861580a565b9150506159a06060830186615871565b6101208201939093526101400152949350505050565b6020815260006138d0602083018461580a565b6040815260006159dc604083018561580a565b90508260208301529392505050565b6020808252825482820181905260008481528281209092916040850190845b81811015615a2657835483526001938401939285019201615a0a565b50909695505050505050565b6020815260006138d06020830184615845565b6020808252600e908201526d6f6e6c7920636f6d6d697474656560901b604082015260600190565b6020808252601e908201527f76657374696e6720706572696f64732063616e6e6f74206265207a65726f0000604082015260600190565b6020808252600f908201526e6f6e6c7920676f7665726e616e636560881b604082015260600190565b6020808252601690820152751c195b991a5b99c8185c1c1c9bdd985b08195e1a5cdd60521b604082015260600190565b6020808252601c908201527f76657374696e67206475726174696f6e20697320746f6f206c6f6e6700000000604082015260600190565b60208082526025908201527f76657374696e67206475726174696f6e20736d616c6c6572207468616e20706560408201526472696f647360d81b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60c081016117098284615871565b602081526000825160a06020840152615bda60c0840182615845565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60208152615c28602082018351615871565b600060208301516101408060e0850152615c4661016085018361580a565b6040860151151561010086015260608601516101208601526080909501519301929092525090919050565b8381526001600160a01b038316602082015261010081016137606040830184615871565b6040805190810167ffffffffffffffff81118282101715615cb857615cb8615e04565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715615ce757615ce7615e04565b604052919050565b60008219821115615d0257615d02615dc2565b500190565b600082615d1657615d16615dd8565b500490565b6000816000190483118215151615615d3557615d35615dc2565b500290565b600082821015615d4c57615d4c615dc2565b500390565b60005b83811015615d6c578181015183820152602001615d54565b838111156143e15750506000910152565b6000600019821415615d9157615d91615dc2565b5060010190565b600082615da757615da7615dd8565b500690565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146122ac57600080fd5b80151581146122ac57600080fdfea264697066735822122079009a8ae3b9731756933a98158ca9c0485be9ead682ff201ad5eb91827e847764736f6c63430008060033000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c000000000000000000000000000000000000000000000000003980c218c3c0000000000000000000000000000000000000000000000000000000000000c52b10000000000000000000000000000000000000000000000000000000000002fa80000000000000000000000000a13ddfa63774c5b982d2c3e92fde3b660616ffcd000000000000000000000000e592427a0aece92de3edee1f18e0157c058615640000000000000000000000002c7daec5b1c6157c2b37b2505d5d57d6d075e39e

Deployed Bytecode

0x6080604052600436106103c35760003560e01c806382b0617d116101f2578063cbd42a701161010d578063eabcff2c116100a0578063f3fe12c91161006f578063f3fe12c914610d51578063f5e820fd14610d64578063f7cd531914610d9a578063fcecc73814610dce57600080fd5b8063eabcff2c14610cda578063ebb6bc7214610cfa578063f19451d814610d1a578063f26ae82714610d3157600080fd5b8063dd072f03116100dc578063dd072f0314610bf4578063df1b1ebe14610c14578063e02ff8f214610c82578063e2bbb15814610cba57600080fd5b8063cbd42a7014610b71578063ce2529c914610b91578063d2369c6514610bbe578063da42757814610bd457600080fd5b806399f9b05a11610185578063b2e629c711610154578063b2e629c714610af1578063b9a4bdb414610b11578063be75e74f14610b31578063c7b5184a14610b5157600080fd5b806399f9b05a14610a645780639c2a7a6d14610a9c578063aa0cd25c14610abc578063ae169a5014610ad157600080fd5b806393f1a40b116101c157806393f1a40b1461098f57806395fec613146109e3578063975532dc14610a1057806398969e8214610a4457600080fd5b806382b0617d1461090257806383867c1b1461092f57806384fcf8e51461094f5780638dbb1e3a1461096f57600080fd5b8063398488eb116102e2578063520a924d11610275578063686b656e11610244578063686b656e146108315780636e419506146108a257806374899a7e146108c25780637b550bc9146108e257600080fd5b8063520a924d1461079f5780635312ea8e146107bf5780635aa6e675146107df5780635d01ff3d146107fd57600080fd5b8063441a3e70116102b1578063441a3e701461071f57806346e301351461073f5780634f8d45ee1461075f57806351eb05a61461077f57600080fd5b8063398488eb1461068b57806339b3e826146106ab5780633a71ede8146106df5780633d8a0906146106ff57600080fd5b80631d46446a1161035a5780633207b103116103295780633207b103146105d057806334333058146105fd5780633449a8651461062a57806335bbf3161461065e57600080fd5b80631d46446a146105435780632a5ad7d0146105635780632b2f4d84146105905780632e75ab50146105b057600080fd5b80630d2edde2116103965780630d2edde21461046357806311c2aae31461047857806313401551146104c45780631526fe27146104e457600080fd5b8063081e3eda146103c85780630abb6035146103ec5780630af937f21461040e5780630b346a9e1461044e575b600080fd5b3480156103d457600080fd5b506004545b6040519081526020015b60405180910390f35b3480156103f857600080fd5b5061040c6104073660046153a8565b610de5565b005b34801561041a57600080fd5b5061043e61042936600461546d565b60106020526000908152604090205460ff1681565b60405190151581526020016103e3565b34801561045a57600080fd5b506005546103d9565b34801561046f57600080fd5b5061040c610eee565b34801561048457600080fd5b506104ac7f0000000000000000000000002c7daec5b1c6157c2b37b2505d5d57d6d075e39e81565b6040516001600160a01b0390911681526020016103e3565b3480156104d057600080fd5b506001546104ac906001600160a01b031681565b3480156104f057600080fd5b506105046104ff36600461546d565b611052565b604080516001600160a01b0390981688526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016103e3565b34801561054f57600080fd5b5061040c61055e3660046155c8565b6110ab565b34801561056f57600080fd5b506103d961057e3660046153a8565b600c6020526000908152604090205481565b34801561059c57600080fd5b5061040c6105ab3660046157ac565b6112c7565b3480156105bc57600080fd5b5061040c6105cb36600461546d565b6113a1565b3480156105dc57600080fd5b506105f06105eb36600461546d565b6113d0565b6040516103e391906159b6565b34801561060957600080fd5b5061061d610618366004615714565b611435565b6040516103e39190615bb0565b34801561063657600080fd5b506104ac7f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c81565b34801561066a57600080fd5b506103d961067936600461546d565b600f6020526000908152604090205481565b34801561069757600080fd5b5061040c6106a6366004615714565b6116b0565b3480156106b757600080fd5b506103d97f0000000000000000000000000000000000000000000000000000000000c52b1081565b3480156106eb57600080fd5b506103d96106fa36600461549f565b6116e5565b34801561070b57600080fd5b5061040c61071a36600461546d565b61170f565b34801561072b57600080fd5b5061040c61073a366004615714565b6118f9565b34801561074b57600080fd5b5061040c61075a36600461546d565b611910565b34801561076b57600080fd5b5061040c61077a3660046154c4565b611d96565b34801561078b57600080fd5b5061040c61079a36600461546d565b612049565b3480156107ab57600080fd5b5061040c6107ba366004615714565b612235565b3480156107cb57600080fd5b5061040c6107da36600461546d565b61229a565b3480156107eb57600080fd5b506000546001600160a01b03166104ac565b34801561080957600080fd5b506104ac7f000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156481565b34801561083d57600080fd5b5061087861084c36600461546d565b600d602052600090815260409020805460018201546002909201546001600160a01b0391821692911683565b604080516001600160a01b03948516815260208101939093529216918101919091526060016103e3565b3480156108ae57600080fd5b5061040c6108bd366004615714565b6122af565b3480156108ce57600080fd5b5061040c6108dd36600461546d565b61240b565b3480156108ee57600080fd5b506103d96108fd36600461546d565b6124d6565b34801561090e57600080fd5b5061092261091d36600461546d565b61256d565b6040516103e39190615c16565b34801561093b57600080fd5b5061040c61094a36600461546d565b612651565b34801561095b57600080fd5b5061040c61096a3660046156a0565b6126a8565b34801561097b57600080fd5b506103d961098a366004615714565b61279e565b34801561099b57600080fd5b506109ce6109aa36600461549f565b60076020908152600092835260408084209091529082529020805460019091015482565b604080519283526020830191909152016103e3565b3480156109ef57600080fd5b506103d96109fe3660046153a8565b600a6020526000908152604090205481565b348015610a1c57600080fd5b506103d97f000000000000000000000000000000000000000000000000003980c218c3c00081565b348015610a5057600080fd5b506103d9610a5f36600461549f565b612a0b565b348015610a7057600080fd5b506103d9610a7f3660046153e2565b600b60209081526000928352604080842090915290825290205481565b348015610aa857600080fd5b5061040c610ab73660046156e7565b612af0565b348015610ac857600080fd5b5061061d612c28565b348015610add57600080fd5b5061040c610aec36600461546d565b612c9e565b348015610afd57600080fd5b5061040c610b0c366004615736565b612ca9565b348015610b1d57600080fd5b5061040c610b2c366004615600565b612dab565b348015610b3d57600080fd5b5061040c610b4c36600461549f565b61327e565b348015610b5d57600080fd5b5061040c610b6c36600461546d565b613415565b348015610b7d57600080fd5b506109ce610b8c36600461546d565b613471565b348015610b9d57600080fd5b506103d9610bac3660046153a8565b60066020526000908152604090205481565b348015610bca57600080fd5b506103d960025481565b348015610be057600080fd5b5061040c610bef366004615714565b61349f565b348015610c0057600080fd5b5061040c610c0f366004615714565b61358f565b348015610c2057600080fd5b50601154601254601354601454601554601654601754601854610c47979695949392919088565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e0820152610100016103e3565b348015610c8e57600080fd5b506103d9610c9d36600461549f565b600e60209081526000928352604080842090915290825290205481565b348015610cc657600080fd5b5061040c610cd5366004615714565b613656565b348015610ce657600080fd5b506103d9610cf53660046157d8565b613714565b348015610d0657600080fd5b5061040c610d1536600461546d565b613768565b348015610d2657600080fd5b506103d9620f424081565b348015610d3d57600080fd5b506103d9610d4c3660046157ac565b6137df565b61040c610d5f366004615438565b6138d7565b348015610d7057600080fd5b506104ac610d7f36600461546d565b6009602052600090815260409020546001600160a01b031681565b348015610da657600080fd5b506103d97f000000000000000000000000000000000000000000000000000000000002fa8081565b348015610dda57600080fd5b506103d96202a30081565b6000546001600160a01b03163314610e185760405162461bcd60e51b8152600401610e0f90615aa4565b60405180910390fd5b6001600160a01b038116610e845760405162461bcd60e51b815260206004820152602d60248201527f476f7665726e61626c653a6e657720676f7665726e616e63652069732074686560448201526c207a65726f206164647265737360981b6064820152608401610e0f565b600180546001600160a01b038084166001600160a01b03199092168217909255426002819055600054604051929316917f6dedeac5137d4e7301332bf2cbe80d9997406cff0e2b3634c9f8c47a49989ba991610ee39190815260200190565b60405180910390a350565b6000546001600160a01b03163314610f185760405162461bcd60e51b8152600401610e0f90615aa4565b600060025411610f745760405162461bcd60e51b815260206004820152602160248201527f476f7665726e61626c653a206e6f2070656e64696e6720676f7665726e616e636044820152606560f81b6064820152608401610e0f565b6202a30060025442610f869190615d3a565b11610fee5760405162461bcd60e51b815260206004820152603260248201527f476f7665726e61626c653a2063616e6e6f7420636f6e6669726d20676f7665726044820152716e616e636520617420746869732074696d6560701b6064820152608401610e0f565b600154600080546040516001600160a01b0393841693909116917fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a91a3600154600080546001600160a01b0319166001600160a01b03909216919091178155600255565b6004818154811061106257600080fd5b600091825260209091206007909102018054600182015460028301546003840154600485015460058601546006909601546001600160a01b039095169650929491939092919087565b60008381526009602052604090205483906001600160a01b031633146110e35760405162461bcd60e51b8152600401610e0f90615a45565b6000848152600d602052604090205484906001600160a01b03161561111a5760405162461bcd60e51b8152600401610e0f90615acd565b6001600160a01b0384166111665760405162461bcd60e51b815260206004820152601360248201527262656e6566696369617279206973207a65726f60681b6044820152606401610e0f565b6013546014546111769082615cef565b6111809042615d98565b10156111c35760405162461bcd60e51b81526020600482015260126024820152711b9bdb99481cd859995d1e481c195c9a5bd960721b6044820152606401610e0f565b60008581526008602052604090206006015483106112235760405162461bcd60e51b815260206004820152601d60248201527f5f7365766572697479206973206e6f7420696e207468652072616e67650000006044820152606401610e0f565b604080516060810182526001600160a01b0386811680835260208084018881523385870181815260008d8152600d8552889020965187549087166001600160a01b0319918216178855925160018801555160029096018054969095169590911694909417909255925191825285929188917fd878c70cbed9605353e23b13b6475a2e1ef3c7d976f8495f233a1a7f4bc6811c91015b60405180910390a45050505050565b6000546001600160a01b031633146112f15760405162461bcd60e51b8152600401610e0f90615aa4565b629e340082106113135760405162461bcd60e51b8152600401610e0f90615afd565b600081116113335760405162461bcd60e51b8152600401610e0f90615a6d565b808210156113535760405162461bcd60e51b8152600401610e0f90615b34565b60008381526008602081905260408083209182018590556009909101839055518291849186917fb2c473651bf0d98b7935f0a45d2e04d804b1d00c3131bf824fb1944ff9ae8e3c91a4505050565b6000546001600160a01b031633146113cb5760405162461bcd60e51b8152600401610e0f90615aa4565b601855565b60008181526008602090815260409182902060060180548351818402810184019094528084526060939283018282801561142957602002820191906000526020600020905b815481526020019060010190808311611415575b50505050509050919050565b61146e6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60006004848154811061148357611483615dee565b9060005260206000209060070201600601549050600081116114dd5760405162461bcd60e51b8152602060048201526013602482015272746f74616c537570706c79206973207a65726f60681b6044820152606401610e0f565b600084815260086020526040902060060154831061153d5760405162461bcd60e51b815260206004820152601d60248201527f5f7365766572697479206973206e6f7420696e207468652072616e67650000006044820152606401610e0f565b6000848152600860205260408120600601805461157f91908690811061156557611565615dee565b9060005260206000200154836139f390919063ffffffff16565b90506115b061159061271080615d1b565b6000878152600860205260409020546115aa9084906139f3565b906139ff565b83526115de6115c161271080615d1b565b6000878152600860205260409020600101546115aa9084906139f3565b602084015261160f6115f261271080615d1b565b6000878152600860205260409020600201546115aa9084906139f3565b604084015261164061162361271080615d1b565b6000878152600860205260409020600301546115aa9084906139f3565b606084015261167161165461271080615d1b565b6000878152600860205260409020600401546115aa9084906139f3565b60808401526116a261168561271080615d1b565b6000878152600860205260409020600501546115aa9084906139f3565b60a084015250909392505050565b6000546001600160a01b031633146116da5760405162461bcd60e51b8152600401610e0f90615aa4565b601791909155601655565b60008281526007602090815260408083206001600160a01b03851684529091529020545b92915050565b60008181526009602052604090205481906001600160a01b031633146117475760405162461bcd60e51b8152600401610e0f90615a45565b6000828152600d602052604090205482906001600160a01b03161561177e5760405162461bcd60e51b8152600401610e0f90615acd565b6000838152600f60205260409020546117d95760405162461bcd60e51b815260206004820152601d60248201527f6e6f2070656e64696e67207365742072657761726473206c6576656c730000006044820152606401610e0f565b6015546000848152600f60205260409020546117f59042615d3a565b116118575760405162461bcd60e51b815260206004820152602c60248201527f63616e6e6f7420636f6e6669726d20736574526577617264734c6576656c732060448201526b617420746869732074696d6560a01b6064820152608401610e0f565b6000838152600f60209081526040808320600890925290912060019091018054611885926006019190615112565b506000838152600f60205260408120818155906118a56001830182615162565b5050827f37234a2297757e81787ddd776e23606f74b9ecc8562ba691b9dde3adef5089cd600860008681526020019081526020016000206006016040516118ec91906159eb565b60405180910390a2505050565b61190282613a0b565b61190c8282613b4f565b5050565b6000546001600160a01b0316331461193a5760405162461bcd60e51b8152600401610e0f90615aa4565b6002600354141561195d5760405162461bcd60e51b8152600401610e0f90615b79565b60026003556000818152600d60205260409020546001600160a01b03166119bc5760405162461bcd60e51b81526020600482015260136024820152721b9bc81c195b991a5b99c8185c1c1c9bdd985b606a1b6044820152606401610e0f565b6000818152600860209081526040808320600d808452828520835160608101855281546001600160a01b038082168352600184018054848a0152600285018054928316988501989098528a8a52949097526001600160a01b0319908116909255918690559093169091556004805491939185908110611a3d57611a3d615dee565b60009182526020808320600790920290910154908401516001600160a01b039091169250611a6c908690611435565b9050611ae5611ab28260800151611aac8460a00151611aac8660600151611aac8860400151611aac8a600001518b60200151613d3490919063ffffffff16565b90613d34565b60048781548110611ac557611ac5615dee565b906000526020600020906007020160060154613d4090919063ffffffff16565b60048681548110611af857611af8615dee565b60009182526020822060066007909202010191909155815115611c02577f0000000000000000000000002c7daec5b1c6157c2b37b2505d5d57d6d075e39e6001600160a01b031663e95cd0518461dead87600001518660000151428b6008015442611b639190615cef565b8c60090154600080600260006040518c63ffffffff1660e01b8152600401611b959b9a999897969594939291906158c7565b602060405180830381600087803b158015611baf57600080fd5b505af1158015611bc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be791906153c5565b8251909150611c02906001600160a01b038516908390613d4c565b83516020830151611c1d916001600160a01b03861691613d4c565b60408085015190830151611c3b916001600160a01b03861691613d4c565b60608201516001600160a01b0384166000908152600a6020526040902054611c6291613d34565b6001600160a01b0384166000908152600a60209081526040808320939093556080850151600c90915291902054611c9891613d34565b6001600160a01b038085166000818152600c602090815260408083209590955560a087015189519094168252600b8152848220928252919091529190912054611ce091613d34565b84516001600160a01b039081166000908152600b6020908152604080832088851684528252918290209390935586519287015190519290911691889133917fb34d89b43b53d2ebac4aa01c9ab4b64aca3ca9612c3f79a58c6d2528e414775291611d4d9187908990615c71565b60405180910390a4600060048781548110611d6a57611d6a615dee565b90600052602060002090600702016006015411611d8957611d89615dac565b5050600160035550505050565b6000546001600160a01b03163314611dc05760405162461bcd60e51b8152600401610e0f90615aa4565b8051629e340011611de35760405162461bcd60e51b8152600401610e0f90615afd565b6020810151611e045760405162461bcd60e51b8152600401610e0f90615a6d565b602081015181511015611e295760405162461bcd60e51b8152600401610e0f90615b34565b6001600160a01b038516611e735760405162461bcd60e51b8152602060048201526011602482015270636f6d6d6974746565206973207a65726f60781b6044820152606401610e0f565b611e7d8787613db4565b600454600090611e8f90600190615d3a565b600081815260096020526040812080546001600160a01b0319166001600160a01b038a16179055909150611ec2866140cc565b8551909150600090158015611ed957506020860151155b611ee35785611eeb565b611eeb612c28565b9050611ef6816141ef565b6040518060a0016040528082815260200183815260200160001515815260200185600060028110611f2957611f29615dee565b6020020151815260200185600160028110611f4657611f46615dee565b60209081029190910151909152600085815260088252604090819020835180518255808401516001830155918201516002820155606082015160038201556080820151600482015560a09091015160058201558282015180519192611fb392600685019290910190615180565b50604082015160078201805460ff1916911515919091179055606082015160088201556080909101516009909101556001600160a01b0389168a847f101333dd96212851804793a854aef45352029659781cb05bddccb6815bd86dc78b8987878b600060200201518c6001602002015160405161203596959493929190615957565b60405180910390a450505050505050505050565b60006004828154811061205e5761205e615dee565b9060005260206000209060070201905060008160020154905080431161208357505050565b600482015460055460009061209a90600190615d3a565b9050816120b557436002850155600590930192909255505050565b60006120c28685846137df565b604051633d1bb33160e21b81523060048201529091506000906001600160a01b037f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c169063f46eccc49060240160206040518083038186803b15801561212757600080fd5b505afa15801561213b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215f9190615486565b905081811061216e5781612170565b805b915081156121f9576040516340c10f1960e01b8152306004820152602481018390527f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c6001600160a01b0316906340c10f1990604401600060405180830381600087803b1580156121e057600080fd5b505af11580156121f4573d6000803e3d6000fd5b505050505b61221a61220f856115aa8564e8d4a510006139f3565b600388015490613d34565b60038701555050436002850155600590930192909255505050565b6000546001600160a01b0316331461225f5760405162461bcd60e51b8152600401610e0f90615aa4565b60138290556014819055604051819083907f47c8a5b15f6172a5053bfac488642484dd38e9c0f3073c23c5d822c4cbab530990600090a35050565b6122a381613a0b565b6122ac8161427a565b50565b600482815481106122c2576122c2615dee565b906000526020600020906007020160040154612312620f42406115aa84600487815481106122f2576122f2615dee565b906000526020600020906007020160060154613d3490919063ffffffff16565b1061235f5760405162461bcd60e51b815260206004820152601b60248201527f616d6f756e7420746f2072657761726420697320746f6f2062696700000000006044820152606401610e0f565b61239a3330836004868154811061237857612378615dee565b60009182526020909120600790910201546001600160a01b03169291906143a9565b6123b181600484815481106122f2576122f2615dee565b600483815481106123c4576123c4615dee565b90600052602060002090600702016006018190555080827f66a9deaf092dcf4f0e1ca57edbef82d4eb4df8fdd6501dc30018338a4b8f625a60405160405180910390a35050565b6016546000828152600e602090815260408083203384529091529020546124329190615cef565b42116124805760405162461bcd60e51b815260206004820152601e60248201527f70656e64696e67207769746864726177207265717565737420657869737400006044820152606401610e0f565b60175461248d9042615cef565b6000828152600e6020908152604080832033808552925280832084905551909184917f13be99dfb4b71705ce15b8b7b83d0b8aa95b5ffb84bb2830a7e2b6b858c7218e9190a450565b6000816124f4576117096124eb600143615d3a565b43600180613714565b611709612502600143615d3a565b436004612510600187615d3a565b8154811061252057612520615dee565b906000526020600020906007020160010154600560016005805490506125469190615d3a565b8154811061255657612556615dee565b906000526020600020906002020160010154613714565b6125756151bb565b600082815260086020908152604091829020825161016081018452815460a08201908152600183015460c0830152600283015460e083015260038301546101008301526004830154610120830152600583015461014083015281526006820180548551818602810186019096528086529194929385810193929083018282801561261e57602002820191906000526020600020905b81548152602001906001019080831161260a575b5050509183525050600782015460ff16151560208201526008820154604082015260099091015460609091015292915050565b60008181526009602052604090205481906001600160a01b031633146126895760405162461bcd60e51b8152600401610e0f90615a45565b506000908152600860205260409020600701805460ff19166001179055565b60008281526009602052604090205482906001600160a01b031633146126e05760405162461bcd60e51b8152600401610e0f90615a45565b6000838152600d602052604090205483906001600160a01b0316156127175760405162461bcd60e51b8152600401610e0f90615acd565b612720836140cc565b600f60008681526020019081526020016000206001019080519060200190612749929190615180565b506000848152600f6020526040908190204290819055905185917f58f0d300eb5324931fe020560b51830bc4ead10b19467f5d56af8083eed98d48916127909187916159c9565b60405180910390a250505050565b604080516103208101825261113d808252602082015261227991810191909152611e6c6060820152611ad960808201526117b160a08201526114e960c082015261127460e0820152611049610100820152610e5f610120820152610caf610140820152610b316101608201526109e06101808201526108b76101a08201526107b16101c08201526106ca6101e08201526105fe6102008201526105496102208201526104aa61024082015261041e6102608201526103a26102808201526103356102a08201526102d46102c082015261027f6102e082015260006103008201819052906019827f000000000000000000000000000000000000000000000000000000000002fa806128cf7f0000000000000000000000000000000000000000000000000000000000c52b1088615d3a565b6128d99190615d07565b6128e4906001615cef565b90505b818110156129ab5760007f0000000000000000000000000000000000000000000000000000000000c52b1061293c837f000000000000000000000000000000000000000000000000000000000002fa80615d1b565b6129469190615cef565b905080861161295557506129ab565b83612961600184615d3a565b6019811061297157612971615dee565b60200201516129808883615d3a565b61298a9190615d1b565b6129949086615cef565b9096509350806129a381615d7d565b9150506128e7565b828282116129c3576129be600183615d3a565b6129ce565b6129ce600184615d3a565b601981106129de576129de615dee565b60200201516129ed8787615d3a565b6129f79190615d1b565b612a019085615cef565b9695505050505050565b60008060048481548110612a2157612a21615dee565b60009182526020808320878452600780835260408086206001600160a01b038a168752909352919093209102909101600381015460028201549193509043118015612a70575060008360040154115b15612ac2576000612a928785600201546001600580549050610d4c9190615d3a565b9050612abe612ab785600401546115aa64e8d4a51000856139f390919063ffffffff16565b8390613d34565b9150505b612a018260010154612aea64e8d4a510006115aa8587600001546139f390919063ffffffff16565b90613d40565b6000546001600160a01b03163314612b1a5760405162461bcd60e51b8152600401610e0f90615aa4565b6000828152600d602052604090205482906001600160a01b031615612b515760405162461bcd60e51b8152600401610e0f90615acd565b601354601454612b619082615cef565b612b6b9042615d98565b10612ba85760405162461bcd60e51b815260206004820152600d60248201526c1cd859995d1e481c195c9a5bd9609a1b6044820152606401610e0f565b612bb1826141ef565b60008381526008602090815260409182902084518155908401516001820155818401516002820155606084015160038201556080840151600482015560a08401516005909101555183907fe0fe09d9a25d5360154efb63f8f8c43a9cf25b0e4715d7f9ee42b362d99c941f906118ec908590615bb0565b612c616040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060c0016040528061177081526020016107d081526020016101f48152602001600081526020016103e881526020016101f4815250905090565b6122ac8160006143e7565b6000546001600160a01b03163314612cd35760405162461bcd60e51b8152600401610e0f90615aa4565b60006001600160a01b031660048681548110612cf157612cf1615dee565b60009182526020909120600790910201546001600160a01b03161415612d4f5760405162461bcd60e51b81526020600482015260136024820152721c1bdbdb08191bd95cc81b9bdd08195e1a5cdd606a1b6044820152606401610e0f565b612d5985856145e7565b60008581526010602052604090819020805460ff19168415151790555183151590859087907fd01a08be7ba6451f751cf523b54675f30a2c5ea6fa6bd909c2fd57f296fef0b5906112b8908690615a32565b6000546001600160a01b03163314612dd55760405162461bcd60e51b8152600401610e0f90615aa4565b600060048581548110612dea57612dea615dee565b600091825260208083206007909202909101546001600160a01b03908116808452600a83526040808520549289168552600b8452808520828652845280852054600c909452842054909450909290612e4690611aac8585613d34565b905060008111612e895760405162461bcd60e51b815260206004820152600e60248201526d616d6f756e74206973207a65726f60901b6044820152606401610e0f565b6001600160a01b038085166000818152600a60209081526040808320839055600c8252808320839055938b168252600b815283822092825291909152908120819055612ed78286888a614781565b90506000612ee9836115aa84886139f3565b90508015612f6c57604051630852cd8d60e31b8152600481018290527f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c6001600160a01b0316906342966c6890602401600060405180830381600087803b158015612f5357600080fd5b505af1158015612f67573d6000803e3d6000fd5b505050505b80838b7f4f255c8cf5a84786ddc35d528b4df336f3aad1b61d63615fd8b228a39548cc9360405160405180910390a4600080612fac856115aa86896139f3565b9050801561314b577f0000000000000000000000002c7daec5b1c6157c2b37b2505d5d57d6d075e39e6001600160a01b031663e95cd0517f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c61dead8e85426011600001544261301b9190615cef565b6012546040516001600160e01b031960e08a901b168152613050979695949392919060009081906002906001906004016158c7565b602060405180830381600087803b15801561306a57600080fd5b505af115801561307e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a291906153c5565b60405163a9059cbb60e01b81526001600160a01b038083166004830152602482018490529193507f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c9091169063a9059cbb90604401602060405180830381600087803b15801561311157600080fd5b505af1158015613125573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613149919061541b565b505b848b6001600160a01b03168d7f5130497d6ba2833abd6dbfb4eb1a4bfa30540ea493ee0f3c811e44ff829697dc848660405161319a9291909182526001600160a01b0316602082015260400190565b60405180910390a47f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c6001600160a01b031663a9059cbb6131e36000546001600160a01b031690565b6131f186612aea8987613d40565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b15801561323757600080fd5b505af115801561324b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326f919061541b565b50505050505050505050505050565b6001600160a01b0381166132c85760405162461bcd60e51b8152602060048201526011602482015270636f6d6d6974746565206973207a65726f60781b6044820152606401610e0f565b6000546001600160a01b0316331480156132f957506000828152600960205260409020546001600160a01b03163314155b156133655760008281526008602052604090206007015460ff16156133605760405162461bcd60e51b815260206004820152601c60248201527f436f6d6d697474656520616c726561647920636865636b656420696e000000006044820152606401610e0f565b6133bc565b6000828152600960205260409020546001600160a01b031633146133bc5760405162461bcd60e51b815260206004820152600e60248201526d4f6e6c7920636f6d6d697474656560901b6044820152606401610e0f565b60008281526009602052604080822080546001600160a01b0319166001600160a01b0385169081179091559051909184917f2d56897538f0fc982e13469f511616bed63e0c8f65a75270ba4346266b50f2a59190a35050565b6000546001600160a01b0316331461343f5760405162461bcd60e51b8152600401610e0f90615aa4565b6000908152600d6020526040812080546001600160a01b03199081168255600182019290925560020180549091169055565b6005818154811061348157600080fd5b60009182526020909120600290910201805460019091015490915082565b6004548111156134e95760405162461bcd60e51b8152602060048201526015602482015274706f6f6c2072616e676520697320746f6f2062696760581b6044820152606401610e0f565b8082111561352e5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420706f6f6c2072616e676560701b6044820152606401610e0f565b815b818110156135515761354181612049565b61354a81615d7d565b9050613530565b5060408051838152602081018390527fd3f7645e6170879584cabe5bb42b1c424830ab0646a05d1d90bf6f641dc2e3d8910160405180910390a15050565b6000546001600160a01b031633146135b95760405162461bcd60e51b8152600401610e0f90615aa4565b62ed4e0082106135db5760405162461bcd60e51b8152600401610e0f90615afd565b600081116135fb5760405162461bcd60e51b8152600401610e0f90615a6d565b8082101561361b5760405162461bcd60e51b8152600401610e0f90615b34565b60118290556012819055604051819083907fa3d5527033c65a7e5eda0ffec2fe75b8bfc358a419914452e5e29993f531136d90600090a35050565b60008281526010602052604090205460ff16156136a65760405162461bcd60e51b815260206004820152600e60248201526d19195c1bdcda5d081c185d5cd95960921b6044820152606401610e0f565b620f42408110156136f05760405162461bcd60e51b815260206004820152601460248201527330b6b7bab73a103632b9b9903a3430b71018b29b60611b6044820152606401610e0f565b6000828152600e6020908152604080832033845290915281205561190c82826143e7565b600081156137605761375d60646115aa846115aa876137577f000000000000000000000000000000000000000000000000003980c218c3c0006137578d8d61279e565b906139f3565b90505b949350505050565b6000546001600160a01b031633146137925760405162461bcd60e51b8152600401610e0f90615aa4565b6202a3008110156137da5760405162461bcd60e51b815260206004820152601260248201527119195b185e481a5cc81d1bdbc81cda1bdc9d60721b6044820152606401610e0f565b601555565b600080600485815481106137f5576137f5615dee565b906000526020600020906007020160010154905060006004868154811061381e5761381e615dee565b90600052602060002090600702016005015490505b838110156138a8576000600561384a836001615cef565b8154811061385a5761385a615dee565b906000526020600020906002020160000154905061389161388a8783866005878154811061255657612556615dee565b8590613d34565b9095509250806138a081615d7d565b915050613833565b6138cb6138c48643856005868154811061255657612556615dee565b8490613d34565b925050505b9392505050565b60185415613964576018543410156139285760405162461bcd60e51b81526020600482015260146024820152731b9bdd08195b9bdd59da08199959481c185e595960621b6044820152606401610e0f565b600080546040516001600160a01b03909116913480156108fc02929091818181858888f19350505050158015613962573d6000803e3d6000fd5b505b336001600160a01b03167fc8fdf13a4b928b8811a082d6f49538b13d9279cc130d1312406e8fa8742997358260405161399d9190615a32565b60405180910390a250565b600080546001600160a01b0319166001600160a01b03831690811782556040519091907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a350565b60006138d08284615d1b565b60006138d08284615d07565b6000818152600d602052604090205481906001600160a01b031615613a425760405162461bcd60e51b8152600401610e0f90615acd565b601354601454613a529082615cef565b613a5c9042615d98565b10613a995760405162461bcd60e51b815260206004820152600d60248201526c1cd859995d1e481c195c9a5bd9609a1b6044820152606401610e0f565b6000828152600e6020908152604080832033845290915290205442118015613ae657506016546000838152600e60209081526040808320338452909152902054613ae39190615cef565b42105b613b325760405162461bcd60e51b815260206004820152601a60248201527f77697468647261772072657175657374206e6f742076616c69640000000000006044820152606401610e0f565b506000908152600e60209081526040808320338452909152812055565b60026003541415613b725760405162461bcd60e51b8152600401610e0f90615b79565b6002600381905550600060048381548110613b8f57613b8f615dee565b6000918252602080832086845260078083526040808620338752909352919093208054929091029092019250831115613c145760405162461bcd60e51b815260206004820152602160248201527f77697468647261773a206e6f7420656e6f75676820757365722062616c616e636044820152606560f81b6064820152608401610e0f565b613c1d84612049565b6000613c4b8260010154612aea64e8d4a510006115aa876003015487600001546139f390919063ffffffff16565b90508015613c5e57613c5e338287614cbd565b8315613cd1578154613c709085613d40565b825560048301546006840154600091613c8e916115aa9088906139f3565b6006850154909150613ca09082613d40565b60068501558354613cbb906001600160a01b03163383613d4c565b6004840154613cca9086613d40565b6004850155505b60038301548254613cec9164e8d4a51000916115aa916139f3565b6001830155604051848152859033907ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689060200160405180910390a350506001600355505050565b60006138d08284615cef565b60006138d08284615d3a565b6040516001600160a01b038316602482015260448101829052613daf90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614f35565b505050565b6001600160a01b03811660009081526006602052604090205415613e2d5760405162461bcd60e51b815260206004820152602a60248201527f4841544d61737465723a3a6164643a206c70546f6b656e20697320616c726561604482015269191e481a5b881c1bdbdb60b21b6064820152608401610e0f565b600454613e3b906001615cef565b6001600160a01b0382166000908152600660205260408120919091557f0000000000000000000000000000000000000000000000000000000000c52b104311613ea4577f0000000000000000000000000000000000000000000000000000000000c52b10613ea6565b435b60055490915060009015613eff5760058054613efa918691613eca90600190615d3a565b81548110613eda57613eda615dee565b906000526020600020906002020160010154613d3490919063ffffffff16565b613f01565b835b60055490915015801590613f47575060058054439190613f2390600190615d3a565b81548110613f3357613f33615dee565b906000526020600020906002020160000154145b15613f895760058054829190613f5f90600190615d3a565b81548110613f6f57613f6f615dee565b906000526020600020906002020160010181905550614000565b60408051808201909152438152602081018281526005805460018101825560009190915291517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0600290930292830155517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db1909101555b60046040518060e00160405280856001600160a01b03168152602001868152602001848152602001600081526020016000815260200160016005805490506140489190615d3a565b81526000602091820181905283546001808201865594825290829020835160079092020180546001600160a01b0319166001600160a01b03909216919091178155908201519281019290925560408101516002830155606081015160038301556080810151600483015560a0810151600583015560c0015160069091015550505050565b606060008251600014156141505760408051600480825260a0820190925290602082016080803683370190505091505b600481101561414b57614110816001615cef565b61411c906107d0615d1b565b82828151811061412e5761412e615dee565b60209081029190910101528061414381615d7d565b9150506140fc565b6141e9565b82518110156141e55761271083828151811061416e5761416e615dee565b6020026020010151106141d35760405162461bcd60e51b815260206004820152602760248201527f726577617264206c6576656c2063616e206e6f74206265206d6f72652074686160448201526606e2031303030360cc1b6064820152608401610e0f565b806141dd81615d7d565b915050614150565b8291505b50919050565b61271061422d8260a00151611aac8460800151611aac8660600151611aac8860400151611aac8a602001518b60000151613d3490919063ffffffff16565b146122ac5760405162461bcd60e51b815260206004820152601d60248201527f746f74616c2073706c697420252073686f756c642062652031303030300000006044820152606401610e0f565b60006004828154811061428f5761428f615dee565b60009182526020808320858452600780835260408086203387529093529190932080549290910290920192506142f95760405162461bcd60e51b815260206004820152600f60248201526e0757365722e616d6f756e74203d203608c1b6044820152606401610e0f565b600061431e83600401546115aa856006015485600001546139f390919063ffffffff16565b825460048501549192506143329190613d40565b60048401556000808355600183015560068301546143509082613d40565b6006840155825461436b906001600160a01b03163383613d4c565b604051818152849033907fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595906020015b60405180910390a350505050565b6040516001600160a01b03808516602483015283166044820152606481018290526143e19085906323b872dd60e01b90608401613d78565b50505050565b6002600354141561440a5760405162461bcd60e51b8152600401610e0f90615b79565b600260035560008281526008602052604090206007015460ff166144705760405162461bcd60e51b815260206004820152601c60248201527f636f6d6d6974746565206e6f7420636865636b656420696e20796574000000006044820152606401610e0f565b60006004838154811061448557614485615dee565b600091825260208083208684526007808352604080862033875290935291909320910290910191506144b684612049565b8054156145005760006144eb8260010154612aea64e8d4a510006115aa876003015487600001546139f390919063ffffffff16565b905080156144fe576144fe338287614cbd565b505b82156145855760068201548254614522906001600160a01b03163330876143a9565b60068301546145319085613d34565b600684015560048301548490156145605761455d826115aa8787600401546139f390919063ffffffff16565b90505b825461456c9082613d34565b8355600484015461457d9082613d34565b600485015550505b600382015481546145a09164e8d4a51000916115aa916139f3565b6001820155604051838152849033907f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159060200160405180910390a3505060016003555050565b6145f082612049565b600061466282611aac6004868154811061460c5761460c615dee565b906000526020600020906007020160010154600560016005805490506146329190615d3a565b8154811061464257614642615dee565b906000526020600020906002020160010154613d4090919063ffffffff16565b60058054919250439161467790600190615d3a565b8154811061468757614687615dee565b90600052602060002090600202016000015414156146dc57600580548291906146b290600190615d3a565b815481106146c2576146c2615dee565b906000526020600020906002020160010181905550614753565b60408051808201909152438152602081018281526005805460018101825560009190915291517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0600290930292830155517f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db1909101555b816004848154811061476757614767615dee565b906000526020600020906007020160010181905550505050565b60007f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c6001600160a01b0316846001600160a01b031614156147c4575083613760565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564811660048301526024820187905285169063095ea7b390604401602060405180830381600087803b15801561482e57600080fd5b505af1158015614842573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614866919061541b565b6148a95760405162461bcd60e51b81526020600482015260146024820152731d1bdad95b88185c1c1c9bdd994819985a5b195960621b6044820152606401610e0f565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c6001600160a01b0316906370a082319060240160206040518083038186803b15801561490b57600080fd5b505afa15801561491f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149439190615486565b905060007f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615646001600160a01b0316634aa4a4fc6040518163ffffffff1660e01b815260040160206040518083038186803b1580156149a057600080fd5b505afa1580156149b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149d891906153c5565b90506060816001600160a01b0316876001600160a01b03161415614a6f578551604051606089811b6bffffffffffffffffffffffff19908116602084015260e89390931b6001600160e81b03191660348301527f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c901b9091166037820152604b016040516020818303038152906040529050614b02565b855160208088015160405160608b811b6bffffffffffffffffffffffff199081169483019490945260e894851b6001600160e81b0319908116603484015287821b851660378401529290941b909116604b8201527f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c90921b16604e82015260620160405160208183030381529060405290505b6040805160a0810182528281523060208201524281830152606081018a905260808101879052905163c04b8d5960e01b81526001600160a01b037f000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564169163c04b8d5991614b729190600401615bbe565b602060405180830381600087803b158015614b8c57600080fd5b505af1158015614ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bc49190615486565b6040516370a0823160e01b8152306004820152909450859084906001600160a01b037f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c16906370a082319060240160206040518083038186803b158015614c2a57600080fd5b505afa158015614c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c629190615486565b614c6c9190615d3a565b1015614cb25760405162461bcd60e51b81526020600482015260156024820152741ddc9bdb99c8185b5bdd5b9d081c9958d95a5d9959605a1b6044820152606401610e0f565b505050949350505050565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c6001600160a01b0316906370a082319060240160206040518083038186803b158015614d1f57600080fd5b505afa158015614d33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d579190615486565b905080831115614e4f5760405163a9059cbb60e01b81526001600160a01b038581166004830152602482018390527f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c169063a9059cbb90604401602060405180830381600087803b158015614dcb57600080fd5b505af1158015614ddf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e03919061541b565b50604080518281526020810185905283916001600160a01b038716917fee9cbb749817d7aa2d7b761a12c7789e3f9ac46e77f63c47e4f5f21da5e7cf0b910160405180910390a36143e1565b60405163a9059cbb60e01b81526001600160a01b038581166004830152602482018590527f000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c169063a9059cbb90604401602060405180830381600087803b158015614eb957600080fd5b505af1158015614ecd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ef1919061541b565b50604080518481526020810185905283916001600160a01b038716917fee9cbb749817d7aa2d7b761a12c7789e3f9ac46e77f63c47e4f5f21da5e7cf0b910161439b565b6000614f8a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166150079092919063ffffffff16565b805190915015613daf5780806020019051810190614fa8919061541b565b613daf5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610e0f565b6060613760848460008585843b6150605760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610e0f565b600080866001600160a01b0316858760405161507c91906158ab565b60006040518083038185875af1925050503d80600081146150b9576040519150601f19603f3d011682016040523d82523d6000602084013e6150be565b606091505b50915091506150ce8282866150d9565b979650505050505050565b606083156150e85750816138d0565b8251156150f85782518084602001fd5b8160405162461bcd60e51b8152600401610e0f9190615a32565b8280548282559060005260206000209081019282156151525760005260206000209182015b82811115615152578254825591600101919060010190615137565b5061515e929150615223565b5090565b50805460008255906000526020600020908101906122ac9190615223565b828054828255906000526020600020908101928215615152579160200282015b828111156151525782518255916020019190600101906151a0565b6040518060a001604052806151ff6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b81526020016060815260200160001515815260200160008152602001600081525090565b5b8082111561515e5760008155600101615224565b600082601f83011261524957600080fd5b8135602067ffffffffffffffff82111561526557615265615e04565b8160051b615274828201615cbe565b83815282810190868401838801850189101561528f57600080fd5b600093505b858410156152b2578035835260019390930192918401918401615294565b50979650505050505050565b600082601f8301126152cf57600080fd5b813567ffffffffffffffff8111156152e9576152e9615e04565b6152fc601f8201601f1916602001615cbe565b81815284602083860101111561531157600080fd5b816020850160208301376000918101602001919091529392505050565b600060c0828403121561534057600080fd5b60405160c0810181811067ffffffffffffffff8211171561536357615363615e04565b8060405250809150823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a08201525092915050565b6000602082840312156153ba57600080fd5b81356138d081615e1a565b6000602082840312156153d757600080fd5b81516138d081615e1a565b600080604083850312156153f557600080fd5b823561540081615e1a565b9150602083013561541081615e1a565b809150509250929050565b60006020828403121561542d57600080fd5b81516138d081615e2f565b60006020828403121561544a57600080fd5b813567ffffffffffffffff81111561546157600080fd5b613760848285016152be565b60006020828403121561547f57600080fd5b5035919050565b60006020828403121561549857600080fd5b5051919050565b600080604083850312156154b257600080fd5b82359150602083013561541081615e1a565b60008060008060008060006101a080898b0312156154e157600080fd5b883597506020808a01356154f481615e1a565b975060408a013561550481615e1a565b965060608a013567ffffffffffffffff8082111561552157600080fd5b61552d8d838e01615238565b975061553c8d60808e0161532e565b96506101408c013591508082111561555357600080fd5b506155608c828d016152be565b9450508a61017f8b011261557357600080fd5b61557b615c95565b806101608c018d858e01111561559057600080fd5b600094505b60028510156155b4578035835260019490940193918301918301615595565b508094505050505092959891949750929550565b6000806000606084860312156155dd57600080fd5b8335925060208401356155ef81615e1a565b929592945050506040919091013590565b60008060008060a0858703121561561657600080fd5b8435935060208086013561562981615e1a565b935060408601359250607f8601871361564157600080fd5b615649615c95565b80606088018960a08a01111561565e57600080fd5b6000805b600281101561568f57823562ffffff8116811461567d578283fd5b85529385019391850191600101615662565b50979a969950949750955050505050565b600080604083850312156156b357600080fd5b82359150602083013567ffffffffffffffff8111156156d157600080fd5b6156dd85828601615238565b9150509250929050565b60008060e083850312156156fa57600080fd5b8235915061570b846020850161532e565b90509250929050565b6000806040838503121561572757600080fd5b50508035926020909101359150565b600080600080600060a0868803121561574e57600080fd5b8535945060208601359350604086013561576781615e2f565b9250606086013561577781615e2f565b9150608086013567ffffffffffffffff81111561579357600080fd5b61579f888289016152be565b9150509295509295909350565b6000806000606084860312156157c157600080fd5b505081359360208301359350604090920135919050565b600080600080608085870312156157ee57600080fd5b5050823594602084013594506040840135936060013592509050565b600081518084526020808501945080840160005b8381101561583a5781518752958201959082019060010161581e565b509495945050505050565b6000815180845261585d816020860160208601615d51565b601f01601f19169290920160200192915050565b805182526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a08301525050565b600082516158bd818460208701615d51565b9190910192915050565b6001600160a01b038c811682528b811660208301528a166040820152606081018990526080810188905260a0810187905260c0810186905260e08101859052610100810184905261016081016003841061593157634e487b7160e01b600052602160045260246000fd5b8361012083015261594761014083018415159052565b9c9b505050505050505050505050565b6001600160a01b03871681526101606020820181905260009061597c83820189615845565b90508281036040840152615990818861580a565b9150506159a06060830186615871565b6101208201939093526101400152949350505050565b6020815260006138d0602083018461580a565b6040815260006159dc604083018561580a565b90508260208301529392505050565b6020808252825482820181905260008481528281209092916040850190845b81811015615a2657835483526001938401939285019201615a0a565b50909695505050505050565b6020815260006138d06020830184615845565b6020808252600e908201526d6f6e6c7920636f6d6d697474656560901b604082015260600190565b6020808252601e908201527f76657374696e6720706572696f64732063616e6e6f74206265207a65726f0000604082015260600190565b6020808252600f908201526e6f6e6c7920676f7665726e616e636560881b604082015260600190565b6020808252601690820152751c195b991a5b99c8185c1c1c9bdd985b08195e1a5cdd60521b604082015260600190565b6020808252601c908201527f76657374696e67206475726174696f6e20697320746f6f206c6f6e6700000000604082015260600190565b60208082526025908201527f76657374696e67206475726174696f6e20736d616c6c6572207468616e20706560408201526472696f647360d81b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60c081016117098284615871565b602081526000825160a06020840152615bda60c0840182615845565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60208152615c28602082018351615871565b600060208301516101408060e0850152615c4661016085018361580a565b6040860151151561010086015260608601516101208601526080909501519301929092525090919050565b8381526001600160a01b038316602082015261010081016137606040830184615871565b6040805190810167ffffffffffffffff81118282101715615cb857615cb8615e04565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715615ce757615ce7615e04565b604052919050565b60008219821115615d0257615d02615dc2565b500190565b600082615d1657615d16615dd8565b500490565b6000816000190483118215151615615d3557615d35615dc2565b500290565b600082821015615d4c57615d4c615dc2565b500390565b60005b83811015615d6c578181015183820152602001615d54565b838111156143e15750506000910152565b6000600019821415615d9157615d91615dc2565b5060010190565b600082615da757615da7615dd8565b500690565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146122ac57600080fd5b80151581146122ac57600080fdfea264697066735822122079009a8ae3b9731756933a98158ca9c0485be9ead682ff201ad5eb91827e847764736f6c63430008060033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c000000000000000000000000000000000000000000000000003980c218c3c0000000000000000000000000000000000000000000000000000000000000c52b10000000000000000000000000000000000000000000000000000000000002fa80000000000000000000000000a13ddfa63774c5b982d2c3e92fde3b660616ffcd000000000000000000000000e592427a0aece92de3edee1f18e0157c058615640000000000000000000000002c7daec5b1c6157c2b37b2505d5d57d6d075e39e

-----Decoded View---------------
Arg [0] : _rewardsToken (address): 0x685D939C8FE6CCe02f3C7Cbc37d024E99570812c
Arg [1] : _rewardPerBlock (uint256): 16185644800000000
Arg [2] : _startBlock (uint256): 12921616
Arg [3] : _multiplierPeriod (uint256): 195200
Arg [4] : _hatGovernance (address): 0xa13DDFA63774C5b982d2C3E92fDe3b660616FfCd
Arg [5] : _uniSwapRouter (address): 0xE592427A0AEce92De3Edee1F18E0157C05861564
Arg [6] : _tokenLockFactory (address): 0x2c7dAec5B1C6157C2b37B2505d5D57d6D075E39E

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000685d939c8fe6cce02f3c7cbc37d024e99570812c
Arg [1] : 000000000000000000000000000000000000000000000000003980c218c3c000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000c52b10
Arg [3] : 000000000000000000000000000000000000000000000000000000000002fa80
Arg [4] : 000000000000000000000000a13ddfa63774c5b982d2c3e92fde3b660616ffcd
Arg [5] : 000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Arg [6] : 0000000000000000000000002c7daec5b1c6157c2b37b2505d5d57d6d075e39e


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
Chain Token Portfolio % Price Amount Value
ETH23.77%$0.99933623,704.4509$23,688.71
ETH22.89%$0.022691,005,024.5267$22,803.69
ETH17.40%$0.63551227,287.6198$17,341.61
ETH15.86%$1.5810,000$15,800
ETH11.62%$0.046332250,000$11,582.89
ETH3.17%$0.06298350,100$3,155.45
ETH1.81%$0.014781121,793.2029$1,800.23
ETH1.36%$11,351.0649$1,351.12
ETH0.87%$1.35641.3408$865.81
ETH0.52%$0.999385518.4435$518.12
ETH0.34%$0.01570521,639.1315$339.85
ETH0.26%$0.0001491,755,000$260.97
ETH0.10%$1.1188.8$98.57
ETH0.02%$0.00059233,837.368$20.02
ETH0.01%$0.2816745$12.68
ETH<0.01%$0.9994763.0004$3
MATIC<0.01%$0.4258820.0001$0.000043
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.