ETH Price: $2,135.42 (+2.31%)

Contract

0x5b250dF8B491994f59eB5fb3CAa2c3b02cFcCEc7
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Claim127982262021-07-10 7:07:391709 days ago1625900859IN
0x5b250dF8...02cFcCEc7
0 ETH0.0007176712
Claim Deposits127872542021-07-08 14:35:461711 days ago1625754946IN
0x5b250dF8...02cFcCEc7
0 ETH0.0024816536.1
Claim127836972021-07-08 1:00:431711 days ago1625706043IN
0x5b250dF8...02cFcCEc7
0 ETH0.0021813628
Unstake127697052021-07-05 20:40:161714 days ago1625517616IN
0x5b250dF8...02cFcCEc7
0 ETH0.0042036414.3
Claim127697032021-07-05 20:40:061714 days ago1625517606IN
0x5b250dF8...02cFcCEc7
0 ETH0.0012750514.3
Stake127609342021-07-04 12:08:471715 days ago1625400527IN
0x5b250dF8...02cFcCEc7
0 ETH0.0041946110
Stake127344092021-06-30 9:06:321719 days ago1625043992IN
0x5b250dF8...02cFcCEc7
0 ETH0.0053062518
Claim126855682021-06-22 18:16:041727 days ago1624385764IN
0x5b250dF8...02cFcCEc7
0 ETH0.0020393834.1
Unstake126855242021-06-22 18:04:331727 days ago1624385073IN
0x5b250dF8...02cFcCEc7
0 ETH0.0102141434.1
Stake126788792021-06-21 17:07:571728 days ago1624295277IN
0x5b250dF8...02cFcCEc7
0 ETH0.0030651
Stake126747592021-06-21 1:24:541728 days ago1624238694IN
0x5b250dF8...02cFcCEc7
0 ETH0.0032341810
Claim Deposits126697232021-06-20 6:47:221729 days ago1624171642IN
0x5b250dF8...02cFcCEc7
0 ETH0.000515066
Unstake126500262021-06-17 5:19:251732 days ago1623907165IN
0x5b250dF8...02cFcCEc7
0 ETH0.0029953510
Claim Deposits126376972021-06-15 7:23:581734 days ago1623741838IN
0x5b250dF8...02cFcCEc7
0 ETH0.0007561811
Stake126143002021-06-11 16:23:491738 days ago1623428629IN
0x5b250dF8...02cFcCEc7
0 ETH0.0109542831
Unstake126070152021-06-10 13:19:371739 days ago1623331177IN
0x5b250dF8...02cFcCEc7
0 ETH0.0033461112
Claim126069842021-06-10 13:15:081739 days ago1623330908IN
0x5b250dF8...02cFcCEc7
0 ETH0.0011769713.2
Stake126017782021-06-09 17:57:411740 days ago1623261461IN
0x5b250dF8...02cFcCEc7
0 ETH0.0092557529
Claim Deposits125663232021-06-04 6:23:141745 days ago1622787794IN
0x5b250dF8...02cFcCEc7
0 ETH0.0019744123
Claim125563742021-06-02 17:14:321747 days ago1622654072IN
0x5b250dF8...02cFcCEc7
0 ETH0.0024074527
Unstake125420192021-05-31 12:05:261749 days ago1622462726IN
0x5b250dF8...02cFcCEc7
0 ETH0.005827923
Claim125419322021-05-31 11:44:451749 days ago1622461485IN
0x5b250dF8...02cFcCEc7
0 ETH0.0012699216.5
Unstake125404202021-05-31 6:09:441749 days ago1622441384IN
0x5b250dF8...02cFcCEc7
0 ETH0.0039705915.6601911
Stake125249342021-05-28 20:28:461752 days ago1622233726IN
0x5b250dF8...02cFcCEc7
0 ETH0.008224825
Claim Deposits123831372021-05-06 21:21:201774 days ago1620336080IN
0x5b250dF8...02cFcCEc7
0 ETH0.0050870574
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
-116205262021-01-09 12:23:091891 days ago1610194989
0x5b250dF8...02cFcCEc7
 Contract Creation0 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RewardsType5

Compiler Version
v0.6.2+commit.bacdbe57

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
pragma solidity ^0.6.0;
import "./RewardsV2.sol";
import "./ReferralRewardsType5.sol";

contract RewardsType5 is RewardsV2 {
    event WithdrawRequested(
        address indexed user,
        uint256 id,
        uint256 amount,
        uint256 timelock
    );

    struct Request {
        uint256 timelock; // Wnen the unstake can be executed
        uint256 amount; // Amount to be withdrawn
        Status status; // Request status
    }
    enum Status {NONE, PENDING, EXECUTED} // Unstake request status
    mapping(address => Request[]) public unstakeRequests; // Requests list per each user
    mapping(address => uint256) public requestHead; // The first pending unstake request in the user's requests list

    /// @dev Constructor that initializes the most important configurations.
    /// @param _token Token to be staked and harvested.
    /// @param _rewards Old main farming contract.
    /// @param _referralTree Contract with referral's tree.
    constructor(
        IMintableBurnableERC20 _token,
        IRewards _rewards,
        IReferralTree _referralTree
    ) public RewardsV2(_token, 0, 57870370370) {
        ReferralRewardsType5 newRreferralRewards =
            new ReferralRewardsType5(
                _token,
                _referralTree,
                _rewards,
                IRewardsV2(address(this)),
                [uint256(5000 * 1e18), 2000 * 1e18, 100 * 1e18],
                [[uint256(0), 0, 0], [uint256(0), 0, 0], [uint256(0), 0, 0]],
                [
                    [uint256(6 * 1e16), 2 * 1e16, 1 * 1e16],
                    [uint256(5 * 1e16), 15 * 1e15, 75 * 1e14],
                    [uint256(4 * 1e16), 1 * 1e16, 5 * 1e15]
                ]
            );
        newRreferralRewards.transferOwnership(_msgSender());
        referralRewards = IReferralRewardsV2(address(newRreferralRewards));
    }

    /// @dev Allows to unstake deposit amount.
    /// @param _amount Amount to be unstaked.
    function unstake(uint256 _amount) public {
        updateStakingReward(msg.sender);
        UserInfo storage user = userInfo[msg.sender];
        if (_amount == 0) {
            _amount = user.amount;
        }
        user.amount = user.amount.sub(_amount);
        user.unfrozen = user.unfrozen.add(_amount);
        totalStake = totalStake.sub(_amount);
        uint256 id = unstakeRequests[msg.sender].length;
        unstakeRequests[msg.sender].push(
            Request({
                timelock: now + 3 days,
                amount: _amount,
                status: Status.PENDING
            })
        );
        emit WithdrawRequested(msg.sender, id, _amount, now + 3 days);
        referralRewards.handleDepositEnd(msg.sender, _amount);
    }

    /// @dev Executes unstake requests if timelock passed.
    /// @param _user Address of the user.
    /// @param _count How many deposits to claim.
    function executeUnstakes(address _user, uint256 _count) internal override {
        _count = (_count == 0)
            ? unstakeRequests[_user].length
            : Math.min(
                unstakeRequests[_user].length,
                requestHead[_user].add(_count)
            );
        for (
            uint256 requestId = requestHead[_user];
            requestId < _count;
            requestId++
        ) {
            Request storage request = unstakeRequests[_user][requestId];
            if (request.timelock < now && request.status == Status.PENDING) {
                request.status = Status.EXECUTED;
                UserInfo storage user = userInfo[_user];
                user.unfrozen = user.unfrozen.sub(request.amount);
                safeTokenTransfer(_user, request.amount);
                emit Withdraw(_user, requestId, request.amount, 0, now);
                requestHead[_user] = requestHead[_user].add(1);
            }
        }
    }

    /// @dev Returns user's unclaimed reward.
    /// @param _includeDeposit Should the finnished deposits be included into calculations.
    /// @return _reward User's reward.
    function getPendingReward(address _user, bool _includeDeposit)
        public
        view
        override
        returns (uint256 _reward)
    {
        UserInfo storage user = userInfo[_user];
        _reward = user.claimable.add(
            now.sub(user.lastUpdate).mul(user.amount).mul(rewardPerSec).div(
                1e18
            )
        );
        if (_includeDeposit) {
            for (
                uint256 requestId = requestHead[_user];
                requestId < unstakeRequests[_user].length;
                requestId++
            ) {
                Request storage request = unstakeRequests[_user][requestId];
                if (
                    request.timelock < now && request.status == Status.PENDING
                ) {
                    _reward = _reward.add(request.amount);
                }
            }
        }
    }

    // /// @dev Returns user's unstake requests length.
    // /// @param _user Address of the user.
    // /// @return Number of unstake requests.
    function getRequestsLength(address _user) public view returns (uint256) {
        return unstakeRequests[_user].length;
    }

    /// @dev Returns unclaimed rewardsV2.
    /// @return All unclaimed rewardsV2.
    function getTotalPendingRewards() public view returns (uint256) {
        return now.sub(lastUpdate).mul(totalStake).mul(rewardPerSec).div(1e18);
    }

    /// @dev Returns assessed rewardsV2.
    /// @return All assessed rewardsV2.
    function getTotalRewards() public view returns (uint256) {
        return
            totalClaimed.add(getTotalPendingRewards()).sub(totalClaimed).div(
                1e18
            );
    }

    /// @dev Returns user's ended deposits.
    /// @param _user Address of the user.
    /// @return _count Number of the deposit's that can be withdrawn.
    function getEndedDepositsCount(address _user)
        public
        view
        override
        returns (uint256 _count)
    {
        for (
            uint256 requestId = requestHead[_user];
            requestId < unstakeRequests[_user].length;
            requestId++
        ) {
            Request storage request = unstakeRequests[_user][requestId];
            if (request.timelock < now && request.status == Status.PENDING) {
                _count = _count.add(1);
            }
        }
    }
}

pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

import "./ReferralRewardsV2.sol";

contract ReferralRewardsType5 is ReferralRewardsV2 {
    /// @dev Constructor that initializes the most important configurations.
    /// @param _token Token to be staked and harvested.
    /// @param _referralTree Contract with referral's tree.
    /// @param _rewards Old farming contract.
    /// @param _rewardsV2 Main farming contract.
    /// @param _depositBounds Limits of referral's stake used to determine the referral rate.
    /// @param _depositRate Referral rates based on referral's deplth and stake received from deposit.
    /// @param _stakingRate Referral rates based on referral's deplth and stake received from staking.
    constructor(
        IMintableBurnableERC20 _token,
        IReferralTree _referralTree,
        IRewards _rewards,
        IRewardsV2 _rewardsV2,
        uint256[amtLevels] memory _depositBounds,
        uint256[referDepth][amtLevels] memory _depositRate,
        uint256[referDepth][amtLevels] memory _stakingRate
    )
        public
        ReferralRewardsV2(
            _token,
            _referralTree,
            _rewards,
            _rewardsV2,
            _depositBounds,
            _depositRate,
            _stakingRate
        )
    {}

    /// @dev Allows the main farming contract to assess referral deposit rewardsV2.
    /// @param _referrer Address of the referred user.
    /// @param _referral Address of the user.
    /// @param _amount Amount of new deposit.
    function proccessDeposit(
        address _referrer,
        address _referral,
        uint256 _amount
    ) external override {
        require(
            msg.sender == address(rewardsV2),
            "assessReferalDepositReward: bad role"
        );
        referralTree.setReferral(_referrer, _referral);
        referralReward[_referrer].totalDeposit = referralReward[_referrer]
            .totalDeposit
            .add(_amount);
        address[] memory referrals =
            referralTree.getReferrals(_referrer, referDepth);
        for (uint256 i = 0; i < referrals.length; i++) {
            if (referrals[i] == address(0)) {
                continue;
            }
            accumulateReward(referrals[i]);
            ReferralInfo storage referralInfo = referralReward[referrals[i]];
            referralInfo.amounts[i] = referralInfo.amounts[i].add(_amount);
        }
    }
}

pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IMintableBurnableERC20.sol";
import "./interfaces/IReferralTree.sol";
import "./interfaces/IRewardsV2.sol";
import "./interfaces/IRewards.sol";

contract ReferralRewardsV2 is Ownable {
    using SafeMath for uint256;

    event ReferralDepositReward(
        address indexed refferer,
        address indexed refferal,
        uint256 indexed level,
        uint256 amount
    );
    event ReferralRewardPaid(address indexed user, uint256 amount);

    // Info of each referral
    struct ReferralInfo {
        uint256 totalDeposit; // Ammount of own deposits
        uint256 reward; // Ammount of collected deposit rewardsV2
        uint256 lastUpdate; // Last time the referral claimed rewardsV2
        uint256[amtLevels] amounts; // Amounts that generate rewardsV2 on each referral level
    }

    uint256 public constant amtLevels = 3; // Number of levels by total staked amount that determine referral reward's rate
    uint256 public constant referDepth = 3; // Number of referral levels that can receive dividends

    IMintableBurnableERC20 public token; // Harvested token contract
    IReferralTree public referralTree; // Contract with referral's tree
    IRewardsV2 rewardsV2; // Main farming contract
    IRewards rewards; // Main farming contract

    uint256[amtLevels] public depositBounds; // Limits of referral's stake used to determine the referral rate
    uint256[referDepth][amtLevels] public depositRate; // Referral rates based on referral's deplth and stake received from deposit
    uint256[referDepth][amtLevels] public stakingRate; // Referral rates based on referral's deplth and stake received from staking

    mapping(address => ReferralInfo) public referralReward; // Info per each referral

    /// @dev Constructor that initializes the most important configurations.
    /// @param _token Token to be staked and harvested.
    /// @param _referralTree Contract with referral's tree.
    /// @param _rewards Main farming contract.
    /// @param _depositBounds Limits of referral's stake used to determine the referral rate.
    /// @param _depositRate Referral rates based on referral's deplth and stake received from deposit.
    /// @param _stakingRate Referral rates based on referral's deplth and stake received from staking.
    constructor(
        IMintableBurnableERC20 _token,
        IReferralTree _referralTree,
        IRewards _rewards,
        IRewardsV2 _rewardsV2,
        uint256[amtLevels] memory _depositBounds,
        uint256[referDepth][amtLevels] memory _depositRate,
        uint256[referDepth][amtLevels] memory _stakingRate
    ) public Ownable() {
        token = _token;
        referralTree = _referralTree;
        depositBounds = _depositBounds;
        depositRate = _depositRate;
        stakingRate = _stakingRate;
        rewardsV2 = _rewardsV2;
        rewards = _rewards;
    }

    /// @dev Allows an owner to update bounds.
    /// @param _depositBounds Limits of referral's stake used to determine the referral rate.
    function setBounds(uint256[amtLevels] memory _depositBounds)
        public
        onlyOwner
    {
        depositBounds = _depositBounds;
    }

    /// @dev Allows an owner to update deposit rates.
    /// @param _depositRate Referral rates based on referral's deplth and stake received from deposit.
    function setDepositRate(uint256[referDepth][amtLevels] memory _depositRate)
        public
        onlyOwner
    {
        depositRate = _depositRate;
    }

    /// @dev Allows an owner to update staking rates.
    /// @param _stakingRate Referral rates based on referral's deplth and stake received from staking.
    function setStakingRate(uint256[referDepth][amtLevels] memory _stakingRate)
        public
        onlyOwner
    {
        stakingRate = _stakingRate;
    }

    /// @dev Allows the main farming contract to assess referral deposit rewardsV2.
    /// @param _referrer Address of the referred user.
    /// @param _referral Address of the user.
    /// @param _amount Amount of new deposit.
    function proccessDeposit(
        address _referrer,
        address _referral,
        uint256 _amount
    ) external virtual {
        require(
            msg.sender == address(rewardsV2),
            "assessReferalDepositReward: bad role"
        );
        referralTree.setReferral(_referrer, _referral);
        referralReward[_referrer].totalDeposit = referralReward[_referrer]
            .totalDeposit
            .add(_amount);
        address[] memory referrals =
            referralTree.getReferrals(_referrer, referDepth);
        uint256[] memory referralStakes = rewards.getReferralStakes(referrals);
        for (uint256 level = 0; level < referrals.length; level++) {
            if (referrals[level] == address(0)) {
                continue;
            }
            accumulateReward(referrals[level]);
            ReferralInfo storage referralInfo =
                referralReward[referrals[level]];
            referralInfo.amounts[level] = referralInfo.amounts[level].add(
                _amount
            );
            uint256 percent =
                getDepositRate(
                    referralInfo.totalDeposit.add(referralStakes[level]),
                    level
                );
            if (percent == 0) {
                continue;
            }
            uint256 depositReward = _amount.mul(percent);
            if (depositReward > 0) {
                referralInfo.reward = referralInfo.reward.add(depositReward);
                emit ReferralDepositReward(
                    _referrer,
                    referrals[level],
                    level,
                    depositReward
                );
            }
        }
    }

    /// @dev Allows the main farming contract to assess referral deposit rewardsV2.
    /// @param _referrer Address of the referred user.
    /// @param _amount Amount of new deposit.
    function handleDepositEnd(address _referrer, uint256 _amount)
        external
        virtual
    {
        require(msg.sender == address(rewardsV2), "handleDepositEnd: bad role");
        referralReward[_referrer].totalDeposit = referralReward[_referrer]
            .totalDeposit
            .sub(_amount);
        address[] memory referrals =
            referralTree.getReferrals(_referrer, referDepth);
        for (uint256 level = 0; level < referrals.length; level++) {
            if (referrals[level] == address(0)) {
                continue;
            }
            accumulateReward(referrals[level]);
            ReferralInfo storage referralInfo =
                referralReward[referrals[level]];
            referralInfo.amounts[level] = referralInfo.amounts[level].sub(
                _amount
            );
        }
    }

    /// @dev Allows a user to claim his dividends.
    function claimDividends() public {
        claimUserDividends(msg.sender);
    }

    /// @dev Allows a referral tree to claim all the dividends.
    /// @param _referral Address of user that claims his dividends.
    function claimAllDividends(address _referral) public {
        require(
            msg.sender == address(referralTree),
            "claimAllDividends: bad role"
        );
        claimUserDividends(_referral);
    }

    /// @dev Update the staking referral reward for _user.
    /// @param _user Address of the referral.
    function accumulateReward(address _user) internal {
        ReferralInfo storage referralInfo = referralReward[_user];
        if (referralInfo.lastUpdate > now) {
            return;
        }
        uint256 rewardPerSec = rewardsV2.rewardPerSec();
        uint256 referralPrevStake = rewards.getReferralStake(_user);
        uint256[referDepth] memory rates =
            getStakingRateRange(
                referralInfo.totalDeposit.add(referralPrevStake)
            );
        if (referralInfo.lastUpdate > 0) {
            for (uint256 i = 0; i < referralInfo.amounts.length; i++) {
                uint256 reward =
                    now
                        .sub(referralInfo.lastUpdate)
                        .mul(referralInfo.amounts[i])
                        .mul(rewardPerSec)
                        .mul(rates[i])
                        .div(1e18);
                if (reward > 0) {
                    referralInfo.reward = referralInfo.reward.add(reward);
                }
            }
        }
        referralInfo.lastUpdate = now;
    }

    /// @dev Asses and distribute claimed dividends.
    /// @param _user Address of user that claims dividends.
    function claimUserDividends(address _user) internal {
        accumulateReward(_user);
        ReferralInfo storage referralInfo = referralReward[_user];
        uint256 amount = referralInfo.reward.div(1e18);
        if (amount > 0) {
            uint256 scaledReward = amount.mul(1e18);
            referralInfo.reward = referralInfo.reward.sub(scaledReward);
            token.mint(_user, amount);
            emit ReferralRewardPaid(_user, amount);
        }
    }

    /// @dev Returns referral reward.
    /// @param _user Address of referral.
    /// @return Referral reward.
    function getReferralReward(address _user) external view returns (uint256) {
        ReferralInfo storage referralInfo = referralReward[_user];
        uint256 rewardPerSec = rewardsV2.rewardPerSec();
        uint256 referralPrevStake = rewards.getReferralStake(_user);
        uint256[referDepth] memory rates =
            getStakingRateRange(
                referralInfo.totalDeposit.add(referralPrevStake)
            );
        uint256 _reward = referralInfo.reward;
        if (referralInfo.lastUpdate > 0) {
            for (uint256 i = 0; i < referralInfo.amounts.length; i++) {
                _reward = _reward.add(
                    now
                        .sub(referralInfo.lastUpdate)
                        .mul(referralInfo.amounts[i])
                        .mul(rewardPerSec)
                        .mul(rates[i])
                        .div(1e18)
                );
            }
        }
        return _reward.div(1e18);
    }

    /// @dev Returns direct user referral.
    /// @param _user Address of referrer.
    /// @return Direct user referral.
    function getReferral(address _user) public view returns (address) {
        return referralTree.referrals(_user);
    }

    /// @dev Returns stakong rate for the spesific referral stake.
    /// @param _referralStake Amount staked by referral.
    /// @return _rates Array of stakong rates by referral level.
    function getStakingRateRange(uint256 _referralStake)
        public
        view
        returns (uint256[referDepth] memory _rates)
    {
        for (uint256 i = 0; i < depositBounds.length; i++) {
            if (_referralStake >= depositBounds[i]) {
                return stakingRate[i];
            }
        }
    }

    /// @dev Returns deposit rate based on the spesific referral stake and referral level.
    /// @param _referralStake Amount staked by referrals.
    /// @param _level Level of the referral.
    /// @return _rate Deposit rates by referral level.
    function getDepositRate(uint256 _referralStake, uint256 _level)
        public
        view
        returns (uint256 _rate)
    {
        for (uint256 j = 0; j < depositBounds.length; j++) {
            if (_referralStake >= depositBounds[j]) {
                return depositRate[j][_level];
            }
        }
    }

    /// @dev Returns limits of referral's stake used to determine the referral rate.
    /// @return Array of deposit bounds.
    function getDepositBounds()
        public
        view
        returns (uint256[referDepth] memory)
    {
        return depositBounds;
    }

    /// @dev Returns referral rates based on referral's deplth and stake received from staking.
    /// @return Array of staking rates.
    function getStakingRates()
        public
        view
        returns (uint256[referDepth][amtLevels] memory)
    {
        return stakingRate;
    }

    /// @dev Returns referral rates based on referral's deplth and stake received from deposit.
    /// @return Array of deposit rates.
    function getDepositRates()
        public
        view
        returns (uint256[referDepth][amtLevels] memory)
    {
        return depositRate;
    }

    /// @dev Returns amounts that generate reward for referral bu levels.
    /// @param _user Address of referral.
    /// @return Returns amounts that generate reward for referral bu levels.
    function getReferralAmounts(address _user)
        public
        view
        returns (uint256[amtLevels] memory)
    {
        ReferralInfo memory referralInfo = referralReward[_user];
        return referralInfo.amounts;
    }
}

pragma solidity ^0.6.0;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IMintableBurnableERC20.sol";
import "./interfaces/IReferralRewardsV2.sol";

abstract contract RewardsV2 is Ownable {
    using SafeMath for uint256;

    event Deposit(
        address indexed user,
        uint256 indexed id,
        uint256 amount,
        uint256 start,
        uint256 end
    );
    event Withdraw(
        address indexed user,
        uint256 indexed id,
        uint256 amount,
        uint256 ended,
        uint256 time
    );
    event RewardPaid(address indexed user, uint256 amount);

    // Info of each deposit made by the user
    struct DepositInfo {
        uint256 amount; // Amount of deposited LP tokens
        uint256 time; // Wnen the deposit is ended
    }

    // Info of each user
    struct UserInfo {
        uint256 amount; // Total deposited amount
        uint256 unfrozen; // Amount of token to be unstaked
        uint256 reward; // Ammount of claimed rewards
        uint256 claimable; // Ammount of claimable rewards
        uint256 lastUpdate; // Last time the user claimed rewards
        uint256 depositHead; // The start index in the deposit's list
        uint256 depositTail; // The end index in the deposit's list
        mapping(uint256 => DepositInfo) deposits; // User's dposits
    }

    IMintableBurnableERC20 public token; // Harvested token contract
    IReferralRewardsV2 public referralRewards; // Contract that manages referral rewards

    uint256 public duration; // How long the deposit works
    uint256 public rewardPerSec; // Reward rate generated each second
    uint256 public totalStake; // Amount of all staked LP tokens
    uint256 public totalClaimed; // Amount of all distributed rewards
    uint256 public lastUpdate; // Last time someone received rewards

    bool public isActive; // If the deposits are allowed

    mapping(address => UserInfo) public userInfo; // Info per each user

    /// @dev Constructor that initializes the most important configurations.
    /// @param _token Token to be staked and harvested.
    /// @param _duration How long the deposit works.
    /// @param _rewardPerSec Reward rate generated each second.
    constructor(
        IMintableBurnableERC20 _token,
        uint256 _duration,
        uint256 _rewardPerSec
    ) public Ownable() {
        token = _token;
        duration = _duration;
        rewardPerSec = _rewardPerSec;
        isActive = true;
    }

    /// @dev Allows an owner to stop or countinue deposits.
    /// @param _isActive Whether the deposits are allowed.
    function setActive(bool _isActive) public onlyOwner {
        isActive = _isActive;
    }

    /// @dev Allows an owner to update referral rewardsV2 module.
    /// @param _referralRewards Contract that manages referral rewardsV2.
    function setReferralRewards(IReferralRewardsV2 _referralRewards)
        public
        onlyOwner
    {
        referralRewards = _referralRewards;
    }

    /// @dev Allows an owner to update duration of the deposits.
    /// @param _duration How long the deposit works.
    function setDuration(uint256 _duration) public onlyOwner {
        duration = _duration;
    }

    /// @dev Allows an owner to update reward rate per sec.
    /// @param _rewardPerSec Reward rate generated each second.
    function setRewardPerSec(uint256 _rewardPerSec) public onlyOwner {
        rewardPerSec = _rewardPerSec;
    }

    /// @dev Allows to stake for the specific user.
    /// @param _user Deposit receiver.
    /// @param _amount Amount of deposit.
    function stakeFor(address _user, uint256 _amount) public {
        require(
            referralRewards.getReferral(_user) != address(0),
            "stakeFor: referral isn't set"
        );
        proccessStake(_user, _amount, address(0), 0);
    }

    /// @dev Allows to stake for themselves.
    /// @param _amount Amount of deposit.
    /// @param _refferal Referral address that will be set in case of the first stake.
    /// @param _reinvest Whether the tokens should be reinvested.
    function stake(
        uint256 _amount,
        address _refferal,
        uint256 _reinvest
    ) public {
        proccessStake(msg.sender, _amount, _refferal, _reinvest);
    }

    /// @dev Allows to stake for themselves.
    /// @param _count Max amount of claimed deposits.
    function claimDeposits(uint256 _count) public {
        executeUnstakes(msg.sender, _count);
    }

    /// @dev Allows to stake for themselves.
    /// @param _amount Max amount of claimed deposits.
    function claim(uint256 _amount) public {
        updateStakingReward(msg.sender);
        proccessClaim(msg.sender, _amount, false);
    }

    /// @dev Proccess the stake.
    /// @param _receiver Deposit receiver.
    /// @param _amount Amount of deposit.
    /// @param _refferal Referral address that will be set in case of the first stake.
    /// @param _reinvest Whether the tokens should be reinvested.
    function proccessStake(
        address _receiver,
        uint256 _amount,
        address _refferal,
        uint256 _reinvest
    ) internal virtual {
        require(isActive, "stake: is paused");
        updateStakingReward(_receiver);
        if (_amount > 0) {
            token.transferFrom(msg.sender, address(this), _amount);
            addDeposit(_receiver, _amount, _refferal);
        }
        if (_reinvest > 0) {
            proccessClaim(_receiver, _reinvest, true);
        }
    }

    /// @dev Proccess the stake.
    /// @param _receiver Deposit receiver.
    /// @param _amount Amount of deposit.
    /// @param _reinvest Whether the tokens should be reinvested.
    function proccessClaim(
        address _receiver,
        uint256 _amount,
        bool _reinvest
    ) internal virtual {
        UserInfo storage user = userInfo[_receiver];
        if (_amount == 0) {
            _amount = user.claimable;
        }
        require(user.claimable >= _amount, "claim: insufficient rewards");
        user.claimable = user.claimable.sub(_amount);
        user.reward = user.reward.add(_amount);
        totalClaimed = totalClaimed.add(_amount);
        emit RewardPaid(_receiver, _amount);
        if (_reinvest) {
            token.mint(address(this), _amount);
            addDeposit(_receiver, _amount, address(0));
        } else {
            token.mint(_receiver, _amount);
        }
    }

    /// @dev Assess new reward.
    /// @param _user Address of the user.
    function updateStakingReward(address _user) internal {
        UserInfo storage user = userInfo[_user];
        if (user.lastUpdate >= now) {
            return;
        }
        uint256 scaledReward =
            now.sub(user.lastUpdate).mul(user.amount).mul(rewardPerSec);
        uint256 reward = scaledReward.div(1e18);
        lastUpdate = now;
        user.claimable = user.claimable.add(reward);
        user.lastUpdate = now;
    }

    /// @dev Add the deposit.
    /// @param _receiver Deposit receiver.
    /// @param _amount Amount of deposit.
    /// @param _refferal Referral address that will be set in case of the first stake.
    function addDeposit(
        address _receiver,
        uint256 _amount,
        address _refferal
    ) internal virtual {
        UserInfo storage user = userInfo[_receiver];
        user.amount = user.amount.add(_amount);
        totalStake = totalStake.add(_amount);
        user.deposits[user.depositTail] = DepositInfo({
            amount: _amount,
            time: now + duration
        });
        emit Deposit(_receiver, user.depositTail, _amount, now, now + duration);
        user.depositTail = user.depositTail.add(1);
        referralRewards.proccessDeposit(_receiver, _refferal, _amount);
    }

    /// @dev Accumulate new reward and remove old deposits.
    /// @param _user Address of the user.
    /// @param _count How many deposits to claim.
    function executeUnstakes(address _user, uint256 _count) internal virtual {
        UserInfo storage user = userInfo[_user];
        _count = (_count == 0)
            ? user.depositTail
            : Math.min(user.depositTail, user.depositHead.add(_count));
        uint256 endedDepositAmount = 0;
        for (uint256 i = user.depositHead; i < _count; i++) {
            DepositInfo memory deposit = user.deposits[i];
            if (deposit.time < now) {
                endedDepositAmount = endedDepositAmount.add(deposit.amount);
                delete user.deposits[i];
                user.depositHead = user.depositHead.add(1);
                emit Withdraw(_user, 0, deposit.amount, deposit.time, now);
            }
        }
        if (endedDepositAmount > 0) {
            user.amount = user.amount.sub(endedDepositAmount);
            totalStake = totalStake.sub(endedDepositAmount);
            referralRewards.handleDepositEnd(_user, endedDepositAmount);
            safeTokenTransfer(_user, endedDepositAmount);
        }
    }

    /// @dev Safe token transfer.
    /// @param _to Address of the receiver.
    /// @param _amount Amount of the tokens to be sent.
    function safeTokenTransfer(address _to, uint256 _amount) internal {
        uint256 tokenBal = token.balanceOf(address(this));
        if (_amount > tokenBal) {
            token.transfer(_to, tokenBal);
        } else {
            token.transfer(_to, _amount);
        }
    }

    /// @dev Returns user's unclaimed reward.
    /// @param _user Address of the user.
    /// @param _includeDeposit Should the finnished deposits be included into calculations.
    /// @return _reward User's reward.
    function getPendingReward(address _user, bool _includeDeposit)
        public
        view
        virtual
        returns (uint256 _reward)
    {
        UserInfo storage user = userInfo[_user];
        _reward = user.claimable.add(
            now.sub(user.lastUpdate).mul(user.amount).mul(rewardPerSec).div(
                1e18
            )
        );
        if (_includeDeposit) {
            for (uint256 i = user.depositHead; i < user.depositTail; i++) {
                DepositInfo memory deposit = user.deposits[i];
                if (deposit.time < now) {
                    _reward = _reward.add(deposit.amount);
                }
            }
        }
    }

    /// @dev Returns claimed and unclaimed user's reward.
    /// @param _user Address of the user.
    /// @return _reward User's reward.
    function getReward(address _user)
        public
        view
        virtual
        returns (uint256 _reward)
    {
        UserInfo storage user = userInfo[_user];
        _reward = user.reward.add(getPendingReward(_user, false));
    }

    /// @dev Returns approximate reward assessed in the future.
    /// @param _delta Time to estimate.
    /// @return Predicted rewardsV2.
    function getEstimated(uint256 _delta) public view returns (uint256) {
        return
            (now + _delta)
                .sub(lastUpdate)
                .mul(totalStake)
                .mul(rewardPerSec)
                .div(1e18);
    }

    /// @dev Returns user's deposit by id.
    /// @param _user Address of user.
    /// @param _id Deposit id.
    /// @return Deposited amount and deposit end time.
    function getDeposit(address _user, uint256 _id)
        public
        view
        returns (uint256, uint256)
    {
        DepositInfo memory deposit = userInfo[_user].deposits[_id];
        return (deposit.amount, deposit.time);
    }

    /// @dev Returns user's ended deposits.
    /// @param _user Address of the user.
    /// @return _count Number of the deposit's that can be withdrawn.
    function getEndedDepositsCount(address _user)
        public
        view
        virtual
        returns (uint256 _count)
    {
        UserInfo storage user = userInfo[_user];
        for (uint256 i = user.depositHead; i < user.depositTail; i++) {
            DepositInfo memory deposit = user.deposits[i];
            if (deposit.time < now) {
                _count = _count.add(1);
            }
        }
    }
}

pragma solidity ^0.6.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";

interface IMintableBurnableERC20 is IERC20 {
    function burn(uint256 amount) external;

    function burnFrom(address account, uint256 amount) external;

    function mint(address _to, uint256 _amount) external;
}

pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

interface IReferralRewards {
    struct DepositInfo {
        address referrer;
        uint256 depth;
        uint256 amount;
        uint256 time;
        uint256 lastUpdatedTime;
    }
    struct ReferralInfo {
        uint256 reward;
        uint256 lastUpdate;
        uint256 depositHead;
        uint256 depositTail;
        uint256[3] amounts;
        mapping(uint256 => DepositInfo) deposits;
    }

    function setBounds(uint256[3] calldata _depositBounds) external;

    function setDepositRate(uint256[3][3] calldata _depositRate) external;

    function setStakingRate(uint256[3][3] calldata _stakingRate) external;

    function assessReferalDepositReward(address _referrer, uint256 _amount)
        external;

    function claimDividends() external;

    function claimAllDividends(address _referral) external;

    function removeDepositReward(address _referrer, uint256 _amount) external;

    function getReferralReward(address _user) external view;

    function getReferral(address _user) external view returns (address);

    function getStakingRateRange(uint256 _referralStake)
        external
        view
        returns (uint256[3] memory _rates);

    function getDepositRate(uint256[] calldata _referralStakes)
        external
        view
        returns (uint256[] memory _rates);

    function getDepositBounds() external view returns (uint256[3] memory);

    function getStakingRates() external view returns (uint256[3][3] memory);

    function getDepositRates() external view returns (uint256[3][3] memory);

    function getReferralAmounts(address _user)
        external
        view
        returns (uint256[3] memory);
}

pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

interface IReferralRewardsV2 {
    struct ReferralInfo {
        uint256 totalDeposit;
        uint256 reward;
        uint256 lastUpdate;
        uint256[3] amounts;
    }

    function setBounds(uint256[3] calldata _depositBounds) external;

    function setDepositRate(uint256[3][3] calldata _depositRate) external;

    function setStakingRate(uint256[3][3] calldata _stakingRate) external;

    function setReferral(address _referrer, address _referral) external;

    function assessReferalDepositReward(address _referrer, uint256 _amount)
        external;

    function transferOwnership(address newOwner) external;

    function claimDividends() external;

    function claimAllDividends(address _referral) external;

    function proccessDeposit(
        address _referrer,
        address _referral,
        uint256 _amount
    ) external;

    function handleDepositEnd(address _referrer, uint256 _amount) external;

    function getReferralReward(address _user) external view;

    function getReferral(address _user) external view returns (address);

    function getStakingRateRange(uint256 _referralStake)
        external
        view
        returns (uint256[3] memory _rates);

    function getDepositRate(uint256[] calldata _referralStakes)
        external
        view
        returns (uint256[] memory _rates);

    function getDepositBounds() external view returns (uint256[3] memory);

    function getStakingRates() external view returns (uint256[3][3] memory);

    function getDepositRates() external view returns (uint256[3][3] memory);

    function getReferralAmounts(address _user)
        external
        view
        returns (uint256[3] memory);
}

pragma solidity ^0.6.0;

import "./IReferralRewards.sol";

interface IReferralTree {
    function changeAdmin(address _newAdmin) external;

    function setReferral(address _referrer, address _referral) external;

    function removeReferralReward(IReferralRewards _referralRewards) external;

    function addReferralReward(IReferralRewards _referralRewards) external;

    function claimAllDividends() external;

    function getReferrals(address _referrer, uint256 _referDepth)
        external
        view
        returns (address[] memory);

    function referrals(address _referrer) external view returns (address);

    function getReferrers(address _referral)
        external
        view
        returns (address[] memory);

    function getUserReferralReward(address _user)
        external
        view
        returns (uint256);

    function getReferralRewards()
        external
        view
        returns (IReferralRewards[] memory);
}

pragma solidity ^0.6.0;

// import "./dANT.sol";
import "./IReferralRewards.sol";

interface IRewards {
    struct DepositInfo {
        uint256 amount;
        uint256 time;
    }

    struct UserInfo {
        uint256 amount;
        uint256 unfrozen;
        uint256 reward;
        uint256 lastUpdate;
        uint256 depositHead;
        uint256 depositTail;
        mapping(uint256 => DepositInfo) deposits;
    }

    function setActive(bool _isActive) external;

    function setReferralRewards(IReferralRewards _referralRewards) external;

    function setDuration(uint256 _duration) external;

    function setRewardPerSec(uint256 _rewardPerSec) external;

    function stakeFor(address _user, uint256 _amount) external;

    function stake(uint256 _amount, address _refferal) external;

    function getPendingReward(address _user, bool _includeDeposit)
        external
        view
        returns (uint256 _reward);

    function getReward(address _user) external view returns (uint256 _reward);

    function getReferralStakes(address[] calldata _referrals)
        external
        view
        returns (uint256[] memory _stakes);

    function getReferralStake(address _referral)
        external
        view
        returns (uint256);

    function getEstimated(uint256 _delta) external view returns (uint256);

    function getDeposit(address _user, uint256 _id)
        external
        view
        returns (uint256, uint256);
}

pragma solidity ^0.6.0;

// import "./dANT.sol";
import "./IReferralRewards.sol";

interface IRewardsV2 {
    struct DepositInfo {
        uint256 amount;
        uint256 time;
    }

    struct UserInfo {
        uint256 amount;
        uint256 unfrozen;
        uint256 reward;
        uint256 lastUpdate;
        uint256 depositHead;
        uint256 depositTail;
        mapping(uint256 => DepositInfo) deposits;
    }

    function setActive(bool _isActive) external;

    function setReferralRewards(IReferralRewards _referralRewards) external;

    function setDuration(uint256 _duration) external;

    function setRewardPerSec(uint256 _rewardPerSec) external;

    function stakeFor(address _user, uint256 _amount) external;

    function stake(uint256 _amount, address _refferal) external;

    function getPendingReward(address _user, bool _includeDeposit)
        external
        view
        returns (uint256 _reward);

    function rewardPerSec() external view returns (uint256);

    function getReward(address _user) external view returns (uint256 _reward);

    function getReferralStake(address _referral)
        external
        view
        returns (uint256);

    function getEstimated(uint256 _delta) external view returns (uint256);

    function getDeposit(address _user, uint256 _id)
        external
        view
        returns (uint256, uint256);
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 GSN 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 payable) {
        return msg.sender;
    }

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

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../GSN/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @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) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @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 sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

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

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * 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) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * 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) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts 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 mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.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 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name_, string memory symbol_) public {
        _name = name_;
        _symbol = symbol_;
        _decimals = 18;
    }

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

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view 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 {_setupDecimals} is
     * called.
     *
     * 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 returns (uint8) {
        return _decimals;
    }

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

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view 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);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        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].add(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) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        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);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(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 = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(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);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(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 Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }

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

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../../GSN/Context.sol";
import "./ERC20.sol";

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    using SafeMath for uint256;

    /**
     * @dev Destroys `amount` tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 amount) public virtual {
        _burn(_msgSender(), amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, deducting from the caller's
     * allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `amount`.
     */
    function burnFrom(address account, uint256 amount) public virtual {
        uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");

        _approve(account, _msgSender(), decreasedAllowance);
        _burn(account, amount);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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);
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IMintableBurnableERC20","name":"_token","type":"address"},{"internalType":"contract IRewards","name":"_rewards","type":"address"},{"internalType":"contract IReferralTree","name":"_referralTree","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ended","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timelock","type":"uint256"}],"name":"WithdrawRequested","type":"event"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_count","type":"uint256"}],"name":"claimDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"duration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getEndedDepositsCount","outputs":[{"internalType":"uint256","name":"_count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delta","type":"uint256"}],"name":"getEstimated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"bool","name":"_includeDeposit","type":"bool"}],"name":"getPendingReward","outputs":[{"internalType":"uint256","name":"_reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getRequestsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getReward","outputs":[{"internalType":"uint256","name":"_reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalPendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralRewards","outputs":[{"internalType":"contract IReferralRewardsV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"requestHead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerSec","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isActive","type":"bool"}],"name":"setActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"setDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IReferralRewardsV2","name":"_referralRewards","type":"address"}],"name":"setReferralRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardPerSec","type":"uint256"}],"name":"setRewardPerSec","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_refferal","type":"address"},{"internalType":"uint256","name":"_reinvest","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stakeFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IMintableBurnableERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"unstakeRequests","outputs":[{"internalType":"uint256","name":"timelock","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"enum RewardsType5.Status","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"unfrozen","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"claimable","type":"uint256"},{"internalType":"uint256","name":"lastUpdate","type":"uint256"},{"internalType":"uint256","name":"depositHead","type":"uint256"},{"internalType":"uint256","name":"depositTail","type":"uint256"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b5060405162006a7c38038062006a7c833981810160405260608110156200003757600080fd5b81019080805190602001909291908051906020019092919080519060200190929190505050826000640d7957c642600062000077620005a660201b60201c565b9050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35082600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600381905550806004819055506001600860006101000a81548160ff021916908315150217905550505050600083828430604051806060016040528069010f0cf064dd592000008152602001686c6b935b8bbd400000815260200168056bc75e2d631000008152506040518060600160405280604051806060016040528060008152602001600081526020016000815250815260200160405180606001604052806000815260200160008152602001600081525081526020016040518060600160405280600081526020016000815260200160008152508152506040518060600160405280604051806060016040528066d529ae9e860000815260200166470de4df8200008152602001662386f26fc100008152508152602001604051806060016040528066b1a2bc2ec50000815260200166354a6ba7a180008152602001661aa535d3d0c00081525081526020016040518060600160405280668e1bc9bf0400008152602001662386f26fc1000081526020016611c37937e08000815250815250604051620002e790620005ae565b808873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184600360200280838360005b83811015620003d9578082015181840152602081019050620003bc565b505050509050018360036000925b81841015620004315782846020020151600360200280838360005b838110156200041f57808201518184015260208101905062000402565b505050509050019260010192620003e7565b925050508260036000925b81841015620004865782846020020151600360200280838360005b838110156200047457808201518184015260208101905062000457565b5050505090500192600101926200043c565b92505050975050505050505050604051809103906000f080158015620004b0573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663f2fde38b620004df620005a660201b60201c565b6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b1580156200054257600080fd5b505af115801562000557573d6000803e3d6000fd5b5050505080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050620005bc565b600033905090565b6135f3806200348983390190565b612ebd80620005cc6000396000f3fe608060405234801561001057600080fd5b50600436106101e55760003560e01c8063715018a61161010f578063c00007b0116100a2578063eeb58da511610071578063eeb58da514610879578063f2fde38b146108bd578063f6be71d114610901578063fc0c546a1461092f576101e5565b8063c00007b0146107c7578063c04637111461081f578063d54ad2a11461083d578063e627f2db1461085b576101e5565b8063abdc8054116100de578063abdc8054146106cf578063acec338a14610711578063adcfa77314610741578063b43b6d481461076f576101e5565b8063715018a6146106135780638b0e9f3f1461061d5780638da5cb5b1461063b578063995deaba14610685576101e5565b80632ee40908116101875780634da63f8f116101565780634da63f8f146104bb5780634f41e95d1461051f57806366442a061461053d5780636e9c931c146105bb576101e5565b80632ee40908146103b9578063379607f5146104075780634709384f146104355780634d597e7614610463576101e5565b80631e9b3a92116101c35780631e9b3a92146102e257806322f3e2d4146103005780632726b506146103225780632e17de781461038b576101e5565b80630fb5a6b4146101ea57806316ad0f6d146102085780631959a00214610260575b600080fd5b6101f2610979565b6040518082815260200191505060405180910390f35b61024a6004803603602081101561021e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061097f565b6040518082815260200191505060405180910390f35b6102a26004803603602081101561027657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109cb565b6040518088815260200187815260200186815260200185815260200184815260200183815260200182815260200197505050505050505060405180910390f35b6102ea610a0d565b6040518082815260200191505060405180910390f35b610308610a6b565b604051808215151515815260200191505060405180910390f35b61036e6004803603604081101561033857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610a7e565b604051808381526020018281526020019250505060405180910390f35b6103b7600480360360208110156103a157600080fd5b8101908080359060200190929190505050610b13565b005b610405600480360360408110156103cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e0c565b005b6104336004803603602081101561041d57600080fd5b8101908080359060200190929190505050610f99565b005b6104616004803603602081101561044b57600080fd5b8101908080359060200190929190505050610fb1565b005b6104a56004803603602081101561047957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fbe565b6040518082815260200191505060405180910390f35b610509600480360360408110156104d157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803515159060200190929190505050610fd6565b6040518082815260200191505060405180910390f35b6105276111ee565b6040518082815260200191505060405180910390f35b6105896004803603604081101561055357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506111f4565b604051808481526020018381526020018260028111156105a557fe5b60ff168152602001935050505060405180910390f35b610611600480360360608110156105d157600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611245565b005b61061b611256565b005b6106256113de565b6040518082815260200191505060405180910390f35b6106436113e4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61068d61140d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6106fb600480360360208110156106e557600080fd5b8101908080359060200190929190505050611433565b6040518082815260200191505060405180910390f35b61073f6004803603602081101561072757600080fd5b81019080803515159060200190929190505050611495565b005b61076d6004803603602081101561075757600080fd5b810190808035906020019092919050505061157b565b005b6107b16004803603602081101561078557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061164e565b6040518082815260200191505060405180910390f35b610809600480360360208110156107dd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506117a4565b6040518082815260200191505060405180910390f35b610827611811565b6040518082815260200191505060405180910390f35b610845611817565b6040518082815260200191505060405180910390f35b61086361181d565b6040518082815260200191505060405180910390f35b6108bb6004803603602081101561088f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061186e565b005b6108ff600480360360208110156108d357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061197b565b005b61092d6004803603602081101561091757600080fd5b8101908080359060200190929190505050611b88565b005b610937611c5b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60035481565b6000600a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b60096020528060005260406000206000915090508060000154908060010154908060020154908060030154908060040154908060050154908060060154905087565b6000610a66670de0b6b3a7640000610a58600454610a4a600554610a3c60075442611c8190919063ffffffff16565b611ccb90919063ffffffff16565b611ccb90919063ffffffff16565b611d5190919063ffffffff16565b905090565b600860009054906101000a900460ff1681565b600080610a89612e26565b600960008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060070160008581526020019081526020016000206040518060400160405290816000820154815260200160018201548152505090508060000151816020015192509250509250929050565b610b1c33611d9b565b6000600960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000821415610b7057806000015491505b610b87828260000154611c8190919063ffffffff16565b8160000181905550610ba6828260010154611e8990919063ffffffff16565b8160010181905550610bc382600554611c8190919063ffffffff16565b6005819055506000600a60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050600a60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180606001604052806203f4804201815260200185815260200160016002811115610c7857fe5b8152509080600181540180825580915050600190039060005260206000209060030201600090919091909150600082015181600001556020820151816001015560408201518160020160006101000a81548160ff02191690836002811115610cdc57fe5b021790555050503373ffffffffffffffffffffffffffffffffffffffff167f7a64d79878509820925daa6339976afdd4e1c50dc32bfae6820dd5792bd306a782856203f480420160405180848152602001838152602001828152602001935050505060405180910390a2600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634dc0d7c733856040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b158015610def57600080fd5b505af1158015610e03573d6000803e3d6000fd5b50505050505050565b600073ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633b0f0f2f846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610ec357600080fd5b505afa158015610ed7573d6000803e3d6000fd5b505050506040513d6020811015610eed57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161415610f88576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f7374616b65466f723a20726566657272616c2069736e2774207365740000000081525060200191505060405180910390fd5b610f958282600080611f11565b5050565b610fa233611d9b565b610fae338260006120e6565b50565b610fbb33826123fb565b50565b600b6020528060005260406000206000915090505481565b600080600960008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061108b611078670de0b6b3a764000061106a60045461105c866000015461104e886004015442611c8190919063ffffffff16565b611ccb90919063ffffffff16565b611ccb90919063ffffffff16565b611d5190919063ffffffff16565b8260030154611e8990919063ffffffff16565b915082156111e7576000600b60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b600a60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490508110156111e5576000600a60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811061116e57fe5b906000526020600020906003020190504281600001541080156111b857506001600281111561119957fe5b8160020160009054906101000a900460ff1660028111156111b657fe5b145b156111d7576111d4816001015485611e8990919063ffffffff16565b93505b5080806001019150506110d8565b505b5092915050565b60045481565b600a602052816000526040600020818154811061120d57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900460ff16905083565b61125133848484611f11565b505050565b61125e61277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461131f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60055481565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061148e670de0b6b3a7640000611480600454611472600554611464600754894201611c8190919063ffffffff16565b611ccb90919063ffffffff16565b611ccb90919063ffffffff16565b611d5190919063ffffffff16565b9050919050565b61149d61277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461155e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80600860006101000a81548160ff02191690831515021790555050565b61158361277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611644576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8060048190555050565b600080600b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905081101561179e576000600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811061172a57fe5b9060005260206000209060030201905042816000015410801561177457506001600281111561175557fe5b8160020160009054906101000a900460ff16600281111561177257fe5b145b156117905761178d600184611e8990919063ffffffff16565b92505b508080600101915050611694565b50919050565b600080600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506118096117f6846000610fd6565b8260020154611e8990919063ffffffff16565b915050919050565b60075481565b60065481565b6000611869670de0b6b3a764000061185b60065461184d61183c610a0d565b600654611e8990919063ffffffff16565b611c8190919063ffffffff16565b611d5190919063ffffffff16565b905090565b61187661277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611937576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61198361277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611a44576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611aca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180612e416026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b611b9061277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611c51576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8060038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000611cc383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612784565b905092915050565b600080831415611cde5760009050611d4b565b6000828402905082848281611cef57fe5b0414611d46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612e676021913960400191505060405180910390fd5b809150505b92915050565b6000611d9383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612844565b905092915050565b6000600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905042816004015410611def5750611e86565b6000611e32600454611e248460000154611e16866004015442611c8190919063ffffffff16565b611ccb90919063ffffffff16565b611ccb90919063ffffffff16565b90506000611e51670de0b6b3a764000083611d5190919063ffffffff16565b905042600781905550611e71818460030154611e8990919063ffffffff16565b83600301819055504283600401819055505050505b50565b600080828401905083811015611f07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600860009054906101000a900460ff16611f93576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f7374616b653a206973207061757365640000000000000000000000000000000081525060200191505060405180910390fd5b611f9c84611d9b565b60008311156120ca57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330866040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561208257600080fd5b505af1158015612096573d6000803e3d6000fd5b505050506040513d60208110156120ac57600080fd5b8101908080519060200190929190505050506120c984848461290a565b5b60008111156120e0576120df848260016120e6565b5b50505050565b6000600960008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600083141561213a57806003015492505b82816003015410156121b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f636c61696d3a20696e73756666696369656e742072657761726473000000000081525060200191505060405180910390fd5b6121cb838260030154611c8190919063ffffffff16565b81600301819055506121ea838260020154611e8990919063ffffffff16565b816002018190555061220783600654611e8990919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff167fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486846040518082815260200191505060405180910390a2811561233357600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1930856040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561230a57600080fd5b505af115801561231e573d6000803e3d6000fd5b5050505061232e8484600061290a565b6123f5565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1985856040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156123dc57600080fd5b505af11580156123f0573d6000803e3d6000fd5b505050505b50505050565b600081146124a5576124a0600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905061249b83600b60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611e8990919063ffffffff16565b612b52565b6124e9565b600a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490505b90506000600b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b81811015612777576000600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811061258457fe5b906000526020600020906003020190504281600001541080156125ce5750600160028111156125af57fe5b8160020160009054906101000a900460ff1660028111156125cc57fe5b145b156127695760028160020160006101000a81548160ff021916908360028111156125f457fe5b02179055506000600960008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061265782600101548260010154611c8190919063ffffffff16565b816001018190555061266d858360010154612b6b565b828573ffffffffffffffffffffffffffffffffffffffff167fe08737ac48a1dab4b1a46c7dc9398bd5bfc6d7ad6fabb7cd8caa254de14def35846001015460004260405180848152602001838152602001828152602001935050505060405180910390a36127246001600b60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611e8990919063ffffffff16565b600b60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505b508080600101915050612530565b505050565b600033905090565b6000838311158290612831576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156127f65780820151818401526020810190506127db565b50505050905090810190601f1680156128235780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b600080831182906128f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156128b557808201518184015260208101905061289a565b50505050905090810190601f1680156128e25780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816128fc57fe5b049050809150509392505050565b6000600960008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050612964838260000154611e8990919063ffffffff16565b816000018190555061298183600554611e8990919063ffffffff16565b6005819055506040518060400160405280848152602001600354420181525081600701600083600601548152602001908152602001600020600082015181600001556020820151816001015590505080600601548473ffffffffffffffffffffffffffffffffffffffff167f7162984403f6c73c8639375d45a9187dfd04602231bd8e587c415718b5f7e5f98542600354420160405180848152602001838152602001828152602001935050505060405180910390a3612a4f60018260060154611e8990919063ffffffff16565b8160060181905550600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a6535fd28584866040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b158015612b3457600080fd5b505af1158015612b48573d6000803e3d6000fd5b5050505050505050565b6000818310612b615781612b63565b825b905092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612c0c57600080fd5b505afa158015612c20573d6000803e3d6000fd5b505050506040513d6020811015612c3657600080fd5b8101908080519060200190929190505050905080821115612d3b57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612cfa57600080fd5b505af1158015612d0e573d6000803e3d6000fd5b505050506040513d6020811015612d2457600080fd5b810190808051906020019092919050505050612e21565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612de457600080fd5b505af1158015612df8573d6000803e3d6000fd5b505050506040513d6020811015612e0e57600080fd5b8101908080519060200190929190505050505b505050565b60405180604001604052806000815260200160008152509056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220bde1651ceae600efa54b41620e732efc1fffc64dd202082d681d275315bf356f64736f6c6343000602003360806040523480156200001157600080fd5b50604051620035f3380380620035f3833981810160405262000037919081019062000586565b868686868686866000620000506200024260201b60201c565b9050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35086600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555085600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550826005906003620001839291906200024a565b50816008906003620001979291906200028f565b50806011906003620001ab9291906200028f565b5083600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555084600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505050505050505050505050620007dc565b600033905090565b82600381019282156200027c579160200282015b828111156200027b5782518255916020019190600101906200025e565b5b5090506200028b9190620002e6565b5090565b82600380028101928215620002d3579160200282015b82811115620002d257825182906003620002c19291906200030e565b5091602001919060030190620002a5565b5b509050620002e2919062000353565b5090565b6200030b91905b8082111562000307576000816000905550600101620002ed565b5090565b90565b826003810192821562000340579160200282015b828111156200033f57825182559160200191906001019062000322565b5b5090506200034f9190620002e6565b5090565b6200038191905b808211156200037d576000818162000373919062000384565b506003016200035a565b5090565b90565b50600081556001016000815560010160009055565b600082601f830112620003ab57600080fd5b6003620003c2620003bc8262000663565b62000635565b91508183856060840282011115620003d957600080fd5b60005b838110156200040d5781620003f2888262000417565b845260208401935060608301925050600181019050620003dc565b5050505092915050565b600082601f8301126200042957600080fd5b6003620004406200043a8262000686565b62000635565b915081838560208402820111156200045757600080fd5b60005b838110156200048b57816200047088826200056f565b8452602084019350602083019250506001810190506200045a565b5050505092915050565b600082601f830112620004a757600080fd5b6003620004be620004b882620006a9565b62000635565b91508183856020840282011115620004d557600080fd5b60005b83811015620005095781620004ee88826200056f565b845260208401935060208301925050600181019050620004d8565b5050505092915050565b60008151905062000524816200075a565b92915050565b6000815190506200053b8162000774565b92915050565b60008151905062000552816200078e565b92915050565b6000815190506200056981620007a8565b92915050565b6000815190506200058081620007c2565b92915050565b6000806000806000806000610320888a031215620005a357600080fd5b6000620005b38a828b0162000513565b9750506020620005c68a828b016200052a565b9650506040620005d98a828b0162000558565b9550506060620005ec8a828b0162000541565b9450506080620005ff8a828b0162000495565b93505060e0620006128a828b0162000399565b925050610200620006268a828b0162000399565b91505092959891949750929550565b6000604051905081810181811067ffffffffffffffff821117156200065957600080fd5b8060405250919050565b600067ffffffffffffffff8211156200067b57600080fd5b602082029050919050565b600067ffffffffffffffff8211156200069e57600080fd5b602082029050919050565b600067ffffffffffffffff821115620006c157600080fd5b602082029050919050565b6000620006d98262000730565b9050919050565b6000620006ed82620006cc565b9050919050565b60006200070182620006cc565b9050919050565b60006200071582620006cc565b9050919050565b60006200072982620006cc565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6200076581620006e0565b81146200077157600080fd5b50565b6200077f81620006f4565b81146200078b57600080fd5b50565b620007998162000708565b8114620007a557600080fd5b50565b620007b3816200071c565b8114620007bf57600080fd5b50565b620007cd8162000750565b8114620007d957600080fd5b50565b612e0780620007ec6000396000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c80636e18b6db116100de578063a6a9fcfa11610097578063e7e2fe1911610071578063e7e2fe1914610485578063f2fde38b146104a3578063f3c13a12146104bf578063fc0c546a146104ef5761018e565b8063a6a9fcfa14610409578063ad35710114610439578063c72b50fd146104695761018e565b80636e18b6db14610333578063715018a614610365578063767bd4ba1461036f5780638da5cb5b1461039f57806393af7adc146103bd578063a6535fd2146103ed5761018e565b80633a294ba31161014b5780634dc0d7c7116101255780634dc0d7c7146102d157806353d4e7f5146102ed578063668038e01461030b5780636dcc2b3a146103155761018e565b80633a294ba3146102555780633b0f0f2f14610271578063414eff13146102a15761018e565b80630342e122146101935780630b3cb9d2146101c3578063168b85cf146101e157806319aaff86146101fd578063396fe62714610219578063397f669014610237575b600080fd5b6101ad60048036036101a89190810190612528565b61050d565b6040516101ba9190612b2b565b60405180910390f35b6101cb61056e565b6040516101d89190612b2b565b60405180910390f35b6101fb60048036036101f691908101906124ad565b610573565b005b61021760048036036102129190810190612365565b61061e565b005b6102216106ba565b60405161022e91906129bc565b60405180910390f35b61023f61073d565b60405161024c9190612a0e565b60405180910390f35b61026f600480360361026a9190810190612483565b610763565b005b61028b60048036036102869190810190612365565b61080e565b604051610298919061294f565b60405180910390f35b6102bb60048036036102b69190810190612365565b6108c2565b6040516102c89190612b2b565b60405180910390f35b6102eb60048036036102e69190810190612406565b610b78565b005b6102f5610e74565b60405161030291906129bc565b60405180910390f35b610313610ef7565b005b61031d610f02565b60405161032a9190612b2b565b60405180910390f35b61034d60048036036103489190810190612365565b610f07565b60405161035c93929190612b46565b60405180910390f35b61036d610f31565b005b610389600480360361038491908101906124d6565b611086565b6040516103969190612b2b565b60405180910390f35b6103a761109e565b6040516103b4919061294f565b60405180910390f35b6103d760048036036103d291908101906124d6565b6110c7565b6040516103e491906129d8565b60405180910390f35b610407600480360361040291908101906123b7565b61115c565b005b610423600480360361041e9190810190612365565b6114e8565b60405161043091906129d8565b60405180910390f35b610453600480360361044e9190810190612528565b6115b4565b6040516104609190612b2b565b60405180910390f35b610483600480360361047e9190810190612483565b6115dc565b005b61048d611687565b60405161049a91906129d8565b60405180910390f35b6104bd60048036036104b89190810190612365565b6116d2565b005b6104d960048036036104d49190810190612528565b611896565b6040516104e69190612b2b565b60405180910390f35b6104f76118be565b60405161050491906129f3565b60405180910390f35b600080600090505b6003811015610566576005816003811061052b57fe5b01548410610559576008816003811061054057fe5b60030201836003811061054f57fe5b0154915050610568565b8080600101915050610515565b505b92915050565b600381565b61057b6118e4565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610609576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060090612acb565b60405180910390fd5b80600590600361061a929190611f5d565b5050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106a590612aeb565b60405180910390fd5b6106b7816118ec565b50565b6106c2611f9d565b6011600380602002604051908101604052809291906000905b8282101561073457838260030201600380602002604051908101604052809291908260038015610720576020028201915b81548152602001906001019080831161070c575b5050505050815260200190600101906106db565b50505050905090565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61076b6118e4565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146107f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107f090612acb565b60405180910390fd5b80601190600361080a929190611fca565b5050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639ca423b3836040518263ffffffff1660e01b815260040161086b919061294f565b60206040518083038186803b15801561088357600080fd5b505afa158015610897573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108bb919081019061238e565b9050919050565b600080601a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634f41e95d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561097057600080fd5b505afa158015610984573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109a891908101906124ff565b90506000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631b1ace25866040518263ffffffff1660e01b8152600401610a07919061294f565b60206040518083038186803b158015610a1f57600080fd5b505afa158015610a33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a5791908101906124ff565b9050610a6161201a565b610a80610a7b838660000154611a8690919063ffffffff16565b6110c7565b9050600084600101549050600085600201541115610b515760008090505b6003811015610b4f57610b40610b31670de0b6b3a7640000610b23868560038110610ac557fe5b6020020151610b158a610b078d6003018960038110610ae057fe5b0154610af98f6002015442611adb90919063ffffffff16565b611b2590919063ffffffff16565b611b2590919063ffffffff16565b611b2590919063ffffffff16565b611b9590919063ffffffff16565b83611a8690919063ffffffff16565b91508080600101915050610a9e565b505b610b6c670de0b6b3a764000082611b9590919063ffffffff16565b95505050505050919050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c08576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bff90612a4b565b60405180910390fd5b610c5d81601a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154611adb90919063ffffffff16565b601a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001819055506060600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166332a00d8e8460036040518363ffffffff1660e01b8152600401610d03929190612993565b60006040518083038186803b158015610d1b57600080fd5b505afa158015610d2f573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250610d589190810190612442565b905060008090505b8151811015610e6e57600073ffffffffffffffffffffffffffffffffffffffff16828281518110610d8d57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff161415610db657610e61565b610dd2828281518110610dc557fe5b6020026020010151611bdf565b6000601a6000848481518110610de457fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050610e4b84826003018460038110610e3b57fe5b0154611adb90919063ffffffff16565b816003018360038110610e5a57fe5b0181905550505b8080600101915050610d60565b50505050565b610e7c611f9d565b6008600380602002604051908101604052809291906000905b82821015610eee57838260030201600380602002604051908101604052809291908260038015610eda576020028201915b815481526020019060010190808311610ec6575b505050505081526020019060010190610e95565b50505050905090565b610f00336118ec565b565b600381565b601a6020528060005260406000206000915090508060000154908060010154908060020154905083565b610f396118e4565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610fc7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fbe90612acb565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6005816003811061109357fe5b016000915090505481565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6110cf61201a565b60008090505b600381101561115557600581600381106110eb57fe5b01548310611148576011816003811061110057fe5b6003020160038060200260405190810160405280929190826003801561113b576020028201915b815481526020019060010190808311611127575b5050505050915050611157565b80806001019150506110d5565b505b919050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146111ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111e390612b0b565b60405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637543e3f084846040518363ffffffff1660e01b815260040161124992919061296a565b600060405180830381600087803b15801561126357600080fd5b505af1158015611277573d6000803e3d6000fd5b505050506112d081601a60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154611a8690919063ffffffff16565b601a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001819055506060600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166332a00d8e8560036040518363ffffffff1660e01b8152600401611376929190612993565b60006040518083038186803b15801561138e57600080fd5b505afa1580156113a2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052506113cb9190810190612442565b905060008090505b81518110156114e157600073ffffffffffffffffffffffffffffffffffffffff1682828151811061140057fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff161415611429576114d4565b61144582828151811061143857fe5b6020026020010151611bdf565b6000601a600084848151811061145757fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506114be848260030184600381106114ae57fe5b0154611a8690919063ffffffff16565b8160030183600381106114cd57fe5b0181905550505b80806001019150506113d3565b5050505050565b6114f061201a565b6114f861203c565b601a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060800160405290816000820154815260200160018201548152602001600282015481526020016003820160038060200260405190810160405280929190826003801561159c576020028201915b815481526020019060010190808311611588575b50505050508152505090508060600151915050919050565b601182600381106115c157fe5b6003020181600381106115d057fe5b01600091509150505481565b6115e46118e4565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611672576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161166990612acb565b60405180910390fd5b806008906003611683929190611fca565b5050565b61168f61201a565b60056003806020026040519081016040528092919082600380156116c8576020028201915b8154815260200190600101908083116116b4575b5050505050905090565b6116da6118e4565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611768576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161175f90612acb565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156117d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117cf90612a6b565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600882600381106118a357fe5b6003020181600381106118b257fe5b01600091509150505481565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600033905090565b6118f581611bdf565b6000601a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000611959670de0b6b3a76400008360010154611b9590919063ffffffff16565b90506000811115611a81576000611981670de0b6b3a764000083611b2590919063ffffffff16565b905061199a818460010154611adb90919063ffffffff16565b8360010181905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1985846040518363ffffffff1660e01b81526004016119ff929190612993565b600060405180830381600087803b158015611a1957600080fd5b505af1158015611a2d573d6000803e3d6000fd5b505050508373ffffffffffffffffffffffffffffffffffffffff167f04b20935b234f45fda390d2df59d92b7bb8bed322d3bc8764e826cfff50007d583604051611a779190612b2b565b60405180910390a2505b505050565b600080828401905083811015611ad1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ac890612a8b565b60405180910390fd5b8091505092915050565b6000611b1d83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611ea1565b905092915050565b600080831415611b385760009050611b8f565b6000828402905082848281611b4957fe5b0414611b8a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b8190612aab565b60405180910390fd5b809150505b92915050565b6000611bd783836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611efc565b905092915050565b6000601a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090504281600201541115611c345750611e9e565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634f41e95d6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c9e57600080fd5b505afa158015611cb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611cd691908101906124ff565b90506000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631b1ace25856040518263ffffffff1660e01b8152600401611d35919061294f565b60206040518083038186803b158015611d4d57600080fd5b505afa158015611d61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d8591908101906124ff565b9050611d8f61201a565b611dae611da9838660000154611a8690919063ffffffff16565b6110c7565b9050600084600201541115611e905760008090505b6003811015611e8e576000611e55670de0b6b3a7640000611e47858560038110611de957fe5b6020020151611e3989611e2b8c6003018960038110611e0457fe5b0154611e1d8e6002015442611adb90919063ffffffff16565b611b2590919063ffffffff16565b611b2590919063ffffffff16565b611b2590919063ffffffff16565b611b9590919063ffffffff16565b90506000811115611e8057611e77818760010154611a8690919063ffffffff16565b86600101819055505b508080600101915050611dc3565b505b428460020181905550505050505b50565b6000838311158290611ee9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ee09190612a29565b60405180910390fd5b5060008385039050809150509392505050565b60008083118290611f43576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f3a9190612a29565b60405180910390fd5b506000838581611f4f57fe5b049050809150509392505050565b8260038101928215611f8c579160200282015b82811115611f8b578251825591602001919060010190611f70565b5b509050611f99919061206a565b5090565b60405180606001604052806003905b611fb461208f565b815260200190600190039081611fac5790505090565b82600380028101928215612009579160200282015b8281111561200857825182906003611ff89291906120b1565b5091602001919060030190611fdf565b5b50905061201691906120f1565b5090565b6040518060600160405280600390602082028038833980820191505090505090565b604051806080016040528060008152602001600081526020016000815260200161206461208f565b81525090565b61208c91905b80821115612088576000816000905550600101612070565b5090565b90565b6040518060600160405280600390602082028038833980820191505090505090565b82600381019282156120e0579160200282015b828111156120df5782518255916020019190600101906120c4565b5b5090506120ed919061206a565b5090565b61211a91905b80821115612116576000818161210d919061211d565b506003016120f7565b5090565b90565b50600081556001016000815560010160009055565b60008135905061214181612da3565b92915050565b60008151905061215681612da3565b92915050565b600082601f83011261216d57600080fd5b815161218061217b82612baa565b612b7d565b915081818352602084019350602081019050838560208402820111156121a557600080fd5b60005b838110156121d557816121bb8882612147565b8452602084019350602083019250506001810190506121a8565b5050505092915050565b600082601f8301126121f057600080fd5b60036122036121fe82612bd2565b612b7d565b9150818385606084028201111561221957600080fd5b60005b83811015612249578161222f8882612253565b84526020840193506060830192505060018101905061221c565b5050505092915050565b600082601f83011261226457600080fd5b600361227761227282612bf4565b612b7d565b9150818385602084028201111561228d57600080fd5b60005b838110156122bd57816122a3888261233b565b845260208401935060208301925050600181019050612290565b5050505092915050565b600082601f8301126122d857600080fd5b60036122eb6122e682612c16565b612b7d565b9150818385602084028201111561230157600080fd5b60005b838110156123315781612317888261233b565b845260208401935060208301925050600181019050612304565b5050505092915050565b60008135905061234a81612dba565b92915050565b60008151905061235f81612dba565b92915050565b60006020828403121561237757600080fd5b600061238584828501612132565b91505092915050565b6000602082840312156123a057600080fd5b60006123ae84828501612147565b91505092915050565b6000806000606084860312156123cc57600080fd5b60006123da86828701612132565b93505060206123eb86828701612132565b92505060406123fc8682870161233b565b9150509250925092565b6000806040838503121561241957600080fd5b600061242785828601612132565b92505060206124388582860161233b565b9150509250929050565b60006020828403121561245457600080fd5b600082015167ffffffffffffffff81111561246e57600080fd5b61247a8482850161215c565b91505092915050565b6000610120828403121561249657600080fd5b60006124a4848285016121df565b91505092915050565b6000606082840312156124bf57600080fd5b60006124cd848285016122c7565b91505092915050565b6000602082840312156124e857600080fd5b60006124f68482850161233b565b91505092915050565b60006020828403121561251157600080fd5b600061251f84828501612350565b91505092915050565b6000806040838503121561253b57600080fd5b60006125498582860161233b565b925050602061255a8582860161233b565b9150509250929050565b60006125708383612651565b60608301905092915050565b60006125888383612931565b60208301905092915050565b61259d81612cdb565b82525050565b6125ac81612c56565b6125b68184612ca9565b92506125c182612c38565b8060005b838110156125f25781516125d98782612564565b96506125e483612c82565b9250506001810190506125c5565b505050505050565b61260381612c6c565b61260d8184612cbf565b925061261882612c4c565b8060005b83811015612649578151612630878261257c565b965061263b83612c9c565b92505060018101905061261c565b505050505050565b61265a81612c61565b6126648184612cb4565b925061266f82612c42565b8060005b838110156126a0578151612687878261257c565b965061269283612c8f565b925050600181019050612673565b505050505050565b6126b181612d17565b82525050565b6126c081612d3b565b82525050565b60006126d182612c77565b6126db8185612cca565b93506126eb818560208601612d5f565b6126f481612d92565b840191505092915050565b600061270c601a83612cca565b91507f68616e646c654465706f736974456e643a2062616420726f6c650000000000006000830152602082019050919050565b600061274c602683612cca565b91507f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008301527f64647265737300000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006127b2601b83612cca565b91507f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006000830152602082019050919050565b60006127f2602183612cca565b91507f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60008301527f77000000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000612858602083612cca565b91507f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726000830152602082019050919050565b6000612898601b83612cca565b91507f636c61696d416c6c4469766964656e64733a2062616420726f6c6500000000006000830152602082019050919050565b60006128d8602483612cca565b91507f6173736573735265666572616c4465706f7369745265776172643a206261642060008301527f726f6c65000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b61293a81612d0d565b82525050565b61294981612d0d565b82525050565b60006020820190506129646000830184612594565b92915050565b600060408201905061297f6000830185612594565b61298c6020830184612594565b9392505050565b60006040820190506129a86000830185612594565b6129b56020830184612940565b9392505050565b6000610120820190506129d260008301846125a3565b92915050565b60006060820190506129ed60008301846125fa565b92915050565b6000602082019050612a0860008301846126a8565b92915050565b6000602082019050612a2360008301846126b7565b92915050565b60006020820190508181036000830152612a4381846126c6565b905092915050565b60006020820190508181036000830152612a64816126ff565b9050919050565b60006020820190508181036000830152612a848161273f565b9050919050565b60006020820190508181036000830152612aa4816127a5565b9050919050565b60006020820190508181036000830152612ac4816127e5565b9050919050565b60006020820190508181036000830152612ae48161284b565b9050919050565b60006020820190508181036000830152612b048161288b565b9050919050565b60006020820190508181036000830152612b24816128cb565b9050919050565b6000602082019050612b406000830184612940565b92915050565b6000606082019050612b5b6000830186612940565b612b686020830185612940565b612b756040830184612940565b949350505050565b6000604051905081810181811067ffffffffffffffff82111715612ba057600080fd5b8060405250919050565b600067ffffffffffffffff821115612bc157600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115612be957600080fd5b602082029050919050565b600067ffffffffffffffff821115612c0b57600080fd5b602082029050919050565b600067ffffffffffffffff821115612c2d57600080fd5b602082029050919050565b6000819050919050565b6000819050919050565b6000819050919050565b600060039050919050565b600060039050919050565b600060039050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b600081905092915050565b600081905092915050565b600081905092915050565b600082825260208201905092915050565b6000612ce682612ced565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000612d2282612d29565b9050919050565b6000612d3482612ced565b9050919050565b6000612d4682612d4d565b9050919050565b6000612d5882612ced565b9050919050565b60005b83811015612d7d578082015181840152602081019050612d62565b83811115612d8c576000848401525b50505050565b6000601f19601f8301169050919050565b612dac81612cdb565b8114612db757600080fd5b50565b612dc381612d0d565b8114612dce57600080fd5b5056fea2646970667358221220b11dce3d30a8fbdbf1e272ace4d6f82da3671ebd3fc7734db9a49ccbba9feda164736f6c63430006020033000000000000000000000000be3c393fb670f0a29c3f3e660ffb113200e366760000000000000000000000003c58b7e291454e749b242f23a7a6a8a9f4dddde9000000000000000000000000e5c23851bbde700414beb3ab2d2ae7063c8d9c72

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101e55760003560e01c8063715018a61161010f578063c00007b0116100a2578063eeb58da511610071578063eeb58da514610879578063f2fde38b146108bd578063f6be71d114610901578063fc0c546a1461092f576101e5565b8063c00007b0146107c7578063c04637111461081f578063d54ad2a11461083d578063e627f2db1461085b576101e5565b8063abdc8054116100de578063abdc8054146106cf578063acec338a14610711578063adcfa77314610741578063b43b6d481461076f576101e5565b8063715018a6146106135780638b0e9f3f1461061d5780638da5cb5b1461063b578063995deaba14610685576101e5565b80632ee40908116101875780634da63f8f116101565780634da63f8f146104bb5780634f41e95d1461051f57806366442a061461053d5780636e9c931c146105bb576101e5565b80632ee40908146103b9578063379607f5146104075780634709384f146104355780634d597e7614610463576101e5565b80631e9b3a92116101c35780631e9b3a92146102e257806322f3e2d4146103005780632726b506146103225780632e17de781461038b576101e5565b80630fb5a6b4146101ea57806316ad0f6d146102085780631959a00214610260575b600080fd5b6101f2610979565b6040518082815260200191505060405180910390f35b61024a6004803603602081101561021e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061097f565b6040518082815260200191505060405180910390f35b6102a26004803603602081101561027657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109cb565b6040518088815260200187815260200186815260200185815260200184815260200183815260200182815260200197505050505050505060405180910390f35b6102ea610a0d565b6040518082815260200191505060405180910390f35b610308610a6b565b604051808215151515815260200191505060405180910390f35b61036e6004803603604081101561033857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610a7e565b604051808381526020018281526020019250505060405180910390f35b6103b7600480360360208110156103a157600080fd5b8101908080359060200190929190505050610b13565b005b610405600480360360408110156103cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e0c565b005b6104336004803603602081101561041d57600080fd5b8101908080359060200190929190505050610f99565b005b6104616004803603602081101561044b57600080fd5b8101908080359060200190929190505050610fb1565b005b6104a56004803603602081101561047957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fbe565b6040518082815260200191505060405180910390f35b610509600480360360408110156104d157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803515159060200190929190505050610fd6565b6040518082815260200191505060405180910390f35b6105276111ee565b6040518082815260200191505060405180910390f35b6105896004803603604081101561055357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506111f4565b604051808481526020018381526020018260028111156105a557fe5b60ff168152602001935050505060405180910390f35b610611600480360360608110156105d157600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611245565b005b61061b611256565b005b6106256113de565b6040518082815260200191505060405180910390f35b6106436113e4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61068d61140d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6106fb600480360360208110156106e557600080fd5b8101908080359060200190929190505050611433565b6040518082815260200191505060405180910390f35b61073f6004803603602081101561072757600080fd5b81019080803515159060200190929190505050611495565b005b61076d6004803603602081101561075757600080fd5b810190808035906020019092919050505061157b565b005b6107b16004803603602081101561078557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061164e565b6040518082815260200191505060405180910390f35b610809600480360360208110156107dd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506117a4565b6040518082815260200191505060405180910390f35b610827611811565b6040518082815260200191505060405180910390f35b610845611817565b6040518082815260200191505060405180910390f35b61086361181d565b6040518082815260200191505060405180910390f35b6108bb6004803603602081101561088f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061186e565b005b6108ff600480360360208110156108d357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061197b565b005b61092d6004803603602081101561091757600080fd5b8101908080359060200190929190505050611b88565b005b610937611c5b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60035481565b6000600a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b60096020528060005260406000206000915090508060000154908060010154908060020154908060030154908060040154908060050154908060060154905087565b6000610a66670de0b6b3a7640000610a58600454610a4a600554610a3c60075442611c8190919063ffffffff16565b611ccb90919063ffffffff16565b611ccb90919063ffffffff16565b611d5190919063ffffffff16565b905090565b600860009054906101000a900460ff1681565b600080610a89612e26565b600960008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060070160008581526020019081526020016000206040518060400160405290816000820154815260200160018201548152505090508060000151816020015192509250509250929050565b610b1c33611d9b565b6000600960003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000821415610b7057806000015491505b610b87828260000154611c8190919063ffffffff16565b8160000181905550610ba6828260010154611e8990919063ffffffff16565b8160010181905550610bc382600554611c8190919063ffffffff16565b6005819055506000600a60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050600a60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060405180606001604052806203f4804201815260200185815260200160016002811115610c7857fe5b8152509080600181540180825580915050600190039060005260206000209060030201600090919091909150600082015181600001556020820151816001015560408201518160020160006101000a81548160ff02191690836002811115610cdc57fe5b021790555050503373ffffffffffffffffffffffffffffffffffffffff167f7a64d79878509820925daa6339976afdd4e1c50dc32bfae6820dd5792bd306a782856203f480420160405180848152602001838152602001828152602001935050505060405180910390a2600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634dc0d7c733856040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b158015610def57600080fd5b505af1158015610e03573d6000803e3d6000fd5b50505050505050565b600073ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633b0f0f2f846040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610ec357600080fd5b505afa158015610ed7573d6000803e3d6000fd5b505050506040513d6020811015610eed57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff161415610f88576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f7374616b65466f723a20726566657272616c2069736e2774207365740000000081525060200191505060405180910390fd5b610f958282600080611f11565b5050565b610fa233611d9b565b610fae338260006120e6565b50565b610fbb33826123fb565b50565b600b6020528060005260406000206000915090505481565b600080600960008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061108b611078670de0b6b3a764000061106a60045461105c866000015461104e886004015442611c8190919063ffffffff16565b611ccb90919063ffffffff16565b611ccb90919063ffffffff16565b611d5190919063ffffffff16565b8260030154611e8990919063ffffffff16565b915082156111e7576000600b60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b600a60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490508110156111e5576000600a60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811061116e57fe5b906000526020600020906003020190504281600001541080156111b857506001600281111561119957fe5b8160020160009054906101000a900460ff1660028111156111b657fe5b145b156111d7576111d4816001015485611e8990919063ffffffff16565b93505b5080806001019150506110d8565b505b5092915050565b60045481565b600a602052816000526040600020818154811061120d57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900460ff16905083565b61125133848484611f11565b505050565b61125e61277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461131f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60055481565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061148e670de0b6b3a7640000611480600454611472600554611464600754894201611c8190919063ffffffff16565b611ccb90919063ffffffff16565b611ccb90919063ffffffff16565b611d5190919063ffffffff16565b9050919050565b61149d61277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461155e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80600860006101000a81548160ff02191690831515021790555050565b61158361277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611644576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8060048190555050565b600080600b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905081101561179e576000600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811061172a57fe5b9060005260206000209060030201905042816000015410801561177457506001600281111561175557fe5b8160020160009054906101000a900460ff16600281111561177257fe5b145b156117905761178d600184611e8990919063ffffffff16565b92505b508080600101915050611694565b50919050565b600080600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506118096117f6846000610fd6565b8260020154611e8990919063ffffffff16565b915050919050565b60075481565b60065481565b6000611869670de0b6b3a764000061185b60065461184d61183c610a0d565b600654611e8990919063ffffffff16565b611c8190919063ffffffff16565b611d5190919063ffffffff16565b905090565b61187661277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611937576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61198361277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611a44576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611aca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180612e416026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b611b9061277c565b73ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611c51576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8060038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000611cc383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612784565b905092915050565b600080831415611cde5760009050611d4b565b6000828402905082848281611cef57fe5b0414611d46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612e676021913960400191505060405180910390fd5b809150505b92915050565b6000611d9383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612844565b905092915050565b6000600960008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905042816004015410611def5750611e86565b6000611e32600454611e248460000154611e16866004015442611c8190919063ffffffff16565b611ccb90919063ffffffff16565b611ccb90919063ffffffff16565b90506000611e51670de0b6b3a764000083611d5190919063ffffffff16565b905042600781905550611e71818460030154611e8990919063ffffffff16565b83600301819055504283600401819055505050505b50565b600080828401905083811015611f07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600860009054906101000a900460ff16611f93576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f7374616b653a206973207061757365640000000000000000000000000000000081525060200191505060405180910390fd5b611f9c84611d9b565b60008311156120ca57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330866040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561208257600080fd5b505af1158015612096573d6000803e3d6000fd5b505050506040513d60208110156120ac57600080fd5b8101908080519060200190929190505050506120c984848461290a565b5b60008111156120e0576120df848260016120e6565b5b50505050565b6000600960008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600083141561213a57806003015492505b82816003015410156121b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f636c61696d3a20696e73756666696369656e742072657761726473000000000081525060200191505060405180910390fd5b6121cb838260030154611c8190919063ffffffff16565b81600301819055506121ea838260020154611e8990919063ffffffff16565b816002018190555061220783600654611e8990919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff167fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486846040518082815260200191505060405180910390a2811561233357600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1930856040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561230a57600080fd5b505af115801561231e573d6000803e3d6000fd5b5050505061232e8484600061290a565b6123f5565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1985856040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156123dc57600080fd5b505af11580156123f0573d6000803e3d6000fd5b505050505b50505050565b600081146124a5576124a0600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905061249b83600b60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611e8990919063ffffffff16565b612b52565b6124e9565b600a60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490505b90506000600b60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b81811015612777576000600a60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811061258457fe5b906000526020600020906003020190504281600001541080156125ce5750600160028111156125af57fe5b8160020160009054906101000a900460ff1660028111156125cc57fe5b145b156127695760028160020160006101000a81548160ff021916908360028111156125f457fe5b02179055506000600960008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061265782600101548260010154611c8190919063ffffffff16565b816001018190555061266d858360010154612b6b565b828573ffffffffffffffffffffffffffffffffffffffff167fe08737ac48a1dab4b1a46c7dc9398bd5bfc6d7ad6fabb7cd8caa254de14def35846001015460004260405180848152602001838152602001828152602001935050505060405180910390a36127246001600b60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611e8990919063ffffffff16565b600b60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505b508080600101915050612530565b505050565b600033905090565b6000838311158290612831576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156127f65780820151818401526020810190506127db565b50505050905090810190601f1680156128235780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b600080831182906128f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156128b557808201518184015260208101905061289a565b50505050905090810190601f1680156128e25780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816128fc57fe5b049050809150509392505050565b6000600960008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050612964838260000154611e8990919063ffffffff16565b816000018190555061298183600554611e8990919063ffffffff16565b6005819055506040518060400160405280848152602001600354420181525081600701600083600601548152602001908152602001600020600082015181600001556020820151816001015590505080600601548473ffffffffffffffffffffffffffffffffffffffff167f7162984403f6c73c8639375d45a9187dfd04602231bd8e587c415718b5f7e5f98542600354420160405180848152602001838152602001828152602001935050505060405180910390a3612a4f60018260060154611e8990919063ffffffff16565b8160060181905550600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a6535fd28584866040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050600060405180830381600087803b158015612b3457600080fd5b505af1158015612b48573d6000803e3d6000fd5b5050505050505050565b6000818310612b615781612b63565b825b905092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612c0c57600080fd5b505afa158015612c20573d6000803e3d6000fd5b505050506040513d6020811015612c3657600080fd5b8101908080519060200190929190505050905080821115612d3b57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612cfa57600080fd5b505af1158015612d0e573d6000803e3d6000fd5b505050506040513d6020811015612d2457600080fd5b810190808051906020019092919050505050612e21565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612de457600080fd5b505af1158015612df8573d6000803e3d6000fd5b505050506040513d6020811015612e0e57600080fd5b8101908080519060200190929190505050505b505050565b60405180604001604052806000815260200160008152509056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220bde1651ceae600efa54b41620e732efc1fffc64dd202082d681d275315bf356f64736f6c63430006020033

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

000000000000000000000000be3c393fb670f0a29c3f3e660ffb113200e366760000000000000000000000003c58b7e291454e749b242f23a7a6a8a9f4dddde9000000000000000000000000e5c23851bbde700414beb3ab2d2ae7063c8d9c72

-----Decoded View---------------
Arg [0] : _token (address): 0xbE3c393Fb670f0A29C3F3E660FFB113200e36676
Arg [1] : _rewards (address): 0x3C58B7E291454e749B242F23A7A6a8A9f4dddDe9
Arg [2] : _referralTree (address): 0xe5C23851Bbde700414BeB3Ab2D2aE7063c8D9C72

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000be3c393fb670f0a29c3f3e660ffb113200e36676
Arg [1] : 0000000000000000000000003c58b7e291454e749b242f23a7a6a8a9f4dddde9
Arg [2] : 000000000000000000000000e5c23851bbde700414beb3ab2d2ae7063c8d9c72


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ 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.