ETH Price: $3,218.32 (+4.14%)

Contract

0x49bdd8854481005bBa4aCEbaBF6e06cD5F6312e9
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Vote123453892021-05-01 1:35:401354 days ago1619832940IN
Kyber: DAO
0 ETH0.0008453130
Vote123182262021-04-26 20:48:581359 days ago1619470138IN
Kyber: DAO
0 ETH0.0016624459
Vote123077702021-04-25 6:17:231360 days ago1619331443IN
Kyber: DAO
0 ETH0.0015779156
Vote123077702021-04-25 6:17:231360 days ago1619331443IN
Kyber: DAO
0 ETH0.0009861935
Vote122946832021-04-23 5:52:021362 days ago1619157122IN
Kyber: DAO
0 ETH0.0027049996
Vote122766172021-04-20 10:58:441365 days ago1618916324IN
Kyber: DAO
0 ETH0.00493097175
Vote122722322021-04-19 18:56:121366 days ago1618858572IN
Kyber: DAO
0 ETH0.03459978316
Vote122707762021-04-19 13:27:101366 days ago1618838830IN
Kyber: DAO
0 ETH0.02824939146
Vote122681682021-04-19 3:40:261366 days ago1618803626IN
Kyber: DAO
0 ETH0.0256947101
Vote122666272021-04-18 21:47:561366 days ago1618782476IN
Kyber: DAO
0 ETH0.0179944793
Vote122658772021-04-18 19:03:501367 days ago1618772630IN
Kyber: DAO
0 ETH0.0121529296
Vote122656392021-04-18 18:16:351367 days ago1618769795IN
Kyber: DAO
0 ETH0.02263821117
Vote122620882021-04-18 4:54:141367 days ago1618721654IN
Kyber: DAO
0 ETH0.02660679243
Vote122620622021-04-18 4:48:511367 days ago1618721331IN
Kyber: DAO
0 ETH0.07429977384
Vote122620132021-04-18 4:37:541367 days ago1618720674IN
Kyber: DAO
0 ETH0.03832255350
Vote122620102021-04-18 4:37:121367 days ago1618720632IN
Kyber: DAO
0 ETH0.06752766349
Vote122613802021-04-18 2:25:301367 days ago1618712730IN
Kyber: DAO
0 ETH0.02798433110
Vote122611602021-04-18 1:34:391367 days ago1618709679IN
Kyber: DAO
0 ETH0.0106208297
Vote122599992021-04-17 21:22:141367 days ago1618694534IN
Kyber: DAO
0 ETH0.0189619298
Vote122589062021-04-17 17:21:121368 days ago1618680072IN
Kyber: DAO
0 ETH0.00812849122
Vote122588992021-04-17 17:19:571368 days ago1618679997IN
Kyber: DAO
0 ETH0.01511003138
Vote122588842021-04-17 17:17:061368 days ago1618679826IN
Kyber: DAO
0 ETH0.04350291171
Vote122588112021-04-17 17:00:031368 days ago1618678803IN
Kyber: DAO
0 ETH0.01521952139
Vote122583952021-04-17 15:20:021368 days ago1618672802IN
Kyber: DAO
0 ETH0.02200809201
Vote122583892021-04-17 15:18:481368 days ago1618672728IN
Kyber: DAO
0 ETH0.03463453179
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
104032482020-07-06 2:43:191653 days ago1594003399
Kyber: DAO
 Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
KyberDao

Compiler Version
v0.6.6+commit.6c089d02

Optimization Enabled:
Yes with 430 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-07-06
*/

// File: contracts/sol6/utils/zeppelin/SafeMath.sol

pragma solidity 0.6.6;

/**
 * @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) {
        // Solidity only automatically asserts when dividing by 0
        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;
    }

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

// File: contracts/sol6/Dao/IEpochUtils.sol

pragma solidity 0.6.6;

interface IEpochUtils {
    function epochPeriodInSeconds() external view returns (uint256);

    function firstEpochStartTimestamp() external view returns (uint256);

    function getCurrentEpochNumber() external view returns (uint256);

    function getEpochNumber(uint256 timestamp) external view returns (uint256);
}

// File: contracts/sol6/Dao/EpochUtils.sol

pragma solidity 0.6.6;



contract EpochUtils is IEpochUtils {
    using SafeMath for uint256;

    uint256 public override epochPeriodInSeconds;
    uint256 public override firstEpochStartTimestamp;

    function getCurrentEpochNumber() public view override returns (uint256) {
        return getEpochNumber(now);
    }

    function getEpochNumber(uint256 timestamp) public view override returns (uint256) {
        if (timestamp < firstEpochStartTimestamp || epochPeriodInSeconds == 0) {
            return 0;
        }
        // ((timestamp - firstEpochStartTimestamp) / epochPeriodInSeconds) + 1;
        return ((timestamp.sub(firstEpochStartTimestamp)).div(epochPeriodInSeconds)).add(1);
    }
}

// File: contracts/sol6/Dao/DaoOperator.sol

pragma solidity 0.6.6;


contract DaoOperator {
    address public daoOperator;

    constructor(address _daoOperator) public {
        require(_daoOperator != address(0), "daoOperator is 0");
        daoOperator = _daoOperator;
    }

    modifier onlyDaoOperator() {
        require(msg.sender == daoOperator, "only daoOperator");
        _;
    }
}

// File: contracts/sol6/IERC20.sol

pragma solidity 0.6.6;


interface IERC20 {
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    function approve(address _spender, uint256 _value) external returns (bool success);

    function transfer(address _to, uint256 _value) external returns (bool success);

    function transferFrom(
        address _from,
        address _to,
        uint256 _value
    ) external returns (bool success);

    function allowance(address _owner, address _spender) external view returns (uint256 remaining);

    function balanceOf(address _owner) external view returns (uint256 balance);

    function decimals() external view returns (uint8 digits);

    function totalSupply() external view returns (uint256 supply);
}


// to support backward compatible contract name -- so function signature remains same
abstract contract ERC20 is IERC20 {

}

// File: contracts/sol6/utils/zeppelin/ReentrancyGuard.sol

pragma solidity 0.6.6;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
contract ReentrancyGuard {
    bool private _notEntered;

    constructor () internal {
        // Storing an initial non-zero value makes deployment a bit more
        // expensive, but in exchange the refund on every call to nonReentrant
        // will be lower in amount. Since refunds are capped to a percetange of
        // the total transaction's gas, it is best to keep them low in cases
        // like this one, to increase the likelihood of the full refund coming
        // into effect.
        _notEntered = true;
    }

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

        // Any calls to nonReentrant after this point will fail
        _notEntered = false;

        _;

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

// File: contracts/sol6/Dao/IKyberStaking.sol

pragma solidity 0.6.6;



interface IKyberStaking is IEpochUtils {
    event Delegated(
        address indexed staker,
        address indexed representative,
        uint256 indexed epoch,
        bool isDelegated
    );
    event Deposited(uint256 curEpoch, address indexed staker, uint256 amount);
    event Withdraw(uint256 indexed curEpoch, address indexed staker, uint256 amount);

    function initAndReturnStakerDataForCurrentEpoch(address staker)
        external
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        );

    function deposit(uint256 amount) external;

    function delegate(address dAddr) external;

    function withdraw(uint256 amount) external;

    /**
     * @notice return combine data (stake, delegatedStake, representative) of a staker
     * @dev allow to get staker data up to current epoch + 1
     */
    function getStakerData(address staker, uint256 epoch)
        external
        view
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        );

    function getLatestStakerData(address staker)
        external
        view
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        );

    /**
     * @notice return raw data of a staker for an epoch
     *         WARN: should be used only for initialized data
     *          if data has not been initialized, it will return all 0
     *          pool master shouldn't use this function to compute/distribute rewards of pool members
     */
    function getStakerRawData(address staker, uint256 epoch)
        external
        view
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        );
}

// File: contracts/sol6/IKyberDao.sol

pragma solidity 0.6.6;



interface IKyberDao is IEpochUtils {
    event Voted(address indexed staker, uint indexed epoch, uint indexed campaignID, uint option);

    function getLatestNetworkFeeDataWithCache()
        external
        returns (uint256 feeInBps, uint256 expiryTimestamp);

    function getLatestBRRDataWithCache()
        external
        returns (
            uint256 burnInBps,
            uint256 rewardInBps,
            uint256 rebateInBps,
            uint256 epoch,
            uint256 expiryTimestamp
        );

    function handleWithdrawal(address staker, uint256 penaltyAmount) external;

    function vote(uint256 campaignID, uint256 option) external;

    function getLatestNetworkFeeData()
        external
        view
        returns (uint256 feeInBps, uint256 expiryTimestamp);

    function shouldBurnRewardForEpoch(uint256 epoch) external view returns (bool);

    /**
     * @dev  return staker's reward percentage in precision for a past epoch only
     *       fee handler should call this function when a staker wants to claim reward
     *       return 0 if staker has no votes or stakes
     */
    function getPastEpochRewardPercentageInPrecision(address staker, uint256 epoch)
        external
        view
        returns (uint256);

    /**
     * @dev  return staker's reward percentage in precision for the current epoch
     *       reward percentage is not finalized until the current epoch is ended
     */
    function getCurrentEpochRewardPercentageInPrecision(address staker)
        external
        view
        returns (uint256);
}

// File: contracts/sol6/Dao/KyberStaking.sol

pragma solidity 0.6.6;







/**
 * @notice   This contract is using SafeMath for uint, which is inherited from EpochUtils
 *           Some events are moved to interface, easier for public uses
 *           Staking contract will be deployed by KyberDao's contract
 */
contract KyberStaking is IKyberStaking, EpochUtils, ReentrancyGuard {
    struct StakerData {
        uint256 stake;
        uint256 delegatedStake;
        address representative;
    }

    IERC20 public immutable kncToken;
    IKyberDao public immutable kyberDao;

    // staker data per epoch, including stake, delegated stake and representative
    mapping(uint256 => mapping(address => StakerData)) internal stakerPerEpochData;
    // latest data of a staker, including stake, delegated stake, representative
    mapping(address => StakerData) internal stakerLatestData;
    // true/false: if data has been initialized at an epoch for a staker
    mapping(uint256 => mapping(address => bool)) internal hasInited;

    // event is fired if something is wrong with withdrawal
    // even though the withdrawal is still successful
    event WithdrawDataUpdateFailed(uint256 curEpoch, address staker, uint256 amount);

    constructor(
        IERC20 _kncToken,
        uint256 _epochPeriod,
        uint256 _startTimestamp,
        IKyberDao _kyberDao
    ) public {
        require(_epochPeriod > 0, "ctor: epoch period is 0");
        require(_startTimestamp >= now, "ctor: start in the past");
        require(_kncToken != IERC20(0), "ctor: kncToken 0");
        require(_kyberDao != IKyberDao(0), "ctor: kyberDao 0");

        epochPeriodInSeconds = _epochPeriod;
        firstEpochStartTimestamp = _startTimestamp;
        kncToken = _kncToken;
        kyberDao = _kyberDao;
    }

    /**
     * @dev calls to set delegation for msg.sender, will take effect from the next epoch
     * @param newRepresentative address to delegate to
     */
    function delegate(address newRepresentative) external override {
        require(newRepresentative != address(0), "delegate: representative 0");
        address staker = msg.sender;
        uint256 curEpoch = getCurrentEpochNumber();

        initDataIfNeeded(staker, curEpoch);

        address curRepresentative = stakerPerEpochData[curEpoch + 1][staker].representative;
        // nothing changes here
        if (newRepresentative == curRepresentative) {
            return;
        }

        uint256 updatedStake = stakerPerEpochData[curEpoch + 1][staker].stake;

        // reduce delegatedStake for curRepresentative if needed
        if (curRepresentative != staker) {
            initDataIfNeeded(curRepresentative, curEpoch);

            stakerPerEpochData[curEpoch + 1][curRepresentative].delegatedStake =
                stakerPerEpochData[curEpoch + 1][curRepresentative].delegatedStake.sub(updatedStake);
            stakerLatestData[curRepresentative].delegatedStake =
                stakerLatestData[curRepresentative].delegatedStake.sub(updatedStake);

            emit Delegated(staker, curRepresentative, curEpoch, false);
        }

        stakerLatestData[staker].representative = newRepresentative;
        stakerPerEpochData[curEpoch + 1][staker].representative = newRepresentative;

        // ignore if staker is delegating back to himself
        if (newRepresentative != staker) {
            initDataIfNeeded(newRepresentative, curEpoch);
            stakerPerEpochData[curEpoch + 1][newRepresentative].delegatedStake =
                stakerPerEpochData[curEpoch + 1][newRepresentative].delegatedStake.add(updatedStake);
            stakerLatestData[newRepresentative].delegatedStake =
                stakerLatestData[newRepresentative].delegatedStake.add(updatedStake);
            emit Delegated(staker, newRepresentative, curEpoch, true);
        }
    }

    /**
     * @dev call to stake more KNC for msg.sender
     * @param amount amount of KNC to stake
     */
    function deposit(uint256 amount) external override {
        require(amount > 0, "deposit: amount is 0");

        uint256 curEpoch = getCurrentEpochNumber();
        address staker = msg.sender;

        // collect KNC token from staker
        require(
            kncToken.transferFrom(staker, address(this), amount),
            "deposit: can not get token"
        );

        initDataIfNeeded(staker, curEpoch);

        stakerPerEpochData[curEpoch + 1][staker].stake =
            stakerPerEpochData[curEpoch + 1][staker].stake.add(amount);
        stakerLatestData[staker].stake =
            stakerLatestData[staker].stake.add(amount);

        // increase delegated stake for address that staker has delegated to (if it is not staker)
        address representative = stakerPerEpochData[curEpoch + 1][staker].representative;
        if (representative != staker) {
            initDataIfNeeded(representative, curEpoch);
            stakerPerEpochData[curEpoch + 1][representative].delegatedStake =
                stakerPerEpochData[curEpoch + 1][representative].delegatedStake.add(amount);
            stakerLatestData[representative].delegatedStake =
                stakerLatestData[representative].delegatedStake.add(amount);
        }

        emit Deposited(curEpoch, staker, amount);
    }

    /**
     * @dev call to withdraw KNC from staking, it could affect reward when calling KyberDao handleWithdrawal
     * @param amount amount of KNC to withdraw
     */
    function withdraw(uint256 amount) external override nonReentrant {
        require(amount > 0, "withdraw: amount is 0");

        uint256 curEpoch = getCurrentEpochNumber();
        address staker = msg.sender;

        require(
            stakerLatestData[staker].stake >= amount,
            "withdraw: latest amount staked < withdrawal amount"
        );

        (bool success, ) = address(this).call(
            abi.encodeWithSignature(
                "handleWithdrawal(address,uint256,uint256)",
                staker,
                amount,
                curEpoch
            )
        );
        if (!success) {
            // Note: should catch this event to check if something went wrong
            emit WithdrawDataUpdateFailed(curEpoch, staker, amount);
        }

        stakerLatestData[staker].stake = stakerLatestData[staker].stake.sub(amount);

        // transfer KNC back to staker
        require(kncToken.transfer(staker, amount), "withdraw: can not transfer knc");
        emit Withdraw(curEpoch, staker, amount);
    }

    /**
     * @dev initialize data if needed, then return staker's data for current epoch
     * @dev for safe, only allow calling this func from KyberDao address
     * @param staker - staker's address to initialize and get data for
     */
    function initAndReturnStakerDataForCurrentEpoch(address staker)
        external
        override
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        )
    {
        require(
            msg.sender == address(kyberDao),
            "initAndReturnData: only kyberDao"
        );

        uint256 curEpoch = getCurrentEpochNumber();
        initDataIfNeeded(staker, curEpoch);

        StakerData memory stakerData = stakerPerEpochData[curEpoch][staker];
        stake = stakerData.stake;
        delegatedStake = stakerData.delegatedStake;
        representative = stakerData.representative;
    }

    /**
     * @notice return raw data of a staker for an epoch
     *         WARN: should be used only for initialized data
     *          if data has not been initialized, it will return all 0
     *          pool master shouldn't use this function to compute/distribute rewards of pool members
     * @dev  in KyberDao contract, if staker wants to claim reward for past epoch,
     *       we must know the staker's data for that epoch
     *       if the data has not been initialized, it means staker hasn't done any action -> no reward
     */
    function getStakerRawData(address staker, uint256 epoch)
        external
        view
        override
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        )
    {
        StakerData memory stakerData = stakerPerEpochData[epoch][staker];
        stake = stakerData.stake;
        delegatedStake = stakerData.delegatedStake;
        representative = stakerData.representative;
    }

    /**
     * @dev allow to get data up to current epoch + 1
     */
    function getStake(address staker, uint256 epoch) external view returns (uint256) {
        uint256 curEpoch = getCurrentEpochNumber();
        if (epoch > curEpoch + 1) {
            return 0;
        }
        uint256 i = epoch;
        while (true) {
            if (hasInited[i][staker]) {
                return stakerPerEpochData[i][staker].stake;
            }
            if (i == 0) {
                break;
            }
            i--;
        }
        return 0;
    }

    /**
     * @dev allow to get data up to current epoch + 1
     */
    function getDelegatedStake(address staker, uint256 epoch) external view returns (uint256) {
        uint256 curEpoch = getCurrentEpochNumber();
        if (epoch > curEpoch + 1) {
            return 0;
        }
        uint256 i = epoch;
        while (true) {
            if (hasInited[i][staker]) {
                return stakerPerEpochData[i][staker].delegatedStake;
            }
            if (i == 0) {
                break;
            }
            i--;
        }
        return 0;
    }

    /**
     * @dev allow to get data up to current epoch + 1
     */
    function getRepresentative(address staker, uint256 epoch) external view returns (address) {
        uint256 curEpoch = getCurrentEpochNumber();
        if (epoch > curEpoch + 1) {
            return address(0);
        }
        uint256 i = epoch;
        while (true) {
            if (hasInited[i][staker]) {
                return stakerPerEpochData[i][staker].representative;
            }
            if (i == 0) {
                break;
            }
            i--;
        }
        // not delegated to anyone, default to yourself
        return staker;
    }

    /**
     * @notice return combine data (stake, delegatedStake, representative) of a staker
     * @dev allow to get staker data up to current epoch + 1
     */
    function getStakerData(address staker, uint256 epoch)
        external view override
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        )
    {
        stake = 0;
        delegatedStake = 0;
        representative = address(0);

        uint256 curEpoch = getCurrentEpochNumber();
        if (epoch > curEpoch + 1) {
            return (stake, delegatedStake, representative);
        }
        uint256 i = epoch;
        while (true) {
            if (hasInited[i][staker]) {
                stake = stakerPerEpochData[i][staker].stake;
                delegatedStake = stakerPerEpochData[i][staker].delegatedStake;
                representative = stakerPerEpochData[i][staker].representative;
                return (stake, delegatedStake, representative);
            }
            if (i == 0) {
                break;
            }
            i--;
        }
        // not delegated to anyone, default to yourself
        representative = staker;
    }

    function getLatestRepresentative(address staker) external view returns (address) {
        return
            stakerLatestData[staker].representative == address(0)
                ? staker
                : stakerLatestData[staker].representative;
    }

    function getLatestDelegatedStake(address staker) external view returns (uint256) {
        return stakerLatestData[staker].delegatedStake;
    }

    function getLatestStakeBalance(address staker) external view returns (uint256) {
        return stakerLatestData[staker].stake;
    }

    function getLatestStakerData(address staker)
        external view override
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        )
    {
        stake = stakerLatestData[staker].stake;
        delegatedStake = stakerLatestData[staker].delegatedStake;
        representative = stakerLatestData[staker].representative == address(0)
                ? staker
                : stakerLatestData[staker].representative;
    }

    /**
    * @dev  separate logics from withdraw, so staker can withdraw as long as amount <= staker's deposit amount
            calling this function from withdraw function, ignore reverting
    * @param staker staker that is withdrawing
    * @param amount amount to withdraw
    * @param curEpoch current epoch
    */
    function handleWithdrawal(
        address staker,
        uint256 amount,
        uint256 curEpoch
    ) external {
        require(msg.sender == address(this), "only staking contract");
        initDataIfNeeded(staker, curEpoch);
        // Note: update latest stake will be done after this function
        // update staker's data for next epoch
        stakerPerEpochData[curEpoch + 1][staker].stake =
            stakerPerEpochData[curEpoch + 1][staker].stake.sub(amount);

        address representative = stakerPerEpochData[curEpoch][staker].representative;
        uint256 curStake = stakerPerEpochData[curEpoch][staker].stake;
        uint256 lStakeBal = stakerLatestData[staker].stake.sub(amount);
        uint256 newStake = curStake.min(lStakeBal);
        uint256 reduceAmount = curStake.sub(newStake); // newStake is always <= curStake

        if (reduceAmount > 0) {
            if (representative != staker) {
                initDataIfNeeded(representative, curEpoch);
                // staker has delegated to representative, withdraw will affect representative's delegated stakes
                stakerPerEpochData[curEpoch][representative].delegatedStake =
                    stakerPerEpochData[curEpoch][representative].delegatedStake.sub(reduceAmount);
            }
            stakerPerEpochData[curEpoch][staker].stake = newStake;
            // call KyberDao to reduce reward, if staker has delegated, then pass his representative
            if (address(kyberDao) != address(0)) {
                // don't revert if KyberDao revert so data will be updated correctly
                (bool success, ) = address(kyberDao).call(
                    abi.encodeWithSignature(
                        "handleWithdrawal(address,uint256)",
                        representative,
                        reduceAmount
                    )
                );
                if (!success) {
                    emit WithdrawDataUpdateFailed(curEpoch, staker, amount);
                }
            }
        }
        representative = stakerPerEpochData[curEpoch + 1][staker].representative;
        if (representative != staker) {
            initDataIfNeeded(representative, curEpoch);
            stakerPerEpochData[curEpoch + 1][representative].delegatedStake =
                stakerPerEpochData[curEpoch + 1][representative].delegatedStake.sub(amount);
            stakerLatestData[representative].delegatedStake =
                stakerLatestData[representative].delegatedStake.sub(amount);
        }
    }

    /**
     * @dev initialize data if it has not been initialized yet
     * @param staker staker's address to initialize
     * @param epoch should be current epoch
     */
    function initDataIfNeeded(address staker, uint256 epoch) internal {
        address representative = stakerLatestData[staker].representative;
        if (representative == address(0)) {
            // not delegate to anyone, consider as delegate to yourself
            stakerLatestData[staker].representative = staker;
            representative = staker;
        }

        uint256 ldStake = stakerLatestData[staker].delegatedStake;
        uint256 lStakeBal = stakerLatestData[staker].stake;

        if (!hasInited[epoch][staker]) {
            hasInited[epoch][staker] = true;
            StakerData storage stakerData = stakerPerEpochData[epoch][staker];
            stakerData.representative = representative;
            stakerData.delegatedStake = ldStake;
            stakerData.stake = lStakeBal;
        }

        // whenever stakers deposit/withdraw/delegate, the current and next epoch data need to be updated
        // as the result, we will also initialize data for staker at the next epoch
        if (!hasInited[epoch + 1][staker]) {
            hasInited[epoch + 1][staker] = true;
            StakerData storage nextEpochStakerData = stakerPerEpochData[epoch + 1][staker];
            nextEpochStakerData.representative = representative;
            nextEpochStakerData.delegatedStake = ldStake;
            nextEpochStakerData.stake = lStakeBal;
        }
    }
}

// File: contracts/sol6/utils/Utils5.sol

pragma solidity 0.6.6;



/**
 * @title Kyber utility file
 * mostly shared constants and rate calculation helpers
 * inherited by most of kyber contracts.
 * previous utils implementations are for previous solidity versions.
 */
contract Utils5 {
    IERC20 internal constant ETH_TOKEN_ADDRESS = IERC20(
        0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
    );
    uint256 internal constant PRECISION = (10**18);
    uint256 internal constant MAX_QTY = (10**28); // 10B tokens
    uint256 internal constant MAX_RATE = (PRECISION * 10**7); // up to 10M tokens per eth
    uint256 internal constant MAX_DECIMALS = 18;
    uint256 internal constant ETH_DECIMALS = 18;
    uint256 constant BPS = 10000; // Basic Price Steps. 1 step = 0.01%
    uint256 internal constant MAX_ALLOWANCE = uint256(-1); // token.approve inifinite

    mapping(IERC20 => uint256) internal decimals;

    function getUpdateDecimals(IERC20 token) internal returns (uint256) {
        if (token == ETH_TOKEN_ADDRESS) return ETH_DECIMALS; // save storage access
        uint256 tokenDecimals = decimals[token];
        // moreover, very possible that old tokens have decimals 0
        // these tokens will just have higher gas fees.
        if (tokenDecimals == 0) {
            tokenDecimals = token.decimals();
            decimals[token] = tokenDecimals;
        }

        return tokenDecimals;
    }

    function setDecimals(IERC20 token) internal {
        if (decimals[token] != 0) return; //already set

        if (token == ETH_TOKEN_ADDRESS) {
            decimals[token] = ETH_DECIMALS;
        } else {
            decimals[token] = token.decimals();
        }
    }

    /// @dev get the balance of a user.
    /// @param token The token type
    /// @return The balance
    function getBalance(IERC20 token, address user) internal view returns (uint256) {
        if (token == ETH_TOKEN_ADDRESS) {
            return user.balance;
        } else {
            return token.balanceOf(user);
        }
    }

    function getDecimals(IERC20 token) internal view returns (uint256) {
        if (token == ETH_TOKEN_ADDRESS) return ETH_DECIMALS; // save storage access
        uint256 tokenDecimals = decimals[token];
        // moreover, very possible that old tokens have decimals 0
        // these tokens will just have higher gas fees.
        if (tokenDecimals == 0) return token.decimals();

        return tokenDecimals;
    }

    function calcDestAmount(
        IERC20 src,
        IERC20 dest,
        uint256 srcAmount,
        uint256 rate
    ) internal view returns (uint256) {
        return calcDstQty(srcAmount, getDecimals(src), getDecimals(dest), rate);
    }

    function calcSrcAmount(
        IERC20 src,
        IERC20 dest,
        uint256 destAmount,
        uint256 rate
    ) internal view returns (uint256) {
        return calcSrcQty(destAmount, getDecimals(src), getDecimals(dest), rate);
    }

    function calcDstQty(
        uint256 srcQty,
        uint256 srcDecimals,
        uint256 dstDecimals,
        uint256 rate
    ) internal pure returns (uint256) {
        require(srcQty <= MAX_QTY, "srcQty > MAX_QTY");
        require(rate <= MAX_RATE, "rate > MAX_RATE");

        if (dstDecimals >= srcDecimals) {
            require((dstDecimals - srcDecimals) <= MAX_DECIMALS, "dst - src > MAX_DECIMALS");
            return (srcQty * rate * (10**(dstDecimals - srcDecimals))) / PRECISION;
        } else {
            require((srcDecimals - dstDecimals) <= MAX_DECIMALS, "src - dst > MAX_DECIMALS");
            return (srcQty * rate) / (PRECISION * (10**(srcDecimals - dstDecimals)));
        }
    }

    function calcSrcQty(
        uint256 dstQty,
        uint256 srcDecimals,
        uint256 dstDecimals,
        uint256 rate
    ) internal pure returns (uint256) {
        require(dstQty <= MAX_QTY, "dstQty > MAX_QTY");
        require(rate <= MAX_RATE, "rate > MAX_RATE");

        //source quantity is rounded up. to avoid dest quantity being too low.
        uint256 numerator;
        uint256 denominator;
        if (srcDecimals >= dstDecimals) {
            require((srcDecimals - dstDecimals) <= MAX_DECIMALS, "src - dst > MAX_DECIMALS");
            numerator = (PRECISION * dstQty * (10**(srcDecimals - dstDecimals)));
            denominator = rate;
        } else {
            require((dstDecimals - srcDecimals) <= MAX_DECIMALS, "dst - src > MAX_DECIMALS");
            numerator = (PRECISION * dstQty);
            denominator = (rate * (10**(dstDecimals - srcDecimals)));
        }
        return (numerator + denominator - 1) / denominator; //avoid rounding down errors
    }

    function calcRateFromQty(
        uint256 srcAmount,
        uint256 destAmount,
        uint256 srcDecimals,
        uint256 dstDecimals
    ) internal pure returns (uint256) {
        require(srcAmount <= MAX_QTY, "srcAmount > MAX_QTY");
        require(destAmount <= MAX_QTY, "destAmount > MAX_QTY");

        if (dstDecimals >= srcDecimals) {
            require((dstDecimals - srcDecimals) <= MAX_DECIMALS, "dst - src > MAX_DECIMALS");
            return ((destAmount * PRECISION) / ((10**(dstDecimals - srcDecimals)) * srcAmount));
        } else {
            require((srcDecimals - dstDecimals) <= MAX_DECIMALS, "src - dst > MAX_DECIMALS");
            return ((destAmount * PRECISION * (10**(srcDecimals - dstDecimals))) / srcAmount);
        }
    }

    function minOf(uint256 x, uint256 y) internal pure returns (uint256) {
        return x > y ? y : x;
    }
}

// File: contracts/sol6/Dao/KyberDao.sol

pragma solidity 0.6.6;








/**
 * @notice  This contract is using SafeMath for uint, which is inherited from EpochUtils
            Some events are moved to interface, easier for public uses
 * @dev Network fee campaign: options are fee in bps
 *      BRR fee handler campaign: options are combined of rebate (left most 128 bits) + reward (right most 128 bits)
 *      General campaign: options are from 1 to num_options
 */
contract KyberDao is IKyberDao, EpochUtils, ReentrancyGuard, Utils5, DaoOperator {
    // max number of campaigns for each epoch
    uint256 public   constant MAX_EPOCH_CAMPAIGNS = 10;
    // max number of options for each campaign
    uint256 public   constant MAX_CAMPAIGN_OPTIONS = 8;
    uint256 internal constant POWER_128 = 2**128;

    enum CampaignType {General, NetworkFee, FeeHandlerBRR}

    struct FormulaData {
        uint256 minPercentageInPrecision;
        uint256 cInPrecision;
        uint256 tInPrecision;
    }

    struct CampaignVoteData {
        uint256 totalVotes;
        uint256[] votePerOption;
    }

    struct Campaign {
        CampaignType campaignType;
        bool campaignExists;
        uint256 startTimestamp;
        uint256 endTimestamp;
        uint256 totalKNCSupply; // total KNC supply at the time campaign was created
        FormulaData formulaData; // formula params for concluding campaign result
        bytes link; // link to KIP, explaination of options, etc.
        uint256[] options; // data of options
        CampaignVoteData campaignVoteData; // campaign vote data: total votes + vote per option
    }

    struct BRRData {
        uint256 rewardInBps;
        uint256 rebateInBps;
    }

    uint256 public minCampaignDurationInSeconds = 4 days;
    IERC20 public immutable kncToken;
    IKyberStaking public immutable staking;

    // use to generate increasing campaign ID
    uint256 public numberCampaigns = 0;
    mapping(uint256 => Campaign) internal campaignData;

    // epochCampaigns[epoch]: list campaign IDs for an epoch (epoch => campaign IDs)
    mapping(uint256 => uint256[]) internal epochCampaigns;
    // totalEpochPoints[epoch]: total points for an epoch (epoch => total points)
    mapping(uint256 => uint256) internal totalEpochPoints;
    // numberVotes[staker][epoch]: number of campaigns that the staker has voted in an epoch
    mapping(address => mapping(uint256 => uint256)) public numberVotes;
    // stakerVotedOption[staker][campaignID]: staker's voted option ID for a campaign
    mapping(address => mapping(uint256 => uint256)) public stakerVotedOption;

    uint256 internal latestNetworkFeeResult;
    // epoch => campaignID for network fee campaigns
    mapping(uint256 => uint256) public networkFeeCampaigns;
    // latest BRR data (reward and rebate in bps)
    BRRData internal latestBrrData;
    // epoch => campaignID for brr campaigns
    mapping(uint256 => uint256) public brrCampaigns;

    event NewCampaignCreated(
        CampaignType campaignType,
        uint256 indexed campaignID,
        uint256 startTimestamp,
        uint256 endTimestamp,
        uint256 minPercentageInPrecision,
        uint256 cInPrecision,
        uint256 tInPrecision,
        uint256[] options,
        bytes link
    );

    event CancelledCampaign(uint256 indexed campaignID);

    constructor(
        uint256 _epochPeriod,
        uint256 _startTimestamp,
        IERC20 _knc,
        uint256 _defaultNetworkFeeBps,
        uint256 _defaultRewardBps,
        uint256 _defaultRebateBps,
        address _daoOperator
    ) public DaoOperator(_daoOperator) {
        require(_epochPeriod > 0, "ctor: epoch period is 0");
        require(_startTimestamp >= now, "ctor: start in the past");
        require(_knc != IERC20(0), "ctor: knc token 0");
        // in Network, maximum fee that can be taken from 1 tx is (platform fee + 2 * network fee)
        // so network fee should be less than 50%
        require(_defaultNetworkFeeBps < BPS / 2, "ctor: network fee high");
        require(_defaultRewardBps.add(_defaultRebateBps) <= BPS, "reward plus rebate high");

        epochPeriodInSeconds = _epochPeriod;
        firstEpochStartTimestamp = _startTimestamp;
        kncToken = _knc;

        latestNetworkFeeResult = _defaultNetworkFeeBps;
        latestBrrData = BRRData({
            rewardInBps: _defaultRewardBps,
            rebateInBps: _defaultRebateBps
        });

        // deploy staking contract 
        staking = new KyberStaking({
            _kncToken: _knc,
            _epochPeriod: _epochPeriod,
            _startTimestamp: _startTimestamp,
            _kyberDao: IKyberDao(this)
        });
    }

    modifier onlyStakingContract {
        require(msg.sender == address(staking), "only staking contract");
        _;
    }

    /**
     * @dev called by staking contract when staker wanted to withdraw
     * @param staker address of staker to reduce reward
     * @param reduceAmount amount voting power to be reduced for each campaign staker has voted at this epoch
     */
    function handleWithdrawal(address staker, uint256 reduceAmount) external override onlyStakingContract {
        // staking shouldn't call this func with reduce amount = 0
        if (reduceAmount == 0) {
            return;
        }
        uint256 curEpoch = getCurrentEpochNumber();

        uint256 numVotes = numberVotes[staker][curEpoch];
        // staker has not participated in any campaigns at the current epoch
        if (numVotes == 0) {
            return;
        }

        // update total points for current epoch
        totalEpochPoints[curEpoch] = totalEpochPoints[curEpoch].sub(numVotes.mul(reduceAmount));

        // update voted count for each campaign staker has voted
        uint256[] memory campaignIDs = epochCampaigns[curEpoch];

        for (uint256 i = 0; i < campaignIDs.length; i++) {
            uint256 campaignID = campaignIDs[i];

            uint256 votedOption = stakerVotedOption[staker][campaignID];
            if (votedOption == 0) {
                continue;
            } // staker has not voted yet

            Campaign storage campaign = campaignData[campaignID];
            if (campaign.endTimestamp >= now) {
                // the staker has voted for this campaign and the campaign has not ended yet
                // reduce total votes and vote count of staker's voted option
                campaign.campaignVoteData.totalVotes =
                    campaign.campaignVoteData.totalVotes.sub(reduceAmount);
                campaign.campaignVoteData.votePerOption[votedOption - 1] =
                    campaign.campaignVoteData.votePerOption[votedOption - 1].sub(reduceAmount);
            }
        }
    }

    /**
     * @dev create new campaign, only called by daoOperator
     * @param campaignType type of campaign (General, NetworkFee, FeeHandlerBRR)
     * @param startTimestamp timestamp to start running the campaign
     * @param endTimestamp timestamp to end this campaign
     * @param minPercentageInPrecision min percentage (in precision) for formula to conclude campaign
     * @param cInPrecision c value (in precision) for formula to conclude campaign
     * @param tInPrecision t value (in precision) for formula to conclude campaign
     * @param options list values of options to vote for this campaign
     * @param link additional data for this campaign
     */
    function submitNewCampaign(
        CampaignType campaignType,
        uint256 startTimestamp,
        uint256 endTimestamp,
        uint256 minPercentageInPrecision,
        uint256 cInPrecision,
        uint256 tInPrecision,
        uint256[] calldata options,
        bytes calldata link
    ) external onlyDaoOperator returns (uint256 campaignID) {
        // campaign epoch could be different from current epoch
        // as we allow to create campaign of next epoch as well
        uint256 campaignEpoch = getEpochNumber(startTimestamp);

        validateCampaignParams(
            campaignType,
            startTimestamp,
            endTimestamp,
            minPercentageInPrecision,
            cInPrecision,
            tInPrecision,
            options
        );

        numberCampaigns = numberCampaigns.add(1);
        campaignID = numberCampaigns;

        // add campaignID into the list campaign IDs
        epochCampaigns[campaignEpoch].push(campaignID);
        // update network fee or fee handler brr campaigns
        if (campaignType == CampaignType.NetworkFee) {
            networkFeeCampaigns[campaignEpoch] = campaignID;
        } else if (campaignType == CampaignType.FeeHandlerBRR) {
            brrCampaigns[campaignEpoch] = campaignID;
        }

        FormulaData memory formulaData = FormulaData({
            minPercentageInPrecision: minPercentageInPrecision,
            cInPrecision: cInPrecision,
            tInPrecision: tInPrecision
        });
        CampaignVoteData memory campaignVoteData = CampaignVoteData({
            totalVotes: 0,
            votePerOption: new uint256[](options.length)
        });

        campaignData[campaignID] = Campaign({
            campaignExists: true,
            campaignType: campaignType,
            startTimestamp: startTimestamp,
            endTimestamp: endTimestamp,
            totalKNCSupply: kncToken.totalSupply(),
            link: link,
            formulaData: formulaData,
            options: options,
            campaignVoteData: campaignVoteData
        });

        emit NewCampaignCreated(
            campaignType,
            campaignID,
            startTimestamp,
            endTimestamp,
            minPercentageInPrecision,
            cInPrecision,
            tInPrecision,
            options,
            link
        );
    }

    /**
     * @dev  cancel a campaign with given id, called by daoOperator only
     *       only can cancel campaigns that have not started yet
     * @param campaignID id of the campaign to cancel
     */
    function cancelCampaign(uint256 campaignID) external onlyDaoOperator {
        Campaign storage campaign = campaignData[campaignID];
        require(campaign.campaignExists, "cancelCampaign: campaignID doesn't exist");

        require(campaign.startTimestamp > now, "cancelCampaign: campaign already started");

        uint256 epoch = getEpochNumber(campaign.startTimestamp);

        if (campaign.campaignType == CampaignType.NetworkFee) {
            delete networkFeeCampaigns[epoch];
        } else if (campaign.campaignType == CampaignType.FeeHandlerBRR) {
            delete brrCampaigns[epoch];
        }

        delete campaignData[campaignID];

        uint256[] storage campaignIDs = epochCampaigns[epoch];
        for (uint256 i = 0; i < campaignIDs.length; i++) {
            if (campaignIDs[i] == campaignID) {
                // remove this campaign id out of list
                campaignIDs[i] = campaignIDs[campaignIDs.length - 1];
                campaignIDs.pop();
                break;
            }
        }

        emit CancelledCampaign(campaignID);
    }

    /**
     * @dev  vote for an option of a campaign
     *       options are indexed from 1 to number of options
     * @param campaignID id of campaign to vote for
     * @param option id of options to vote for
     */
    function vote(uint256 campaignID, uint256 option) external override {
        validateVoteOption(campaignID, option);
        address staker = msg.sender;

        uint256 curEpoch = getCurrentEpochNumber();
        (uint256 stake, uint256 dStake, address representative) =
            staking.initAndReturnStakerDataForCurrentEpoch(staker);

        uint256 totalStake = representative == staker ? stake.add(dStake) : dStake;
        uint256 lastVotedOption = stakerVotedOption[staker][campaignID];

        CampaignVoteData storage voteData = campaignData[campaignID].campaignVoteData;

        if (lastVotedOption == 0) {
            // increase number campaigns that the staker has voted at the current epoch
            numberVotes[staker][curEpoch]++;

            totalEpochPoints[curEpoch] = totalEpochPoints[curEpoch].add(totalStake);
            // increase voted count for this option
            voteData.votePerOption[option - 1] =
                voteData.votePerOption[option - 1].add(totalStake);
            // increase total votes
            voteData.totalVotes = voteData.totalVotes.add(totalStake);
        } else if (lastVotedOption != option) {
            // deduce previous option voted count
            voteData.votePerOption[lastVotedOption - 1] =
                voteData.votePerOption[lastVotedOption - 1].sub(totalStake);
            // increase new option voted count
            voteData.votePerOption[option - 1] =
                voteData.votePerOption[option - 1].add(totalStake);
        }

        stakerVotedOption[staker][campaignID] = option;

        emit Voted(staker, curEpoch, campaignID, option);
    }

    /**
     * @dev get latest network fee data + expiry timestamp
     *    conclude network fee campaign if needed and caching latest result in KyberDao
     */
    function getLatestNetworkFeeDataWithCache()
        external
        override
        returns (uint256 feeInBps, uint256 expiryTimestamp)
    {
        (feeInBps, expiryTimestamp) = getLatestNetworkFeeData();
        // cache latest data
        latestNetworkFeeResult = feeInBps;
    }

    /**
     * @dev return latest burn/reward/rebate data, also affecting epoch + expiry timestamp
     *      conclude brr campaign if needed and caching latest result in KyberDao
     */
    function getLatestBRRDataWithCache()
        external
        override
        returns (
            uint256 burnInBps,
            uint256 rewardInBps,
            uint256 rebateInBps,
            uint256 epoch,
            uint256 expiryTimestamp
        )
    {
        (burnInBps, rewardInBps, rebateInBps, epoch, expiryTimestamp) = getLatestBRRData();
        latestBrrData.rewardInBps = rewardInBps;
        latestBrrData.rebateInBps = rebateInBps;
    }

    /**
     * @dev some epochs have reward but no one can claim, for example: epoch 0
     *      return true if should burn all that reward
     * @param epoch epoch to check for burning reward
     */
    function shouldBurnRewardForEpoch(uint256 epoch) external view override returns (bool) {
        uint256 curEpoch = getCurrentEpochNumber();
        if (epoch >= curEpoch) {
            return false;
        }
        return totalEpochPoints[epoch] == 0;
    }

    // return list campaign ids for epoch, excluding non-existed ones
    function getListCampaignIDs(uint256 epoch) external view returns (uint256[] memory campaignIDs) {
        campaignIDs = epochCampaigns[epoch];
    }

    // return total points for an epoch
    function getTotalEpochPoints(uint256 epoch) external view returns (uint256) {
        return totalEpochPoints[epoch];
    }

    function getCampaignDetails(uint256 campaignID)
        external
        view
        returns (
            CampaignType campaignType,
            uint256 startTimestamp,
            uint256 endTimestamp,
            uint256 totalKNCSupply,
            uint256 minPercentageInPrecision,
            uint256 cInPrecision,
            uint256 tInPrecision,
            bytes memory link,
            uint256[] memory options
        )
    {
        Campaign storage campaign = campaignData[campaignID];
        campaignType = campaign.campaignType;
        startTimestamp = campaign.startTimestamp;
        endTimestamp = campaign.endTimestamp;
        totalKNCSupply = campaign.totalKNCSupply;
        minPercentageInPrecision = campaign.formulaData.minPercentageInPrecision;
        cInPrecision = campaign.formulaData.cInPrecision;
        tInPrecision = campaign.formulaData.tInPrecision;
        link = campaign.link;
        options = campaign.options;
    }

    function getCampaignVoteCountData(uint256 campaignID)
        external
        view
        returns (uint256[] memory voteCounts, uint256 totalVoteCount)
    {
        CampaignVoteData memory voteData = campaignData[campaignID].campaignVoteData;
        totalVoteCount = voteData.totalVotes;
        voteCounts = voteData.votePerOption;
    }

    /**
     * @dev  return staker's reward percentage in precision for a past epoch only
     *       fee handler should call this function when a staker wants to claim reward
     *       return 0 if staker has no votes or stakes
     */
    function getPastEpochRewardPercentageInPrecision(address staker, uint256 epoch)
        external
        view
        override
        returns (uint256)
    {
        // return 0 if epoch is not past epoch
        uint256 curEpoch = getCurrentEpochNumber();
        if (epoch >= curEpoch) {
            return 0;
        }

        return getRewardPercentageInPrecision(staker, epoch);
    }

    /**
     * @dev  return staker's reward percentage in precision for the current epoch
     */
    function getCurrentEpochRewardPercentageInPrecision(address staker)
        external
        view
        override
        returns (uint256)
    {
        uint256 curEpoch = getCurrentEpochNumber();
        return getRewardPercentageInPrecision(staker, curEpoch);
    }

    /**
     * @dev return campaign winning option and its value
     *      return (0, 0) if campaign does not exist
     *      return (0, 0) if campaign has not ended yet
     *      return (0, 0) if campaign has no winning option based on the formula
     * @param campaignID id of campaign to get result
     */
    function getCampaignWinningOptionAndValue(uint256 campaignID)
        public
        view
        returns (uint256 optionID, uint256 value)
    {
        Campaign storage campaign = campaignData[campaignID];
        if (!campaign.campaignExists) {
            return (0, 0);
        } // not exist

        // campaign has not ended yet, return 0 as winning option
        if (campaign.endTimestamp > now) {
            return (0, 0);
        }

        uint256 totalSupply = campaign.totalKNCSupply;
        // something is wrong here, total KNC supply shouldn't be 0
        if (totalSupply == 0) {
            return (0, 0);
        }

        uint256 totalVotes = campaign.campaignVoteData.totalVotes;
        uint256[] memory voteCounts = campaign.campaignVoteData.votePerOption;

        // Finding option with most votes
        uint256 winningOption = 0;
        uint256 maxVotedCount = 0;
        for (uint256 i = 0; i < voteCounts.length; i++) {
            if (voteCounts[i] > maxVotedCount) {
                winningOption = i + 1;
                maxVotedCount = voteCounts[i];
            } else if (voteCounts[i] == maxVotedCount) {
                winningOption = 0;
            }
        }

        // more than 1 options have same vote count
        if (winningOption == 0) {
            return (0, 0);
        }

        FormulaData memory formulaData = campaign.formulaData;

        // compute voted percentage (in precision)
        uint256 votedPercentage = totalVotes.mul(PRECISION).div(campaign.totalKNCSupply);

        // total voted percentage is below min acceptable percentage, no winning option
        if (formulaData.minPercentageInPrecision > votedPercentage) {
            return (0, 0);
        }

        // as we already limit value for c & t, no need to check for overflow here
        uint256 x = formulaData.tInPrecision.mul(votedPercentage).div(PRECISION);
        if (x <= formulaData.cInPrecision) {
            // threshold is not negative, need to compare with voted count
            uint256 y = formulaData.cInPrecision.sub(x);
            // (most voted option count / total votes) is below threshold, no winining option
            if (maxVotedCount.mul(PRECISION) < y.mul(totalVotes)) {
                return (0, 0);
            }
        }

        optionID = winningOption;
        value = campaign.options[optionID - 1];
    }

    /**
     * @dev return latest network fee and expiry timestamp
     */
    function getLatestNetworkFeeData()
        public
        view
        override
        returns (uint256 feeInBps, uint256 expiryTimestamp)
    {
        uint256 curEpoch = getCurrentEpochNumber();
        feeInBps = latestNetworkFeeResult;
        // expiryTimestamp = firstEpochStartTimestamp + curEpoch * epochPeriodInSeconds - 1;
        expiryTimestamp = firstEpochStartTimestamp.add(curEpoch.mul(epochPeriodInSeconds)).sub(1);
        if (curEpoch == 0) {
            return (feeInBps, expiryTimestamp);
        }
        uint256 campaignID = networkFeeCampaigns[curEpoch.sub(1)];
        if (campaignID == 0) {
            // don't have network fee campaign, return latest result
            return (feeInBps, expiryTimestamp);
        }

        uint256 winningOption;
        (winningOption, feeInBps) = getCampaignWinningOptionAndValue(campaignID);
        if (winningOption == 0) {
            // fallback to previous result
            feeInBps = latestNetworkFeeResult;
        }
        return (feeInBps, expiryTimestamp);
    }

    /**
     * @dev return latest brr result, conclude brr campaign if needed
     */
    function getLatestBRRData()
        public
        view
        returns (
            uint256 burnInBps,
            uint256 rewardInBps,
            uint256 rebateInBps,
            uint256 epoch,
            uint256 expiryTimestamp
        )
    {
        epoch = getCurrentEpochNumber();
        // expiryTimestamp = firstEpochStartTimestamp + epoch * epochPeriodInSeconds - 1;
        expiryTimestamp = firstEpochStartTimestamp.add(epoch.mul(epochPeriodInSeconds)).sub(1);
        rewardInBps = latestBrrData.rewardInBps;
        rebateInBps = latestBrrData.rebateInBps;

        if (epoch > 0) {
            uint256 campaignID = brrCampaigns[epoch.sub(1)];
            if (campaignID != 0) {
                uint256 winningOption;
                uint256 brrData;
                (winningOption, brrData) = getCampaignWinningOptionAndValue(campaignID);
                if (winningOption > 0) {
                    // has winning option, update reward and rebate value
                    (rebateInBps, rewardInBps) = getRebateAndRewardFromData(brrData);
                }
            }
        }

        burnInBps = BPS.sub(rebateInBps).sub(rewardInBps);
    }

    // Helper functions for squeezing data
    function getRebateAndRewardFromData(uint256 data)
        public
        pure
        returns (uint256 rebateInBps, uint256 rewardInBps)
    {
        rewardInBps = data & (POWER_128.sub(1));
        rebateInBps = (data.div(POWER_128)) & (POWER_128.sub(1));
    }

    /**
     * @dev  helper func to get encoded reward and rebate
     *       revert if validation failed
     */
    function getDataFromRewardAndRebateWithValidation(uint256 rewardInBps, uint256 rebateInBps)
        public
        pure
        returns (uint256 data)
    {
        require(rewardInBps.add(rebateInBps) <= BPS, "reward plus rebate high");
        data = (rebateInBps.mul(POWER_128)).add(rewardInBps);
    }

    /**
     * @dev options are indexed from 1
     */
    function validateVoteOption(uint256 campaignID, uint256 option) internal view {
        Campaign storage campaign = campaignData[campaignID];
        require(campaign.campaignExists, "vote: campaign doesn't exist");

        require(campaign.startTimestamp <= now, "vote: campaign not started");
        require(campaign.endTimestamp >= now, "vote: campaign already ended");

        // option is indexed from 1 to options.length
        require(option > 0, "vote: option is 0");
        require(option <= campaign.options.length, "vote: option is not in range");
    }

    /**
     * @dev Validate params to check if we could submit a new campaign with these params
     */
    function validateCampaignParams(
        CampaignType campaignType,
        uint256 startTimestamp,
        uint256 endTimestamp,
        uint256 minPercentageInPrecision,
        uint256 cInPrecision,
        uint256 tInPrecision,
        uint256[] memory options
    ) internal view {
        // now <= start timestamp < end timestamp
        require(startTimestamp >= now, "validateParams: start in the past");
        // campaign duration must be at least min campaign duration
        // endTimestamp - startTimestamp + 1 >= minCampaignDurationInSeconds,
        require(
            endTimestamp.add(1) >= startTimestamp.add(minCampaignDurationInSeconds),
            "validateParams: campaign duration is low"
        );

        uint256 startEpoch = getEpochNumber(startTimestamp);
        uint256 endEpoch = getEpochNumber(endTimestamp);

        require(
            epochCampaigns[startEpoch].length < MAX_EPOCH_CAMPAIGNS,
            "validateParams: too many campaigns"
        );

        // start timestamp and end timestamp must be in the same epoch
        require(startEpoch == endEpoch, "validateParams: start & end not same epoch");

        uint256 currentEpoch = getCurrentEpochNumber();
        require(
            startEpoch <= currentEpoch.add(1),
            "validateParams: only for current or next epochs"
        );

        // verify number of options
        uint256 numOptions = options.length;
        require(
            numOptions > 1 && numOptions <= MAX_CAMPAIGN_OPTIONS,
            "validateParams: invalid number of options"
        );

        // Validate option values based on campaign type
        if (campaignType == CampaignType.General) {
            // option must be positive number
            for (uint256 i = 0; i < options.length; i++) {
                require(options[i] > 0, "validateParams: general campaign option is 0");
            }
        } else if (campaignType == CampaignType.NetworkFee) {
            require(
                networkFeeCampaigns[startEpoch] == 0,
                "validateParams: already had network fee campaign for this epoch"
            );
            // network fee campaign, option must be fee in bps
            for (uint256 i = 0; i < options.length; i++) {
                // in Network, maximum fee that can be taken from 1 tx is (platform fee + 2 * network fee)
                // so network fee should be less than 50%
                require(
                    options[i] < BPS / 2,
                    "validateParams: network fee must be smaller then BPS / 2"
                );
            }
        } else {
            require(
                brrCampaigns[startEpoch] == 0,
                "validateParams: already had brr campaign for this epoch"
            );
            // brr fee handler campaign, option must be combined for reward + rebate %
            for (uint256 i = 0; i < options.length; i++) {
                // rebate (left most 128 bits) + reward (right most 128 bits)
                (uint256 rebateInBps, uint256 rewardInBps) =
                    getRebateAndRewardFromData(options[i]);
                require(
                    rewardInBps.add(rebateInBps) <= BPS,
                    "validateParams: rebate + reward can't be bigger than BPS"
                );
            }
        }

        // percentage should be smaller than or equal 100%
        require(minPercentageInPrecision <= PRECISION, "validateParams: min percentage is high");

        // limit value of c and t to avoid overflow
        require(cInPrecision < POWER_128, "validateParams: c is high");

        require(tInPrecision < POWER_128, "validateParams: t is high");
    }

    /**
     * @dev  return staker's reward percentage in precision for an epoch
     *       return 0 if staker has no votes or stakes
     *       called by 2 functions in KyberDao
     */
    function getRewardPercentageInPrecision(address staker, uint256 epoch)
        internal
        view
        returns (uint256)
    {
        uint256 numVotes = numberVotes[staker][epoch];
        // no votes, no rewards
        if (numVotes == 0) {
            return 0;
        }

        (uint256 stake, uint256 delegatedStake, address representative) =
            staking.getStakerRawData(staker, epoch);

        uint256 totalStake = representative == staker ? stake.add(delegatedStake) : delegatedStake;
        if (totalStake == 0) {
            return 0;
        }

        uint256 points = numVotes.mul(totalStake);
        uint256 totalPts = totalEpochPoints[epoch];

        // staker's reward percentage should be <= 100%
        assert(points <= totalPts);

        return points.mul(PRECISION).div(totalPts);
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"_epochPeriod","type":"uint256"},{"internalType":"uint256","name":"_startTimestamp","type":"uint256"},{"internalType":"contract IERC20","name":"_knc","type":"address"},{"internalType":"uint256","name":"_defaultNetworkFeeBps","type":"uint256"},{"internalType":"uint256","name":"_defaultRewardBps","type":"uint256"},{"internalType":"uint256","name":"_defaultRebateBps","type":"uint256"},{"internalType":"address","name":"_daoOperator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"campaignID","type":"uint256"}],"name":"CancelledCampaign","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum KyberDao.CampaignType","name":"campaignType","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"campaignID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minPercentageInPrecision","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cInPrecision","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tInPrecision","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"options","type":"uint256[]"},{"indexed":false,"internalType":"bytes","name":"link","type":"bytes"}],"name":"NewCampaignCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"campaignID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"option","type":"uint256"}],"name":"Voted","type":"event"},{"inputs":[],"name":"MAX_CAMPAIGN_OPTIONS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_EPOCH_CAMPAIGNS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"brrCampaigns","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignID","type":"uint256"}],"name":"cancelCampaign","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"daoOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochPeriodInSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstEpochStartTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignID","type":"uint256"}],"name":"getCampaignDetails","outputs":[{"internalType":"enum KyberDao.CampaignType","name":"campaignType","type":"uint8"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"totalKNCSupply","type":"uint256"},{"internalType":"uint256","name":"minPercentageInPrecision","type":"uint256"},{"internalType":"uint256","name":"cInPrecision","type":"uint256"},{"internalType":"uint256","name":"tInPrecision","type":"uint256"},{"internalType":"bytes","name":"link","type":"bytes"},{"internalType":"uint256[]","name":"options","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignID","type":"uint256"}],"name":"getCampaignVoteCountData","outputs":[{"internalType":"uint256[]","name":"voteCounts","type":"uint256[]"},{"internalType":"uint256","name":"totalVoteCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignID","type":"uint256"}],"name":"getCampaignWinningOptionAndValue","outputs":[{"internalType":"uint256","name":"optionID","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentEpochNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getCurrentEpochRewardPercentageInPrecision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardInBps","type":"uint256"},{"internalType":"uint256","name":"rebateInBps","type":"uint256"}],"name":"getDataFromRewardAndRebateWithValidation","outputs":[{"internalType":"uint256","name":"data","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getEpochNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestBRRData","outputs":[{"internalType":"uint256","name":"burnInBps","type":"uint256"},{"internalType":"uint256","name":"rewardInBps","type":"uint256"},{"internalType":"uint256","name":"rebateInBps","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"expiryTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestBRRDataWithCache","outputs":[{"internalType":"uint256","name":"burnInBps","type":"uint256"},{"internalType":"uint256","name":"rewardInBps","type":"uint256"},{"internalType":"uint256","name":"rebateInBps","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"expiryTimestamp","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getLatestNetworkFeeData","outputs":[{"internalType":"uint256","name":"feeInBps","type":"uint256"},{"internalType":"uint256","name":"expiryTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestNetworkFeeDataWithCache","outputs":[{"internalType":"uint256","name":"feeInBps","type":"uint256"},{"internalType":"uint256","name":"expiryTimestamp","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getListCampaignIDs","outputs":[{"internalType":"uint256[]","name":"campaignIDs","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getPastEpochRewardPercentageInPrecision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"data","type":"uint256"}],"name":"getRebateAndRewardFromData","outputs":[{"internalType":"uint256","name":"rebateInBps","type":"uint256"},{"internalType":"uint256","name":"rewardInBps","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getTotalEpochPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"handleWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"kncToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minCampaignDurationInSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"networkFeeCampaigns","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numberCampaigns","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"numberVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"shouldBurnRewardForEpoch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakerVotedOption","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"staking","outputs":[{"internalType":"contract IKyberStaking","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum KyberDao.CampaignType","name":"campaignType","type":"uint8"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"minPercentageInPrecision","type":"uint256"},{"internalType":"uint256","name":"cInPrecision","type":"uint256"},{"internalType":"uint256","name":"tInPrecision","type":"uint256"},{"internalType":"uint256[]","name":"options","type":"uint256[]"},{"internalType":"bytes","name":"link","type":"bytes"}],"name":"submitNewCampaign","outputs":[{"internalType":"uint256","name":"campaignID","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignID","type":"uint256"},{"internalType":"uint256","name":"option","type":"uint256"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c06040526205460060055560006006553480156200001d57600080fd5b5060405162004dee38038062004dee833981810160405260e08110156200004357600080fd5b508051602082015160408301516060840151608085015160a086015160c0909601516002805460ff191660011790559495939492939192909190806001600160a01b038116620000cd576040805162461bcd60e51b815260206004820152601060248201526f064616f4f70657261746f7220697320360841b604482015290519081900360640190fd5b600480546001600160a01b0319166001600160a01b03929092169190911790558662000140576040805162461bcd60e51b815260206004820152601760248201527f63746f723a2065706f636820706572696f642069732030000000000000000000604482015290519081900360640190fd5b4286101562000196576040805162461bcd60e51b815260206004820152601760248201527f63746f723a20737461727420696e207468652070617374000000000000000000604482015290519081900360640190fd5b6001600160a01b038516620001e6576040805162461bcd60e51b8152602060048201526011602482015270063746f723a206b6e6320746f6b656e203607c1b604482015290519081900360640190fd5b61138884106200023d576040805162461bcd60e51b815260206004820152601660248201527f63746f723a206e6574776f726b20666565206869676800000000000000000000604482015290519081900360640190fd5b6127106200025a83856200036460201b62001dd91790919060201c565b1115620002ae576040805162461bcd60e51b815260206004820152601760248201527f72657761726420706c7573207265626174652068696768000000000000000000604482015290519081900360640190fd5b600087905560018690556001600160601b0319606086901b16608052600c849055604080518082018252848152602001839052600e849055600f839055518590889088903090620002ff90620003c6565b6001600160a01b03948516815260208101939093526040808401929092529092166060820152905190819003608001906000f08015801562000345573d6000803e3d6000fd5b5060601b6001600160601b03191660a05250620003d495505050505050565b600082820183811015620003bf576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b611da6806200304883390190565b60805160601c60a05160601c612c366200041260003980610c8e528061137152806118a052806123da525080610f5452806112165250612c366000f3fe608060405234801561001057600080fd5b50600436106101fb5760003560e01c8063811c7fe21161011a578063b384abef116100ad578063d60d6bd41161007c578063d60d6bd414610672578063d993de621461067a578063e2346d711461078f578063ec0a7cc2146107bb578063f63e7811146107d8576101fb565b8063b384abef14610604578063b484f72614610627578063c70d7b6c1461064d578063d60079bf14610655576101fb565b806399e30ba8116100e957806399e30ba8146105c0578063a81ff705146105ec578063a910d096146105f4578063adea6960146105fc576101fb565b8063811c7fe2146105875780638c9bc2081461058f5780639010984e146105975780639833afaf1461059f576101fb565b806345598b4a11610192578063588df33a11610161578063588df33a1461043f5780636695c981146104475780636fbf12ad1461047a578063809e2c621461049d576101fb565b806345598b4a1461035e57806345bd004e1461037d5780634650e3ab146103ae5780634cf088d91461041b576101fb565b80631c552f00116101ce5780631c552f00146102f0578063220046781461030d57806342322250146103395780634408d2ba14610356576101fb565b80630b4defe4146102005780630bff230a1461022f5780631248a166146102a7578063166b4997146102c4575b600080fd5b61021d6004803603602081101561021657600080fd5b50356107e0565b60408051918252519081900360200190f35b61024c6004803603602081101561024557600080fd5b50356107f2565b6040518080602001838152602001828103825284818151815260200191508051906020019060200280838360005b8381101561029257818101518382015260200161027a565b50505050905001935050505060405180910390f35b61021d600480360360208110156102bd57600080fd5b5035610895565b61021d600480360360408110156102da57600080fd5b506001600160a01b0381351690602001356108aa565b61021d6004803603602081101561030657600080fd5b50356108c7565b61021d6004803603604081101561032357600080fd5b506001600160a01b038135169060200135610924565b61021d6004803603602081101561034f57600080fd5b5035610941565b61021d610953565b61037b6004803603602081101561037457600080fd5b5035610964565b005b61039a6004803603602081101561039357600080fd5b5035610bf7565b604080519115158252519081900360200190f35b6103cb600480360360208110156103c457600080fd5b5035610c2a565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104075781810151838201526020016103ef565b505050509050019250505060405180910390f35b610423610c8c565b604080516001600160a01b039092168252519081900360200190f35b61021d610cb0565b61044f610cb6565b6040805195865260208601949094528484019290925260608401526080830152519081900360a00190f35b61021d6004803603604081101561049057600080fd5b5080359060200135610ce1565b61021d60048036036101008110156104b457600080fd5b60ff8235169160208101359160408201359160608101359160808201359160a08101359181019060e0810160c08201356401000000008111156104f657600080fd5b82018360208201111561050857600080fd5b8035906020019184602083028401116401000000008311171561052a57600080fd5b91939092909160208101903564010000000081111561054857600080fd5b82018360208201111561055a57600080fd5b8035906020019184600183028401116401000000008311171561057c57600080fd5b509092509050610d68565b610423611214565b610423611238565b61021d611247565b6105a761124d565b6040805192835260208301919091528051918290030190f35b61021d600480360360408110156105d657600080fd5b506001600160a01b038135169060200135611266565b61021d611296565b61021d61129b565b6105a76112a0565b61037b6004803603604081101561061a57600080fd5b5080359060200135611353565b61021d6004803603602081101561063d57600080fd5b50356001600160a01b0316611639565b61021d611650565b6105a76004803603602081101561066b57600080fd5b5035611656565b61044f6116a3565b6106976004803603602081101561069057600080fd5b503561175d565b604051808a60028111156106a757fe5b60ff1681526020018981526020018881526020018781526020018681526020018581526020018481526020018060200180602001838103835285818151815260200191508051906020019080838360005b838110156107105781810151838201526020016106f8565b50505050905090810190601f16801561073d5780820380516001836020036101000a031916815260200191505b508381038252845181528451602091820191808701910280838360005b8381101561077257818101518382015260200161075a565b505050509050019b50505050505050505050505060405180910390f35b61037b600480360360408110156107a557600080fd5b506001600160a01b038135169060200135611895565b6105a7600480360360208110156107d157600080fd5b5035611acc565b61021d611d4f565b60106020526000908152604090205481565b606060006107fe6127f8565b60076000858152602001908152602001600020600901604051806040016040529081600082015481526020016001820180548060200260200160405190810160405280929190818152602001828054801561087857602002820191906000526020600020905b815481526020019060010190808311610864575b505050919092525050815160209092015196919550909350505050565b6000818152600960205260409020545b919050565b600b60209081526000928352604080842090915290825290205481565b60006001548210806108d95750600054155b156108e6575060006108a5565b61091e600161091260005461090660015487611d5590919063ffffffff16565b9063ffffffff611d9716565b9063ffffffff611dd916565b92915050565b600a60209081526000928352604080842090915290825290205481565b600d6020526000908152604090205481565b600061095e426108c7565b90505b90565b6004546001600160a01b031633146109b6576040805162461bcd60e51b815260206004820152601060248201526f37b7363c903230b7a7b832b930ba37b960811b604482015290519081900360640190fd5b60008181526007602052604090208054610100900460ff16610a095760405162461bcd60e51b8152600401808060200182810382526028815260200180612bd96028913960400191505060405180910390fd5b42816001015411610a4b5760405162461bcd60e51b8152600401808060200182810382526028815260200180612a256028913960400191505060405180910390fd5b6000610a5a82600101546108c7565b90506001825460ff166002811115610a6e57fe5b1415610a88576000818152600d6020526040812055610ab0565b6002825460ff166002811115610a9a57fe5b1415610ab0576000818152601060205260408120555b60008381526007602081905260408220805461ffff191681556001810183905560028101839055600381018390556004810183905560058101839055600681018390559190610b0190830182612812565b610b0f600883016000612859565b60006009830181815590610b26600a850182612859565b505050600082815260086020526040812091505b8154811015610bc55784828281548110610b5057fe5b90600052602060002001541415610bbd57815482906000198101908110610b7357fe5b9060005260206000200154828281548110610b8a57fe5b906000526020600020018190555081805480610ba257fe5b60019003818190600052602060002001600090559055610bc5565b600101610b3a565b5060405184907fef29bb5bcfd2b2ff4bc50d710898467757ff87aad1031fc953907b65127f86fc90600090a250505050565b600080610c02610953565b9050808310610c155760009150506108a5565b50506000908152600960205260409020541590565b600081815260086020908152604091829020805483518184028101840190945280845260609392830182828015610c8057602002820191906000526020600020905b815481526020019060010190808311610c6c575b50505050509050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60065481565b6000806000806000610cc66116a3565b600e849055600f839055939992985090965094509092509050565b6000612710610cf6848463ffffffff611dd916565b1115610d49576040805162461bcd60e51b815260206004820152601760248201527f72657761726420706c7573207265626174652068696768000000000000000000604482015290519081900360640190fd5b610d618361091284600160801b63ffffffff611e3316565b9392505050565b6004546000906001600160a01b03163314610dbd576040805162461bcd60e51b815260206004820152601060248201526f37b7363c903230b7a7b832b930ba37b960811b604482015290519081900360640190fd5b6000610dc88b6108c7565b9050610e0c8c8c8c8c8c8c8c8c80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611e8c92505050565b600654610e2090600163ffffffff611dd916565b60068190556000828152600860209081526040822080546001818101835591845291909220018290559092508c6002811115610e5857fe5b1415610e74576000818152600d60205260409020829055610e9a565b60028c6002811115610e8257fe5b1415610e9a5760008181526010602052604090208290555b610ea2612877565b60405180606001604052808b81526020018a8152602001898152509050610ec76127f8565b6040805180820190915260008152602081018867ffffffffffffffff81118015610ef057600080fd5b50604051908082528060200260200182016040528015610f1a578160200160208202803683370190505b5081525090506040518061012001604052808f6002811115610f3857fe5b81526020016001151581526020018e81526020018d81526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fab57600080fd5b505afa158015610fbf573d6000803e3d6000fd5b505050506040513d6020811015610fd557600080fd5b50518152602081810185905260408051601f8a0183900483028101830182528981529201919089908990819084018382808284376000920191909152505050908252506040805160208b810282810182019093528b82529283019290918c918c9182918501908490808284376000920182905250938552505050602091820184905286815260079091526040902081518154829060ff1916600183600281111561107b57fe5b021790555060208281015182549015156101000261ff00199091161782556040808401516001840155606084015160028401556080840151600384015560a0840151805160048501558083015160058501550151600683015560c083015180516110eb9260078501920190612898565b5060e08201518051611107916008840191602090910190612916565b50610100820151805160098301908155602080830151805161112f92600a8701920190612916565b505050905050837fba908e34477602dcf3b8b10115cb9ba1f56c512e94a0beb561ad0245026cda138f8f8f8f8f8f8f8f8f8f604051808b600281111561117157fe5b60ff1681526020018a815260200189815260200188815260200187815260200186815260200180602001806020018381038352878782818152602001925060200280828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039e50909c50505050505050505050505050a25050509a9950505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6004546001600160a01b031681565b60055481565b6000806112586112a0565b600c82905590939092509050565b600080611271610953565b905080831061128457600091505061091e565b61128e84846123a0565b949350505050565b600881565b600a81565b60008060006112ad610953565b9050600c5492506112ec60016112e06112d160005485611e3390919063ffffffff16565b6001549063ffffffff611dd916565b9063ffffffff611d5516565b9150806112f9575061134f565b6000600d8161130f84600163ffffffff611d5516565b81526020019081526020016000205490508060001415611331575061134f9050565b600061133c82611acc565b955090508061134b57600c5494505b5050505b9091565b61135d828261252e565b336000611368610953565b905060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b7a13c4c866040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050606060405180830381600087803b1580156113e757600080fd5b505af11580156113fb573d6000803e3d6000fd5b505050506040513d606081101561141157600080fd5b5080516020820151604090920151909450909250905060006001600160a01b03808316908716146114425782611452565b611452848463ffffffff611dd916565b6001600160a01b0387166000908152600b602090815260408083208c845282528083205460079092529091209192509060090181611545576001600160a01b0388166000908152600a602090815260408083208a845282528083208054600101905560099091529020546114cc908463ffffffff611dd916565b60008881526009602052604090205560018101805461150e9185916000198d019081106114f557fe5b9060005260206000200154611dd990919063ffffffff16565b8160010160018b038154811061152057fe5b600091825260209091200155805461153e908463ffffffff611dd916565b81556115d0565b8882146115d05761157b8382600101600185038154811061156257fe5b9060005260206000200154611d5590919063ffffffff16565b81600101600184038154811061158d57fe5b90600052602060002001819055506115b1838260010160018c03815481106114f557fe5b8160010160018b03815481106115c357fe5b6000918252602090912001555b6001600160a01b0388166000818152600b602090815260408083208e84528252918290208c905581518c815291518d938b9390927fc32b42768a47a585121e9b8d7a2ab9d3f34c326a192dee11ee1732e3d18313f392918290030190a450505050505050505050565b600080611644610953565b9050610d6183826123a0565b60015481565b60008061166e600160801b600163ffffffff611d5516565b83169050611687600160801b600163ffffffff611d5516565b61169b84600160801b63ffffffff611d9716565b169150915091565b60008060008060006116b3610953565b91506116d260016112e06112d160005486611e3390919063ffffffff16565b600e54600f5490955093509050811561173e5760006010816116fb85600163ffffffff611d5516565b81526020019081526020016000205490508060001461173c5760008061172083611acc565b909250905081156117395761173481611656565b975095505b50505b505b611754846112e06127108663ffffffff611d5516565b94509091929394565b600081815260076020818152604092839020805460018083015460028085015460038601546004870154600588015460068901549a890180548d516101009982161599909902600019011695909504601f81018b90048b0288018b01909c528b875260ff9097169a94999298919790969592946060948594929390919083018282801561182b5780601f106118005761010080835404028352916020019161182b565b820191906000526020600020905b81548152906001019060200180831161180e57829003601f168201915b505050505092508060080180548060200260200160405190810160405280929190818152602001828054801561188057602002820191906000526020600020905b81548152602001906001019080831161186c575b50505050509150509193959799909294969850565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611912576040805162461bcd60e51b815260206004820152601560248201527f6f6e6c79207374616b696e6720636f6e74726163740000000000000000000000604482015290519081900360640190fd5b8061191c57611ac8565b6000611926610953565b6001600160a01b0384166000908152600a6020908152604080832084845290915290205490915080611959575050611ac8565b61198761196c828563ffffffff611e3316565b6000848152600960205260409020549063ffffffff611d5516565b60008381526009602090815260408083209390935560088152908290208054835181840281018401909452808452606093928301828280156119e857602002820191906000526020600020905b8154815260200190600101908083116119d4575b50939450600093505050505b8151811015611ac3576000828281518110611a0b57fe5b6020908102919091018101516001600160a01b0389166000908152600b83526040808220838352909352919091205490915080611a49575050611abb565b600082815260076020526040902060028101544211611ab7576009810154611a77908963ffffffff611d5516565b6009820155600a81018054611a96918a91600019860190811061156257fe5b600a820180546000198501908110611aaa57fe5b6000918252602090912001555b5050505b6001016119f4565b505050505b5050565b60008181526007602052604081208054829190610100900460ff16611af8575060009150819050611d4a565b4281600201541115611b11575060009150819050611d4a565b600381015480611b2a575060009250829150611d4a9050565b6009820154600a830180546040805160208084028201810190925282815260609390929091830182828015611b7e57602002820191906000526020600020905b815481526020019060010190808311611b6a575b5093945060009350839250829150505b8351811015611bfb5781848281518110611ba457fe5b60200260200101511115611bd357806001019250838181518110611bc457fe5b60200260200101519150611bf3565b81848281518110611be057fe5b60200260200101511415611bf357600092505b600101611b8e565b5081611c14575060009650869550611d4a945050505050565b611c1c612877565b506040805160608101825260048801548152600588015460208201526006880154918101919091526003870154600090611c689061090688670de0b6b3a764000063ffffffff611e3316565b90508082600001511115611c8b575060009850889750611d4a9650505050505050565b6000611cb0670de0b6b3a7640000610906848660400151611e3390919063ffffffff16565b905082602001518111611d1e576020830151600090611cd5908363ffffffff611d5516565b9050611ce7818963ffffffff611e3316565b611cff86670de0b6b3a764000063ffffffff611e3316565b1015611d1c575060009a508a9950611d4a98505050505050505050565b505b849a508860080160018c0381548110611d3357fe5b906000526020600020015499505050505050505050505b915091565b60005481565b6000610d6183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506126fc565b6000610d6183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612793565b600082820183811015610d61576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082611e425750600061091e565b82820282848281611e4f57fe5b0414610d615760405162461bcd60e51b8152600401808060200182810382526021815260200180612a4d6021913960400191505060405180910390fd5b42861015611ecb5760405162461bcd60e51b815260040180806020018281038252602181526020018061296b6021913960400191505060405180910390fd5b600554611edf90879063ffffffff611dd916565b611ef086600163ffffffff611dd916565b1015611f2d5760405162461bcd60e51b8152600401808060200182810382526028815260200180612acf6028913960400191505060405180910390fd5b6000611f38876108c7565b90506000611f45876108c7565b600083815260086020526040902054909150600a11611f955760405162461bcd60e51b815260040180806020018281038252602281526020018061298c6022913960400191505060405180910390fd5b808214611fd35760405162461bcd60e51b815260040180806020018281038252602a815260200180612a6e602a913960400191505060405180910390fd5b6000611fdd610953565b9050611ff081600163ffffffff611dd916565b83111561202e5760405162461bcd60e51b815260040180806020018281038252602f815260200180612baa602f913960400191505060405180910390fd5b8351600181118015612041575060088111155b61207c5760405162461bcd60e51b8152600401808060200182810382526029815260200180612b816029913960400191505060405180910390fd5b60008b600281111561208a57fe5b14156120fc5760005b85518110156120f65760008682815181106120aa57fe5b6020026020010151116120ee5760405162461bcd60e51b815260040180806020018281038252602c815260200180612af7602c913960400191505060405180910390fd5b600101612093565b5061229c565b60018b600281111561210a57fe5b14156121c5576000848152600d60205260409020541561215b5760405162461bcd60e51b815260040180806020018281038252603f8152602001806129ae603f913960400191505060405180910390fd5b60005b85518110156120f65760026127100486828151811061217957fe5b6020026020010151106121bd5760405162461bcd60e51b8152600401808060200182810382526038815260200180612b496038913960400191505060405180910390fd5b60010161215e565b600084815260106020526040902054156122105760405162461bcd60e51b8152600401808060200182810382526037815260200180612a986037913960400191505060405180910390fd5b60005b855181101561229a5760008061223b88848151811061222e57fe5b6020026020010151611656565b9092509050612710612253828463ffffffff611dd916565b11156122905760405162461bcd60e51b81526004018080602001828103825260388152602001806129ed6038913960400191505060405180910390fd5b5050600101612213565b505b670de0b6b3a76400008811156122e35760405162461bcd60e51b8152600401808060200182810382526026815260200180612b236026913960400191505060405180910390fd5b600160801b871061233b576040805162461bcd60e51b815260206004820152601960248201527f76616c6964617465506172616d733a2063206973206869676800000000000000604482015290519081900360640190fd5b600160801b8610612393576040805162461bcd60e51b815260206004820152601960248201527f76616c6964617465506172616d733a2074206973206869676800000000000000604482015290519081900360640190fd5b5050505050505050505050565b6001600160a01b0382166000908152600a60209081526040808320848452909152812054806123d357600091505061091e565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166316554d6288886040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060606040518083038186803b15801561245657600080fd5b505afa15801561246a573d6000803e3d6000fd5b505050506040513d606081101561248057600080fd5b5080516020820151604090920151909450909250905060006001600160a01b03808316908916146124b157826124c1565b6124c1848463ffffffff611dd916565b9050806124d65760009550505050505061091e565b60006124e8868363ffffffff611e3316565b6000898152600960205260409020549091508082111561250457fe5b6125208161090684670de0b6b3a764000063ffffffff611e3316565b9a9950505050505050505050565b60008281526007602052604090208054610100900460ff16612597576040805162461bcd60e51b815260206004820152601c60248201527f766f74653a2063616d706169676e20646f65736e277420657869737400000000604482015290519081900360640190fd5b42816001015411156125f0576040805162461bcd60e51b815260206004820152601a60248201527f766f74653a2063616d706169676e206e6f742073746172746564000000000000604482015290519081900360640190fd5b4281600201541015612649576040805162461bcd60e51b815260206004820152601c60248201527f766f74653a2063616d706169676e20616c726561647920656e64656400000000604482015290519081900360640190fd5b6000821161269e576040805162461bcd60e51b815260206004820152601160248201527f766f74653a206f7074696f6e2069732030000000000000000000000000000000604482015290519081900360640190fd5b60088101548211156126f7576040805162461bcd60e51b815260206004820152601c60248201527f766f74653a206f7074696f6e206973206e6f7420696e2072616e676500000000604482015290519081900360640190fd5b505050565b6000818484111561278b5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612750578181015183820152602001612738565b50505050905090810190601f16801561277d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600081836127e25760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612750578181015183820152602001612738565b5060008385816127ee57fe5b0495945050505050565b604051806040016040528060008152602001606081525090565b50805460018160011615610100020316600290046000825580601f106128385750612856565b601f0160209004906000526020600020908101906128569190612950565b50565b50805460008255906000526020600020908101906128569190612950565b60405180606001604052806000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106128d957805160ff1916838001178555612906565b82800160010185558215612906579182015b828111156129065782518255916020019190600101906128eb565b50612912929150612950565b5090565b82805482825590600052602060002090810192821561290657916020028201828111156129065782518255916020019190600101906128eb565b61096191905b80821115612912576000815560010161295656fe76616c6964617465506172616d733a20737461727420696e20746865207061737476616c6964617465506172616d733a20746f6f206d616e792063616d706169676e7376616c6964617465506172616d733a20616c726561647920686164206e6574776f726b206665652063616d706169676e20666f7220746869732065706f636876616c6964617465506172616d733a20726562617465202b207265776172642063616e277420626520626967676572207468616e2042505363616e63656c43616d706169676e3a2063616d706169676e20616c72656164792073746172746564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7776616c6964617465506172616d733a207374617274202620656e64206e6f742073616d652065706f636876616c6964617465506172616d733a20616c726561647920686164206272722063616d706169676e20666f7220746869732065706f636876616c6964617465506172616d733a2063616d706169676e206475726174696f6e206973206c6f7776616c6964617465506172616d733a2067656e6572616c2063616d706169676e206f7074696f6e206973203076616c6964617465506172616d733a206d696e2070657263656e74616765206973206869676876616c6964617465506172616d733a206e6574776f726b20666565206d75737420626520736d616c6c6572207468656e20425053202f203276616c6964617465506172616d733a20696e76616c6964206e756d626572206f66206f7074696f6e7376616c6964617465506172616d733a206f6e6c7920666f722063757272656e74206f72206e6578742065706f63687363616e63656c43616d706169676e3a2063616d706169676e494420646f65736e2774206578697374a2646970667358221220313c6142437875dcaf3f6546db75663d187e82ca7247be8fa4039cdd632f8a2864736f6c6343000606003360c060405234801561001057600080fd5b50604051611da6380380611da68339818101604052608081101561003357600080fd5b508051602082015160408301516060909301516002805460ff1916600117905591929091826100a9576040805162461bcd60e51b815260206004820152601760248201527f63746f723a2065706f636820706572696f642069732030000000000000000000604482015290519081900360640190fd5b428210156100fe576040805162461bcd60e51b815260206004820152601760248201527f63746f723a20737461727420696e207468652070617374000000000000000000604482015290519081900360640190fd5b6001600160a01b03841661014c576040805162461bcd60e51b815260206004820152601060248201526f063746f723a206b6e63546f6b656e20360841b604482015290519081900360640190fd5b6001600160a01b03811661019a576040805162461bcd60e51b815260206004820152601060248201526f063746f723a206b7962657244616f20360841b604482015290519081900360640190fd5b6000929092556001556001600160601b0319606092831b8116608052911b1660a05260805160601c60a05160601c611ba86101fe6000398061095d5280610f125280610f87528061154d525080610786528061117552806112c65250611ba86000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c8063711bbfd9116100ad578063c70d7b6c11610071578063c70d7b6c1461036b578063cfd4766314610373578063d42b72541461039f578063d46684b2146103c5578063f63e7811146103f15761012c565b8063711bbfd9146102c2578063811c7fe2146102f4578063901ab5b2146102fc578063b6b55f2514610328578063b7a13c4c146103455761012c565b80634408d2ba116100f45780634408d2ba146102245780634d8f51051461022c5780635c19a95c146102505780635ee5b4771461027657806360e4f2e01461029c5761012c565b8063072b77f11461013157806316554d62146101695780631c552f00146101bc5780632e1a7d4d146101d957806342ce39cb146101f8575b600080fd5b6101576004803603602081101561014757600080fd5b50356001600160a01b03166103f9565b60408051918252519081900360200190f35b6101956004803603604081101561017f57600080fd5b506001600160a01b038135169060200135610418565b6040805193845260208401929092526001600160a01b031682820152519081900360600190f35b610157600480360360208110156101d257600080fd5b503561047c565b6101f6600480360360208110156101ef57600080fd5b50356104d9565b005b6101956004803603604081101561020e57600080fd5b506001600160a01b03813516906020013561089e565b61015761094b565b61023461095b565b604080516001600160a01b039092168252519081900360200190f35b6101f66004803603602081101561026657600080fd5b50356001600160a01b031661097f565b6102346004803603602081101561028c57600080fd5b50356001600160a01b0316610c95565b610195600480360360208110156102b257600080fd5b50356001600160a01b0316610ce1565b6101f6600480360360608110156102d857600080fd5b506001600160a01b038135169060208101359060400135610d3f565b610234611173565b6102346004803603604081101561031257600080fd5b506001600160a01b038135169060200135611197565b6101f66004803603602081101561033e57600080fd5b5035611233565b6101956004803603602081101561035b57600080fd5b50356001600160a01b031661153e565b610157611635565b6101576004803603604081101561038957600080fd5b506001600160a01b03813516906020013561163b565b610157600480360360208110156103b557600080fd5b50356001600160a01b03166116d4565b610157600480360360408110156103db57600080fd5b506001600160a01b0381351690602001356116f2565b610157611783565b6001600160a01b0381166000908152600460205260409020545b919050565b6000806000610425611b16565b5050506000918252506003602090815260408083206001600160a01b039485168452825291829020825160608101845281548082526001830154938201849052600290920154909416939092018390529092909190565b600060015482108061048e5750600054155b1561049b57506000610413565b6104d360016104c76000546104bb6001548761178990919063ffffffff16565b9063ffffffff6117d216565b9063ffffffff61181416565b92915050565b60025460ff16610530576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002805460ff191690558061058c576040805162461bcd60e51b815260206004820152601560248201527f77697468647261773a20616d6f756e7420697320300000000000000000000000604482015290519081900360640190fd5b600061059661094b565b33600081815260046020526040902054919250908311156105e85760405162461bcd60e51b8152600401808060200182810382526032815260200180611b416032913960400191505060405180910390fd5b604080516001600160a01b038316602482015260448101859052606480820185905282518083039091018152608490910182526020810180516001600160e01b031663711bbfd960e01b17815291518151600093309392918291908083835b602083106106665780518252601f199092019160209182019101610647565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146106c8576040519150601f19603f3d011682016040523d82523d6000602084013e6106cd565b606091505b505090508061071f57604080518481526001600160a01b038416602082015280820186905290517fa412eef5316d3cbf9e2b4ba3d1cf3e482b40dc8946fd919b7f5053450fa621fb9181900360600190a15b6001600160a01b038216600090815260046020526040902054610748908563ffffffff61178916565b6001600160a01b03808416600081815260046020818152604080842096909655855163a9059cbb60e01b8152918201939093526024810189905293517f00000000000000000000000000000000000000000000000000000000000000009093169363a9059cbb936044808301949391928390030190829087803b1580156107ce57600080fd5b505af11580156107e2573d6000803e3d6000fd5b505050506040513d60208110156107f857600080fd5b505161084b576040805162461bcd60e51b815260206004820152601e60248201527f77697468647261773a2063616e206e6f74207472616e73666572206b6e630000604482015290519081900360640190fd5b6040805185815290516001600160a01b0384169185917f9da6493a92039daf47d1f2d7a782299c5994c6323eb1e972f69c432089ec52bf9181900360200190a350506002805460ff191660011790555050565b60008080806108ab61094b565b9050806001018511156108be5750610944565b845b60008181526005602090815260408083206001600160a01b038b16845290915290205460ff161561092b5760009081526003602090815260408083206001600160a01b038a811685529252909120805460018201546002909201549096509094501691506109449050565b806109355761093e565b600019016108c0565b86925050505b9250925092565b60006109564261047c565b905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b6001600160a01b0381166109da576040805162461bcd60e51b815260206004820152601a60248201527f64656c65676174653a20726570726573656e7461746976652030000000000000604482015290519081900360640190fd5b3360006109e561094b565b90506109f1828261186e565b6001810160009081526003602090815260408083206001600160a01b0380871685529252909120600201548116908416811415610a3057505050610c92565b6001820160009081526003602090815260408083206001600160a01b03808816808652919093529220549190831614610b4757610a6d828461186e565b600180840160009081526003602090815260408083206001600160a01b038716845290915290200154610aa6908263ffffffff61178916565b600180850160009081526003602090815260408083206001600160a01b0388168452825280832084019490945560049052919091200154610aed908263ffffffff61178916565b6001600160a01b0380841660008181526004602090815260408083206001019590955584519182529351879492938916927ffbb976ae5268347766b726bd1edba29af0fe16f9c505fbd3b9a10cb6d00cfa3d928290030190a45b6001600160a01b03808516600081815260046020908152604080832060029081018054968c166001600160a01b0319978816811790915560018a0185526003845282852086865290935292209091018054909316811790925514610c8d57610baf858461186e565b600180840160009081526003602090815260408083206001600160a01b038a16845290915290200154610be8908263ffffffff61181416565b600180850160009081526003602090815260408083206001600160a01b038b168452825280832084019490945560049052919091200154610c2f908263ffffffff61181416565b6001600160a01b0380871660008181526004602090815260409182902060019081019590955581519485529051879492938916927ffbb976ae5268347766b726bd1edba29af0fe16f9c505fbd3b9a10cb6d00cfa3d92908290030190a45b505050505b50565b6001600160a01b0381811660009081526004602052604081206002015490911615610cdd576001600160a01b03808316600090815260046020526040902060020154166104d3565b5090565b6001600160a01b0380821660009081526004602052604081208054600182015460029092015490939192911615610d35576001600160a01b0380851660009081526004602052604090206002015416610d37565b835b929491935050565b333014610d93576040805162461bcd60e51b815260206004820152601560248201527f6f6e6c79207374616b696e6720636f6e74726163740000000000000000000000604482015290519081900360640190fd5b610d9d838261186e565b6001810160009081526003602090815260408083206001600160a01b0387168452909152902054610dd4908363ffffffff61178916565b6001820160009081526003602081815260408084206001600160a01b03808a16808752918452828620969096558685529282528084208385528252808420600281015493855254600490925283205491909316929190610e3a908663ffffffff61178916565b90506000610e4e838363ffffffff611a0416565b90506000610e62848363ffffffff61178916565b9050801561108c57876001600160a01b0316856001600160a01b031614610eea57610e8d858761186e565b60008681526003602090815260408083206001600160a01b0389168452909152902060010154610ec3908263ffffffff61178916565b60008781526003602090815260408083206001600160a01b038a1684529091529020600101555b60008681526003602090815260408083206001600160a01b03808d16855292529091208390557f0000000000000000000000000000000000000000000000000000000000000000161561108c57604080516001600160a01b038781166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663e2346d7160e01b178152925182516000947f000000000000000000000000000000000000000000000000000000000000000093909316939282918083835b60208310610fd15780518252601f199092019160209182019101610fb2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611033576040519150601f19603f3d011682016040523d82523d6000602084013e611038565b606091505b505090508061108a57604080518881526001600160a01b038b1660208201528082018a905290517fa412eef5316d3cbf9e2b4ba3d1cf3e482b40dc8946fd919b7f5053450fa621fb9181900360600190a15b505b6001860160009081526003602090815260408083206001600160a01b03808d16808652919093529220600201541695508514611169576110cc858761186e565b600180870160009081526003602090815260408083206001600160a01b038a16845290915290200154611105908863ffffffff61178916565b600180880160009081526003602090815260408083206001600160a01b038b16845282528083208401949094556004905291909120015461114c908863ffffffff61178916565b6001600160a01b0386166000908152600460205260409020600101555b5050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000806111a261094b565b9050806001018311156111b95760009150506104d3565b825b60008181526005602090815260408083206001600160a01b038916845290915290205460ff16156112175760009081526003602090815260408083206001600160a01b0380891685529252909120600201541691506104d39050565b806112215761122a565b600019016111bb565b50929392505050565b60008111611288576040805162461bcd60e51b815260206004820152601460248201527f6465706f7369743a20616d6f756e742069732030000000000000000000000000604482015290519081900360640190fd5b600061129261094b565b604080516323b872dd60e01b8152336004820181905230602483015260448201869052915192935090916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916323b872dd9160648083019260209291908290030181600087803b15801561130e57600080fd5b505af1158015611322573d6000803e3d6000fd5b505050506040513d602081101561133857600080fd5b505161138b576040805162461bcd60e51b815260206004820152601a60248201527f6465706f7369743a2063616e206e6f742067657420746f6b656e000000000000604482015290519081900360640190fd5b611395818361186e565b6001820160009081526003602090815260408083206001600160a01b03851684529091529020546113cc908463ffffffff61181416565b6001830160009081526003602090815260408083206001600160a01b038616845282528083209390935560049052205461140c908463ffffffff61181416565b6001600160a01b038083166000818152600460209081526040808320959095556001870182526003815284822083835290529290922060020154169081146114f557611458818461186e565b600180840160009081526003602090815260408083206001600160a01b038616845290915290200154611491908563ffffffff61181416565b600180850160009081526003602090815260408083206001600160a01b03871684528252808320840194909455600490529190912001546114d8908563ffffffff61181416565b6001600160a01b0382166000908152600460205260409020600101555b604080518481526020810186905281516001600160a01b038516927f1599c0fcf897af5babc2bfcf707f5dc050f841b044d97c3251ecec35b9abf80b928290030190a250505050565b60008080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146115bf576040805162461bcd60e51b815260206004820181905260248201527f696e6974416e6452657475726e446174613a206f6e6c79206b7962657244616f604482015290519081900360640190fd5b60006115c961094b565b90506115d5858261186e565b6115dd611b16565b5060009081526003602090815260408083206001600160a01b03978816845282529182902082516060810184528154808252600183015493820184905260029092015490971696909201869052909590949350915050565b60015481565b60008061164661094b565b90508060010183111561165d5760009150506104d3565b825b60008181526005602090815260408083206001600160a01b038916845290915290205460ff16156116b65760009081526003602090815260408083206001600160a01b038816845290915290205491506104d39050565b806116c0576116c9565b6000190161165f565b506000949350505050565b6001600160a01b031660009081526004602052604090206001015490565b6000806116fd61094b565b9050806001018311156117145760009150506104d3565b825b60008181526005602090815260408083206001600160a01b038916845290915290205460ff16156117705760009081526003602090815260408083206001600160a01b038816845290915290206001015491506104d39050565b8061177a576116c9565b60001901611716565b60005481565b60006117cb83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611a1a565b9392505050565b60006117cb83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611ab1565b6000828201838110156117cb576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6001600160a01b0380831660009081526004602052604090206002015416806118c057506001600160a01b038216600081815260046020526040902060020180546001600160a01b0319169091179055815b6001600160a01b03831660008181526004602090815260408083206001810154905487855260058452828520958552949092529091205490919060ff1661196c5760008481526005602090815260408083206001600160a01b038981168086529184528285208054600160ff199091168117909155898652600385528386209286529190935292206002810180546001600160a01b031916928716929092179091559081018390558190555b6001840160009081526005602090815260408083206001600160a01b038916845290915290205460ff16610c8d57600193840160008181526005602090815260408083206001600160a01b03998a16808552908352818420805460ff19168a17905593835260038252808320938352929052206002810180546001600160a01b03191694909616939093179094559181019190915555565b6000818310611a1357816117cb565b5090919050565b60008184841115611aa95760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611a6e578181015183820152602001611a56565b50505050905090810190601f168015611a9b5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008183611b005760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611a6e578181015183820152602001611a56565b506000838581611b0c57fe5b0495945050505050565b6040518060600160405280600081526020016000815260200160006001600160a01b03168152509056fe77697468647261773a206c617465737420616d6f756e74207374616b6564203c207769746864726177616c20616d6f756e74a2646970667358221220e226a6302b84b358849f5b5e0f541d9614dcdad0cedb6d983293d343b124399564736f6c634300060600330000000000000000000000000000000000000000000000000000000000127500000000000000000000000000000000000000000000000000000000005f0d599b000000000000000000000000dd974d5c2e2928dea5f71b9825b8b646686bd200000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000019640000000000000000000000000000000000000000000000000000000000000bb8000000000000000000000000e6a7338cba0a1070adfb22c07115299605454713

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101fb5760003560e01c8063811c7fe21161011a578063b384abef116100ad578063d60d6bd41161007c578063d60d6bd414610672578063d993de621461067a578063e2346d711461078f578063ec0a7cc2146107bb578063f63e7811146107d8576101fb565b8063b384abef14610604578063b484f72614610627578063c70d7b6c1461064d578063d60079bf14610655576101fb565b806399e30ba8116100e957806399e30ba8146105c0578063a81ff705146105ec578063a910d096146105f4578063adea6960146105fc576101fb565b8063811c7fe2146105875780638c9bc2081461058f5780639010984e146105975780639833afaf1461059f576101fb565b806345598b4a11610192578063588df33a11610161578063588df33a1461043f5780636695c981146104475780636fbf12ad1461047a578063809e2c621461049d576101fb565b806345598b4a1461035e57806345bd004e1461037d5780634650e3ab146103ae5780634cf088d91461041b576101fb565b80631c552f00116101ce5780631c552f00146102f0578063220046781461030d57806342322250146103395780634408d2ba14610356576101fb565b80630b4defe4146102005780630bff230a1461022f5780631248a166146102a7578063166b4997146102c4575b600080fd5b61021d6004803603602081101561021657600080fd5b50356107e0565b60408051918252519081900360200190f35b61024c6004803603602081101561024557600080fd5b50356107f2565b6040518080602001838152602001828103825284818151815260200191508051906020019060200280838360005b8381101561029257818101518382015260200161027a565b50505050905001935050505060405180910390f35b61021d600480360360208110156102bd57600080fd5b5035610895565b61021d600480360360408110156102da57600080fd5b506001600160a01b0381351690602001356108aa565b61021d6004803603602081101561030657600080fd5b50356108c7565b61021d6004803603604081101561032357600080fd5b506001600160a01b038135169060200135610924565b61021d6004803603602081101561034f57600080fd5b5035610941565b61021d610953565b61037b6004803603602081101561037457600080fd5b5035610964565b005b61039a6004803603602081101561039357600080fd5b5035610bf7565b604080519115158252519081900360200190f35b6103cb600480360360208110156103c457600080fd5b5035610c2a565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156104075781810151838201526020016103ef565b505050509050019250505060405180910390f35b610423610c8c565b604080516001600160a01b039092168252519081900360200190f35b61021d610cb0565b61044f610cb6565b6040805195865260208601949094528484019290925260608401526080830152519081900360a00190f35b61021d6004803603604081101561049057600080fd5b5080359060200135610ce1565b61021d60048036036101008110156104b457600080fd5b60ff8235169160208101359160408201359160608101359160808201359160a08101359181019060e0810160c08201356401000000008111156104f657600080fd5b82018360208201111561050857600080fd5b8035906020019184602083028401116401000000008311171561052a57600080fd5b91939092909160208101903564010000000081111561054857600080fd5b82018360208201111561055a57600080fd5b8035906020019184600183028401116401000000008311171561057c57600080fd5b509092509050610d68565b610423611214565b610423611238565b61021d611247565b6105a761124d565b6040805192835260208301919091528051918290030190f35b61021d600480360360408110156105d657600080fd5b506001600160a01b038135169060200135611266565b61021d611296565b61021d61129b565b6105a76112a0565b61037b6004803603604081101561061a57600080fd5b5080359060200135611353565b61021d6004803603602081101561063d57600080fd5b50356001600160a01b0316611639565b61021d611650565b6105a76004803603602081101561066b57600080fd5b5035611656565b61044f6116a3565b6106976004803603602081101561069057600080fd5b503561175d565b604051808a60028111156106a757fe5b60ff1681526020018981526020018881526020018781526020018681526020018581526020018481526020018060200180602001838103835285818151815260200191508051906020019080838360005b838110156107105781810151838201526020016106f8565b50505050905090810190601f16801561073d5780820380516001836020036101000a031916815260200191505b508381038252845181528451602091820191808701910280838360005b8381101561077257818101518382015260200161075a565b505050509050019b50505050505050505050505060405180910390f35b61037b600480360360408110156107a557600080fd5b506001600160a01b038135169060200135611895565b6105a7600480360360208110156107d157600080fd5b5035611acc565b61021d611d4f565b60106020526000908152604090205481565b606060006107fe6127f8565b60076000858152602001908152602001600020600901604051806040016040529081600082015481526020016001820180548060200260200160405190810160405280929190818152602001828054801561087857602002820191906000526020600020905b815481526020019060010190808311610864575b505050919092525050815160209092015196919550909350505050565b6000818152600960205260409020545b919050565b600b60209081526000928352604080842090915290825290205481565b60006001548210806108d95750600054155b156108e6575060006108a5565b61091e600161091260005461090660015487611d5590919063ffffffff16565b9063ffffffff611d9716565b9063ffffffff611dd916565b92915050565b600a60209081526000928352604080842090915290825290205481565b600d6020526000908152604090205481565b600061095e426108c7565b90505b90565b6004546001600160a01b031633146109b6576040805162461bcd60e51b815260206004820152601060248201526f37b7363c903230b7a7b832b930ba37b960811b604482015290519081900360640190fd5b60008181526007602052604090208054610100900460ff16610a095760405162461bcd60e51b8152600401808060200182810382526028815260200180612bd96028913960400191505060405180910390fd5b42816001015411610a4b5760405162461bcd60e51b8152600401808060200182810382526028815260200180612a256028913960400191505060405180910390fd5b6000610a5a82600101546108c7565b90506001825460ff166002811115610a6e57fe5b1415610a88576000818152600d6020526040812055610ab0565b6002825460ff166002811115610a9a57fe5b1415610ab0576000818152601060205260408120555b60008381526007602081905260408220805461ffff191681556001810183905560028101839055600381018390556004810183905560058101839055600681018390559190610b0190830182612812565b610b0f600883016000612859565b60006009830181815590610b26600a850182612859565b505050600082815260086020526040812091505b8154811015610bc55784828281548110610b5057fe5b90600052602060002001541415610bbd57815482906000198101908110610b7357fe5b9060005260206000200154828281548110610b8a57fe5b906000526020600020018190555081805480610ba257fe5b60019003818190600052602060002001600090559055610bc5565b600101610b3a565b5060405184907fef29bb5bcfd2b2ff4bc50d710898467757ff87aad1031fc953907b65127f86fc90600090a250505050565b600080610c02610953565b9050808310610c155760009150506108a5565b50506000908152600960205260409020541590565b600081815260086020908152604091829020805483518184028101840190945280845260609392830182828015610c8057602002820191906000526020600020905b815481526020019060010190808311610c6c575b50505050509050919050565b7f000000000000000000000000ecf0bdb7b3f349abfd68c3563678124c5e8aaea381565b60065481565b6000806000806000610cc66116a3565b600e849055600f839055939992985090965094509092509050565b6000612710610cf6848463ffffffff611dd916565b1115610d49576040805162461bcd60e51b815260206004820152601760248201527f72657761726420706c7573207265626174652068696768000000000000000000604482015290519081900360640190fd5b610d618361091284600160801b63ffffffff611e3316565b9392505050565b6004546000906001600160a01b03163314610dbd576040805162461bcd60e51b815260206004820152601060248201526f37b7363c903230b7a7b832b930ba37b960811b604482015290519081900360640190fd5b6000610dc88b6108c7565b9050610e0c8c8c8c8c8c8c8c8c80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611e8c92505050565b600654610e2090600163ffffffff611dd916565b60068190556000828152600860209081526040822080546001818101835591845291909220018290559092508c6002811115610e5857fe5b1415610e74576000818152600d60205260409020829055610e9a565b60028c6002811115610e8257fe5b1415610e9a5760008181526010602052604090208290555b610ea2612877565b60405180606001604052808b81526020018a8152602001898152509050610ec76127f8565b6040805180820190915260008152602081018867ffffffffffffffff81118015610ef057600080fd5b50604051908082528060200260200182016040528015610f1a578160200160208202803683370190505b5081525090506040518061012001604052808f6002811115610f3857fe5b81526020016001151581526020018e81526020018d81526020017f000000000000000000000000dd974d5c2e2928dea5f71b9825b8b646686bd2006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fab57600080fd5b505afa158015610fbf573d6000803e3d6000fd5b505050506040513d6020811015610fd557600080fd5b50518152602081810185905260408051601f8a0183900483028101830182528981529201919089908990819084018382808284376000920191909152505050908252506040805160208b810282810182019093528b82529283019290918c918c9182918501908490808284376000920182905250938552505050602091820184905286815260079091526040902081518154829060ff1916600183600281111561107b57fe5b021790555060208281015182549015156101000261ff00199091161782556040808401516001840155606084015160028401556080840151600384015560a0840151805160048501558083015160058501550151600683015560c083015180516110eb9260078501920190612898565b5060e08201518051611107916008840191602090910190612916565b50610100820151805160098301908155602080830151805161112f92600a8701920190612916565b505050905050837fba908e34477602dcf3b8b10115cb9ba1f56c512e94a0beb561ad0245026cda138f8f8f8f8f8f8f8f8f8f604051808b600281111561117157fe5b60ff1681526020018a815260200189815260200188815260200187815260200186815260200180602001806020018381038352878782818152602001925060200280828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039e50909c50505050505050505050505050a25050509a9950505050505050505050565b7f000000000000000000000000dd974d5c2e2928dea5f71b9825b8b646686bd20081565b6004546001600160a01b031681565b60055481565b6000806112586112a0565b600c82905590939092509050565b600080611271610953565b905080831061128457600091505061091e565b61128e84846123a0565b949350505050565b600881565b600a81565b60008060006112ad610953565b9050600c5492506112ec60016112e06112d160005485611e3390919063ffffffff16565b6001549063ffffffff611dd916565b9063ffffffff611d5516565b9150806112f9575061134f565b6000600d8161130f84600163ffffffff611d5516565b81526020019081526020016000205490508060001415611331575061134f9050565b600061133c82611acc565b955090508061134b57600c5494505b5050505b9091565b61135d828261252e565b336000611368610953565b905060008060007f000000000000000000000000ecf0bdb7b3f349abfd68c3563678124c5e8aaea36001600160a01b031663b7a13c4c866040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050606060405180830381600087803b1580156113e757600080fd5b505af11580156113fb573d6000803e3d6000fd5b505050506040513d606081101561141157600080fd5b5080516020820151604090920151909450909250905060006001600160a01b03808316908716146114425782611452565b611452848463ffffffff611dd916565b6001600160a01b0387166000908152600b602090815260408083208c845282528083205460079092529091209192509060090181611545576001600160a01b0388166000908152600a602090815260408083208a845282528083208054600101905560099091529020546114cc908463ffffffff611dd916565b60008881526009602052604090205560018101805461150e9185916000198d019081106114f557fe5b9060005260206000200154611dd990919063ffffffff16565b8160010160018b038154811061152057fe5b600091825260209091200155805461153e908463ffffffff611dd916565b81556115d0565b8882146115d05761157b8382600101600185038154811061156257fe5b9060005260206000200154611d5590919063ffffffff16565b81600101600184038154811061158d57fe5b90600052602060002001819055506115b1838260010160018c03815481106114f557fe5b8160010160018b03815481106115c357fe5b6000918252602090912001555b6001600160a01b0388166000818152600b602090815260408083208e84528252918290208c905581518c815291518d938b9390927fc32b42768a47a585121e9b8d7a2ab9d3f34c326a192dee11ee1732e3d18313f392918290030190a450505050505050505050565b600080611644610953565b9050610d6183826123a0565b60015481565b60008061166e600160801b600163ffffffff611d5516565b83169050611687600160801b600163ffffffff611d5516565b61169b84600160801b63ffffffff611d9716565b169150915091565b60008060008060006116b3610953565b91506116d260016112e06112d160005486611e3390919063ffffffff16565b600e54600f5490955093509050811561173e5760006010816116fb85600163ffffffff611d5516565b81526020019081526020016000205490508060001461173c5760008061172083611acc565b909250905081156117395761173481611656565b975095505b50505b505b611754846112e06127108663ffffffff611d5516565b94509091929394565b600081815260076020818152604092839020805460018083015460028085015460038601546004870154600588015460068901549a890180548d516101009982161599909902600019011695909504601f81018b90048b0288018b01909c528b875260ff9097169a94999298919790969592946060948594929390919083018282801561182b5780601f106118005761010080835404028352916020019161182b565b820191906000526020600020905b81548152906001019060200180831161180e57829003601f168201915b505050505092508060080180548060200260200160405190810160405280929190818152602001828054801561188057602002820191906000526020600020905b81548152602001906001019080831161186c575b50505050509150509193959799909294969850565b336001600160a01b037f000000000000000000000000ecf0bdb7b3f349abfd68c3563678124c5e8aaea31614611912576040805162461bcd60e51b815260206004820152601560248201527f6f6e6c79207374616b696e6720636f6e74726163740000000000000000000000604482015290519081900360640190fd5b8061191c57611ac8565b6000611926610953565b6001600160a01b0384166000908152600a6020908152604080832084845290915290205490915080611959575050611ac8565b61198761196c828563ffffffff611e3316565b6000848152600960205260409020549063ffffffff611d5516565b60008381526009602090815260408083209390935560088152908290208054835181840281018401909452808452606093928301828280156119e857602002820191906000526020600020905b8154815260200190600101908083116119d4575b50939450600093505050505b8151811015611ac3576000828281518110611a0b57fe5b6020908102919091018101516001600160a01b0389166000908152600b83526040808220838352909352919091205490915080611a49575050611abb565b600082815260076020526040902060028101544211611ab7576009810154611a77908963ffffffff611d5516565b6009820155600a81018054611a96918a91600019860190811061156257fe5b600a820180546000198501908110611aaa57fe5b6000918252602090912001555b5050505b6001016119f4565b505050505b5050565b60008181526007602052604081208054829190610100900460ff16611af8575060009150819050611d4a565b4281600201541115611b11575060009150819050611d4a565b600381015480611b2a575060009250829150611d4a9050565b6009820154600a830180546040805160208084028201810190925282815260609390929091830182828015611b7e57602002820191906000526020600020905b815481526020019060010190808311611b6a575b5093945060009350839250829150505b8351811015611bfb5781848281518110611ba457fe5b60200260200101511115611bd357806001019250838181518110611bc457fe5b60200260200101519150611bf3565b81848281518110611be057fe5b60200260200101511415611bf357600092505b600101611b8e565b5081611c14575060009650869550611d4a945050505050565b611c1c612877565b506040805160608101825260048801548152600588015460208201526006880154918101919091526003870154600090611c689061090688670de0b6b3a764000063ffffffff611e3316565b90508082600001511115611c8b575060009850889750611d4a9650505050505050565b6000611cb0670de0b6b3a7640000610906848660400151611e3390919063ffffffff16565b905082602001518111611d1e576020830151600090611cd5908363ffffffff611d5516565b9050611ce7818963ffffffff611e3316565b611cff86670de0b6b3a764000063ffffffff611e3316565b1015611d1c575060009a508a9950611d4a98505050505050505050565b505b849a508860080160018c0381548110611d3357fe5b906000526020600020015499505050505050505050505b915091565b60005481565b6000610d6183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506126fc565b6000610d6183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612793565b600082820183811015610d61576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082611e425750600061091e565b82820282848281611e4f57fe5b0414610d615760405162461bcd60e51b8152600401808060200182810382526021815260200180612a4d6021913960400191505060405180910390fd5b42861015611ecb5760405162461bcd60e51b815260040180806020018281038252602181526020018061296b6021913960400191505060405180910390fd5b600554611edf90879063ffffffff611dd916565b611ef086600163ffffffff611dd916565b1015611f2d5760405162461bcd60e51b8152600401808060200182810382526028815260200180612acf6028913960400191505060405180910390fd5b6000611f38876108c7565b90506000611f45876108c7565b600083815260086020526040902054909150600a11611f955760405162461bcd60e51b815260040180806020018281038252602281526020018061298c6022913960400191505060405180910390fd5b808214611fd35760405162461bcd60e51b815260040180806020018281038252602a815260200180612a6e602a913960400191505060405180910390fd5b6000611fdd610953565b9050611ff081600163ffffffff611dd916565b83111561202e5760405162461bcd60e51b815260040180806020018281038252602f815260200180612baa602f913960400191505060405180910390fd5b8351600181118015612041575060088111155b61207c5760405162461bcd60e51b8152600401808060200182810382526029815260200180612b816029913960400191505060405180910390fd5b60008b600281111561208a57fe5b14156120fc5760005b85518110156120f65760008682815181106120aa57fe5b6020026020010151116120ee5760405162461bcd60e51b815260040180806020018281038252602c815260200180612af7602c913960400191505060405180910390fd5b600101612093565b5061229c565b60018b600281111561210a57fe5b14156121c5576000848152600d60205260409020541561215b5760405162461bcd60e51b815260040180806020018281038252603f8152602001806129ae603f913960400191505060405180910390fd5b60005b85518110156120f65760026127100486828151811061217957fe5b6020026020010151106121bd5760405162461bcd60e51b8152600401808060200182810382526038815260200180612b496038913960400191505060405180910390fd5b60010161215e565b600084815260106020526040902054156122105760405162461bcd60e51b8152600401808060200182810382526037815260200180612a986037913960400191505060405180910390fd5b60005b855181101561229a5760008061223b88848151811061222e57fe5b6020026020010151611656565b9092509050612710612253828463ffffffff611dd916565b11156122905760405162461bcd60e51b81526004018080602001828103825260388152602001806129ed6038913960400191505060405180910390fd5b5050600101612213565b505b670de0b6b3a76400008811156122e35760405162461bcd60e51b8152600401808060200182810382526026815260200180612b236026913960400191505060405180910390fd5b600160801b871061233b576040805162461bcd60e51b815260206004820152601960248201527f76616c6964617465506172616d733a2063206973206869676800000000000000604482015290519081900360640190fd5b600160801b8610612393576040805162461bcd60e51b815260206004820152601960248201527f76616c6964617465506172616d733a2074206973206869676800000000000000604482015290519081900360640190fd5b5050505050505050505050565b6001600160a01b0382166000908152600a60209081526040808320848452909152812054806123d357600091505061091e565b60008060007f000000000000000000000000ecf0bdb7b3f349abfd68c3563678124c5e8aaea36001600160a01b03166316554d6288886040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060606040518083038186803b15801561245657600080fd5b505afa15801561246a573d6000803e3d6000fd5b505050506040513d606081101561248057600080fd5b5080516020820151604090920151909450909250905060006001600160a01b03808316908916146124b157826124c1565b6124c1848463ffffffff611dd916565b9050806124d65760009550505050505061091e565b60006124e8868363ffffffff611e3316565b6000898152600960205260409020549091508082111561250457fe5b6125208161090684670de0b6b3a764000063ffffffff611e3316565b9a9950505050505050505050565b60008281526007602052604090208054610100900460ff16612597576040805162461bcd60e51b815260206004820152601c60248201527f766f74653a2063616d706169676e20646f65736e277420657869737400000000604482015290519081900360640190fd5b42816001015411156125f0576040805162461bcd60e51b815260206004820152601a60248201527f766f74653a2063616d706169676e206e6f742073746172746564000000000000604482015290519081900360640190fd5b4281600201541015612649576040805162461bcd60e51b815260206004820152601c60248201527f766f74653a2063616d706169676e20616c726561647920656e64656400000000604482015290519081900360640190fd5b6000821161269e576040805162461bcd60e51b815260206004820152601160248201527f766f74653a206f7074696f6e2069732030000000000000000000000000000000604482015290519081900360640190fd5b60088101548211156126f7576040805162461bcd60e51b815260206004820152601c60248201527f766f74653a206f7074696f6e206973206e6f7420696e2072616e676500000000604482015290519081900360640190fd5b505050565b6000818484111561278b5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612750578181015183820152602001612738565b50505050905090810190601f16801561277d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600081836127e25760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612750578181015183820152602001612738565b5060008385816127ee57fe5b0495945050505050565b604051806040016040528060008152602001606081525090565b50805460018160011615610100020316600290046000825580601f106128385750612856565b601f0160209004906000526020600020908101906128569190612950565b50565b50805460008255906000526020600020908101906128569190612950565b60405180606001604052806000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106128d957805160ff1916838001178555612906565b82800160010185558215612906579182015b828111156129065782518255916020019190600101906128eb565b50612912929150612950565b5090565b82805482825590600052602060002090810192821561290657916020028201828111156129065782518255916020019190600101906128eb565b61096191905b80821115612912576000815560010161295656fe76616c6964617465506172616d733a20737461727420696e20746865207061737476616c6964617465506172616d733a20746f6f206d616e792063616d706169676e7376616c6964617465506172616d733a20616c726561647920686164206e6574776f726b206665652063616d706169676e20666f7220746869732065706f636876616c6964617465506172616d733a20726562617465202b207265776172642063616e277420626520626967676572207468616e2042505363616e63656c43616d706169676e3a2063616d706169676e20616c72656164792073746172746564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7776616c6964617465506172616d733a207374617274202620656e64206e6f742073616d652065706f636876616c6964617465506172616d733a20616c726561647920686164206272722063616d706169676e20666f7220746869732065706f636876616c6964617465506172616d733a2063616d706169676e206475726174696f6e206973206c6f7776616c6964617465506172616d733a2067656e6572616c2063616d706169676e206f7074696f6e206973203076616c6964617465506172616d733a206d696e2070657263656e74616765206973206869676876616c6964617465506172616d733a206e6574776f726b20666565206d75737420626520736d616c6c6572207468656e20425053202f203276616c6964617465506172616d733a20696e76616c6964206e756d626572206f66206f7074696f6e7376616c6964617465506172616d733a206f6e6c7920666f722063757272656e74206f72206e6578742065706f63687363616e63656c43616d706169676e3a2063616d706169676e494420646f65736e2774206578697374a2646970667358221220313c6142437875dcaf3f6546db75663d187e82ca7247be8fa4039cdd632f8a2864736f6c63430006060033

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

0000000000000000000000000000000000000000000000000000000000127500000000000000000000000000000000000000000000000000000000005F0D599B000000000000000000000000dd974d5c2e2928dea5f71b9825b8b646686bd200000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000019640000000000000000000000000000000000000000000000000000000000000bb8000000000000000000000000e6a7338cba0a1070adfb22c07115299605454713

-----Decoded View---------------
Arg [0] : _epochPeriod (uint256): 1209600
Arg [1] : _startTimestamp (uint256): 1594710427
Arg [2] : _knc (address): 0xdd974D5C2e2928deA5F71b9825b8b646686BD200
Arg [3] : _defaultNetworkFeeBps (uint256): 20
Arg [4] : _defaultRewardBps (uint256): 6500
Arg [5] : _defaultRebateBps (uint256): 3000
Arg [6] : _daoOperator (address): 0xE6A7338cba0A1070AdfB22c07115299605454713

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000127500
Arg [1] : 000000000000000000000000000000000000000000000000000000005F0D599B
Arg [2] : 000000000000000000000000dd974d5c2e2928dea5f71b9825b8b646686bd200
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [4] : 0000000000000000000000000000000000000000000000000000000000001964
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000bb8
Arg [6] : 000000000000000000000000e6a7338cba0a1070adfb22c07115299605454713


Deployed Bytecode Sourcemap

37530:28781:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;37530:28781:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;9;2:12;40029:47:0;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;40029:47:0;;:::i;:::-;;;;;;;;;;;;;;;;53343:350;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;53343:350:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;53343:350:0;;;;;;;;;;;;;;;;;;52215:125;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;52215:125:0;;:::i;39653:72::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;39653:72:0;;;;;;;;:::i;6357:381::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;6357:381:0;;:::i;39493:66::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;39493:66:0;;;;;;;;:::i;39834:54::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;39834:54:0;;:::i;6232:117::-;;;:::i;47280:1111::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;47280:1111:0;;:::i;:::-;;51671:266;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;51671:266:0;;:::i;:::-;;;;;;;;;;;;;;;;;;52016:150;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;52016:150:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;52016:150:0;;;;;;;;;;;;;;;;;38916:38;;;:::i;:::-;;;;-1:-1:-1;;;;;38916:38:0;;;;;;;;;;;;;;39010:34;;;:::i;50980:474::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60410:312;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;60410:312:0;;;;;;;:::i;44641:2418::-;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;44641:2418:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:11:-1;11:28;;8:2;;;52:1;49;42:12;8:2;44641:2418:0;;41:9:-1;34:4;18:14;14:25;11:40;8:2;;;64:1;61;54:12;8:2;44641:2418:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;44641:2418:0;;;;;;;;;;;27:11:-1;11:28;;8:2;;;52:1;49;42:12;8:2;44641:2418:0;;41:9:-1;34:4;18:14;14:25;11:40;8:2;;;64:1;61;54:12;8:2;44641:2418:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;44641:2418:0;;-1:-1:-1;44641:2418:0;-1:-1:-1;44641:2418:0;:::i;38877:32::-;;;:::i;6848:26::-;;;:::i;38818:52::-;;;:::i;50485:294::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;53946:404;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;53946:404:0;;;;;;;;:::i;37770:50::-;;;:::i;37665:::-;;;:::i;57599:1068::-;;;:::i;48627:1683::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;48627:1683:0;;;;;;;:::i;54459:277::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;54459:277:0;-1:-1:-1;;;;;54459:277:0;;:::i;6175:48::-;;;:::i;60013:270::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;60013:270:0;;:::i;58764:1197::-;;;:::i;52348:987::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;52348:987:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;52348:987:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;52348:987:0;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;52348:987:0;;;;;;;;;;;;;;;;;;;;;;;;;;42246:1700;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;42246:1700:0;;;;;;;;:::i;55068:2445::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;55068:2445:0;;:::i;6124:44::-;;;:::i;40029:47::-;;;;;;;;;;;;;:::o;53343:350::-;53447:27;53476:22;53516:32;;:::i;:::-;53551:12;:24;53564:10;53551:24;;;;;;;;;;;:41;;53516:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;53516:76:0;;;;-1:-1:-1;;53620:19:0;;53663:22;;;;;;53620:19;;-1:-1:-1;53343:350:0;;-1:-1:-1;;;;53343:350:0:o;52215:125::-;52282:7;52309:23;;;:16;:23;;;;;;52215:125;;;;:::o;39653:72::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;6357:381::-;6430:7;6466:24;;6454:9;:36;:65;;;-1:-1:-1;6494:20:0;;:25;6454:65;6450:106;;;-1:-1:-1;6543:1:0;6536:8;;6450:106;6654:76;6728:1;6655:67;6701:20;;6656:39;6670:24;;6656:9;:13;;:39;;;;:::i;:::-;6655:45;:67;:45;:67;:::i;:::-;6654:73;:76;:73;:76;:::i;:::-;6647:83;6357:381;-1:-1:-1;;6357:381:0:o;39493:66::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;39834:54::-;;;;;;;;;;;;;:::o;6232:117::-;6295:7;6322:19;6337:3;6322:14;:19::i;:::-;6315:26;;6232:117;;:::o;47280:1111::-;7103:11;;-1:-1:-1;;;;;7103:11:0;7089:10;:25;7081:54;;;;;-1:-1:-1;;;7081:54:0;;;;;;;;;;;;-1:-1:-1;;;7081:54:0;;;;;;;;;;;;;;;47360:25:::1;47388:24:::0;;;:12:::1;:24;::::0;;;;47431:23;;::::1;::::0;::::1;;;47423:76;;;;-1:-1:-1::0;;;47423:76:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47546:3;47520:8;:23;;;:29;47512:82;;;;-1:-1:-1::0;;;47512:82:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47607:13;47623:39;47638:8;:23;;;47623:14;:39::i;:::-;47607:55:::0;-1:-1:-1;47704:23:0::1;47679:21:::0;;::::1;;:48;::::0;::::1;;;;;;;47675:230;;;47751:26;::::0;;;:19:::1;:26;::::0;;;;47744:33;47675:230:::1;;;47824:26;47799:21:::0;;::::1;;:51;::::0;::::1;;;;;;;47795:110;;;47874:19;::::0;;;:12:::1;:19;::::0;;;;47867:26;47795:110:::1;47924:24;::::0;;;:12:::1;:24;::::0;;;;;;47917:31;;-1:-1:-1;;47917:31:0;;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;;::::1;::::0;::::1;::::0;;;::::1;::::0;::::1;::::0;;;;;;;;;;;;;;;47924:24;;47917:31:::1;::::0;;::::1;47924:24:::0;47917:31:::1;:::i;:::-;;;::::0;::::1;;;:::i;:::-;;;::::0;::::1;::::0;;;;::::1;::::0;;;;::::1;:::i;:::-;-1:-1:-1::0;;;47961:29:0::1;47993:21:::0;;;:14:::1;:21;::::0;;;;;-1:-1:-1;48025:312:0::1;48049:18:::0;;48045:22;::::1;48025:312;;;48111:10;48093:11;48105:1;48093:14;;;;;;;;;;;;;;;;:28;48089:237;;;48227:18:::0;;48215:11;;-1:-1:-1;;48227:22:0;;;48215:35;::::1;;;;;;;;;;;;;48198:11;48210:1;48198:14;;;;;;;;;;;;;;;:52;;;;48269:11;:17;;;;;;;;;;;;;;;;;;;;;;;;48305:5;;48089:237;48069:3;;48025:312;;;-1:-1:-1::0;48354:29:0::1;::::0;48372:10;;48354:29:::1;::::0;;;::::1;7146:1;;;47280:1111:::0;:::o;51671:266::-;51752:4;51769:16;51788:23;:21;:23::i;:::-;51769:42;;51835:8;51826:5;:17;51822:62;;51867:5;51860:12;;;;;51822:62;-1:-1:-1;;51901:23:0;;;;:16;:23;;;;;;:28;;51671:266::o;52016:150::-;52137:21;;;;:14;:21;;;;;;;;;52123:35;;;;;;;;;;;;;;;;;52082:28;;52123:35;;;52137:21;52123:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52016:150;;;:::o;38916:38::-;;;:::o;39010:34::-;;;;:::o;50980:474::-;51085:17;51117:19;51151;51185:13;51213:23;51328:18;:16;:18::i;:::-;51357:13;:39;;;51407:25;:39;;;51264:82;;;;-1:-1:-1;51264:82:0;;-1:-1:-1;51264:82:0;-1:-1:-1;51264:82:0;;-1:-1:-1;50980:474:0;-1:-1:-1;50980:474:0:o;60410:312::-;60550:12;32102:5;60588:28;:11;60604;60588:28;:15;:28;:::i;:::-;:35;;60580:71;;;;;-1:-1:-1;;;60580:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;60669:45;60702:11;60670:26;:11;-1:-1:-1;;;60670:26:0;:15;:26;:::i;60669:45::-;60662:52;60410:312;-1:-1:-1;;;60410:312:0:o;44641:2418::-;7103:11;;44981:18;;-1:-1:-1;;;;;7103:11:0;7089:10;:25;7081:54;;;;;-1:-1:-1;;;7081:54:0;;;;;;;;;;;;-1:-1:-1;;;7081:54:0;;;;;;;;;;;;;;;45142:21:::1;45166:30;45181:14;45166;:30::i;:::-;45142:54;;45209:231;45246:12;45273:14;45302:12;45329:24;45368:12;45395;45422:7;;45209:231;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16:::0;::::1;74:27:::0;;;;-1:-1;45209:22:0::1;::::0;-1:-1:-1;;;45209:231:0:i:1;:::-;45471:15;::::0;:22:::1;::::0;45491:1:::1;45471:22;:19;:22;:::i;:::-;45453:15;:40:::0;;;45599:29:::1;::::0;;;:14:::1;:29;::::0;;;;;;27:10:-1;;39:1:::1;23:18:::0;;::::1;45:23:::0;;45599:46:0;;;;;;;::::1;::::0;;;45453:40;;-1:-1:-1;45720:12:0::1;:39;;;;;;;;;45716:240;;;45776:34;::::0;;;:19:::1;:34;::::0;;;;:47;;;45716:240:::1;;;45861:26;45845:12;:42;;;;;;;;;45841:115;;;45904:27;::::0;;;:12:::1;:27;::::0;;;;:40;;;45841:115:::1;45968:30;;:::i;:::-;46001:171;;;;;;;;46054:24;46001:171;;;;46107:12;46001:171;;;;46148:12;46001:171;;::::0;45968:204:::1;;46183:40;;:::i;:::-;46226:116;::::0;;;;::::1;::::0;;;-1:-1:-1;46226:116:0;;::::1;::::0;::::1;46315:7:::0;46301:29:::1;::::0;::::1;2:2:-1::0;::::1;;;27:1;24::::0;17:12:::1;2:2;46301:29:0;;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;125:4;109:14;101:6;88:42;144:17;::::0;-1:-1;46301:29:0::1;;46226:116;;::::0;46183:159:::1;;46382:380;;;;;;;;46455:12;46382:380;;;;;;;;;;;;46422:4;46382:380;;;;;;46498:14;46382:380;;;;46541:12;46382:380;;;;46584:8;-1:-1:-1::0;;;;;46584:20:0::1;;:22;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;46584:22:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;46584:22:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28::::0;21:12:::1;4:2;-1:-1:::0;46584:22:0;46382:380;;46584:22:::1;46382:380:::0;;::::1;::::0;;;;;;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;;;;;46627:4;;;;;;46382:380;::::1;46627:4:::0;;;;46382:380;1:33:-1::1;99:1;81:16:::0;::::1;74:27:::0;;;;-1:-1;;;46382:380:0;;;-1:-1:-1;46382:380:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;::::1;::::0;;;46694:7;;;;;;46382:380;::::1;::::0;46694:7;;46382:380;46694:7;46382:380;1:33:-1::1;99:1;81:16:::0;::::1;74:27:::0;;;-1:-1;46382:380:0;;;-1:-1:-1;;;46382:380:0::1;::::0;;::::1;::::0;;;46355:24;;;:12:::1;:24:::0;;;;;;:407;;;;:24;;-1:-1:-1;;46355:407:0::1;::::0;;::::1;::::0;::::1;;;;;;;;::::0;;-1:-1:-1;46355:407:0::1;::::0;;::::1;::::0;;;;::::1;;;;-1:-1:-1::0;;46355:407:0;;::::1;;::::0;;::::1;::::0;;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;;;;::::1;::::0;;;;;::::1;::::0;::::1;::::0;;;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;:::i;:::-;-1:-1:-1::0;46355:407:0::1;::::0;::::1;::::0;;;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;:::i;:::-;-1:-1:-1::0;46355:407:0::1;::::0;::::1;::::0;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;;;::::1;::::0;::::1;:::i;:::-;;;;;;;46840:10;46780:271;46813:12;46865:14;46894:12;46921:24;46960:12;46987;47014:7;;47036:4;;46780:271;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16:::0;;::::1;74:27:::0;137:4:::1;117:14;-1:-1:::0;;113:30:::1;157:16:::0;;::::1;46780:271:0::0;;::::1;::::0;;;;;::::1;;::::0;-1:-1:-1;46780:271:0;;;;;1:33:-1::1;99:1;81:16:::0;;::::1;74:27:::0;46780:271:0::1;::::0;137:4:-1::1;117:14:::0;;::::1;-1:-1:::0;;113:30:::1;157:16:::0;;::::1;46780:271:0::0;;::::1;::::0;-1:-1:-1;46780:271:0;;-1:-1:-1;;;;;;;;;;;;;46780:271:0::1;7146:1;;;44641:2418:::0;;;;;;;;;;;;:::o;38877:32::-;;;:::o;6848:26::-;;;-1:-1:-1;;;;;6848:26:0;;:::o;38818:52::-;;;;:::o;50485:294::-;50583:16;50601:23;50672:25;:23;:25::i;:::-;50738:22;:33;;;50642:55;;;;-1:-1:-1;50485:294:0;-1:-1:-1;50485:294:0:o;53946:404::-;54094:7;54167:16;54186:23;:21;:23::i;:::-;54167:42;;54233:8;54224:5;:17;54220:58;;54265:1;54258:8;;;;;54220:58;54297:45;54328:6;54336:5;54297:30;:45::i;:::-;54290:52;53946:404;-1:-1:-1;;;;53946:404:0:o;37770:50::-;37819:1;37770:50;:::o;37665:::-;37713:2;37665:50;:::o;57599:1068::-;57700:16;57718:23;57759:16;57778:23;:21;:23::i;:::-;57759:42;;57823:22;;57812:33;;57968:71;58037:1;57968:64;57997:34;58010:20;;57997:8;:12;;:34;;;;:::i;:::-;57968:24;;;:64;:28;:64;:::i;:::-;:68;:71;:68;:71;:::i;:::-;57950:89;-1:-1:-1;58054:13:0;58050:80;;-1:-1:-1;58084:34:0;;58050:80;58140:18;58161:19;58140:18;58181:15;:8;58194:1;58181:15;:12;:15;:::i;:::-;58161:36;;;;;;;;;;;;58140:57;;58212:10;58226:1;58212:15;58208:152;;;-1:-1:-1;58314:34:0;;-1:-1:-1;58314:34:0;58208:152;58372:21;58432:44;58465:10;58432:32;:44::i;:::-;58404:72;-1:-1:-1;58404:72:0;-1:-1:-1;58491:18:0;58487:128;;58581:22;;58570:33;;58487:128;-1:-1:-1;;;57599:1068:0;;;:::o;48627:1683::-;48706:38;48725:10;48737:6;48706:18;:38::i;:::-;48772:10;48755:14;48814:23;:21;:23::i;:::-;48795:42;;48849:13;48864:14;48880:22;48919:7;-1:-1:-1;;;;;48919:46:0;;48966:6;48919:54;;;;;;;;;;;;;-1:-1:-1;;;;;48919:54:0;-1:-1:-1;;;;;48919:54:0;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;48919:54:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;48919:54:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;48919:54:0;;;;;;;;;;;;;-1:-1:-1;48919:54:0;;-1:-1:-1;48919:54:0;-1:-1:-1;48986:18:0;-1:-1:-1;;;;;49007:24:0;;;;;;;:53;;49054:6;49007:53;;;49034:17;:5;49044:6;49034:17;:9;:17;:::i;:::-;-1:-1:-1;;;;;49097:25:0;;49071:23;49097:25;;;:17;:25;;;;;;;;:37;;;;;;;;;49183:12;:24;;;;;;48986:74;;-1:-1:-1;49097:37:0;49183:41;;49241:20;49237:946;;-1:-1:-1;;;;;49367:19:0;;;;;;:11;:19;;;;;;;;:29;;;;;;;;:31;;;;;;49444:16;:26;;;;;;:42;;49475:10;49444:42;:30;:42;:::i;:::-;49415:26;;;;:16;:26;;;;;:71;49608:22;;;:34;;:50;;49647:10;;-1:-1:-1;;49631:10:0;;;49608:34;;;;;;;;;;;;;;:38;;:50;;;;:::i;:::-;49554:8;:22;;49586:1;49577:6;:10;49554:34;;;;;;;;;;;;;;;;;:104;49732:19;;:35;;49756:10;49732:35;:23;:35;:::i;:::-;49710:57;;49237:946;;;49808:6;49789:15;:25;49785:398;;49945:59;49993:10;49945:8;:22;;49986:1;49968:15;:19;49945:43;;;;;;;;;;;;;;;;:47;;:59;;;;:::i;:::-;49882:8;:22;;49923:1;49905:15;:19;49882:43;;;;;;;;;;;;;;;:122;;;;50121:50;50160:10;50121:8;:22;;50153:1;50144:6;:10;50121:34;;;;;;;:50;50067:8;:22;;50099:1;50090:6;:10;50067:34;;;;;;;;;;;;;;;;;:104;49785:398;-1:-1:-1;;;;;50195:25:0;;;;;;:17;:25;;;;;;;;:37;;;;;;;;;:46;;;50259:43;;;;;;;50221:10;;50273:8;;50195:25;;50259:43;;;;;;;;;48627:1683;;;;;;;;;;:::o;54459:277::-;54595:7;54620:16;54639:23;:21;:23::i;:::-;54620:42;;54680:48;54711:6;54719:8;54680:30;:48::i;6175:::-;;;;:::o;60013:270::-;60111:19;;60191:16;-1:-1:-1;;;60205:1:0;60191:16;:13;:16;:::i;:::-;60183:25;;;-1:-1:-1;60258:16:0;-1:-1:-1;;;60272:1:0;60258:16;:13;:16;:::i;:::-;60234:19;:4;-1:-1:-1;;;60234:19:0;:8;:19;:::i;:::-;60233:42;60219:56;;60013:270;;;:::o;58764:1197::-;58854:17;58886:19;58920;58954:13;58982:23;59041;:21;:23::i;:::-;59033:31;;59184:68;59250:1;59184:61;59213:31;59223:20;;59213:5;:9;;:31;;;;:::i;59184:68::-;59277:13;:25;59327;;59277;;-1:-1:-1;59327:25:0;-1:-1:-1;59166:86:0;-1:-1:-1;59369:9:0;;59365:527;;59395:18;59416:12;59395:18;59429:12;:5;59439:1;59429:12;:9;:12;:::i;:::-;59416:26;;;;;;;;;;;;59395:47;;59461:10;59475:1;59461:15;59457:424;;59497:21;59537:15;59598:44;59631:10;59598:32;:44::i;:::-;59571:71;;-1:-1:-1;59571:71:0;-1:-1:-1;59665:17:0;;59661:205;;59811:35;59838:7;59811:26;:35::i;:::-;59782:64;-1:-1:-1;59782:64:0;-1:-1:-1;59661:205:0;59457:424;;;59365:527;;59916:37;59941:11;59916:20;32102:5;59924:11;59916:20;:7;:20;:::i;:37::-;59904:49;;58764:1197;;;;;:::o;52348:987::-;52460:25;52838:24;;;:12;:24;;;;;;;;;52888:21;;;52937:23;;;;52986:21;;;;;53035:23;;;;53096:20;;;:45;53167:33;;;;53226;;;;53277:13;;;53270:20;;;;52888:21;53270:20;;;;;;;;-1:-1:-1;;53270:20:0;;;;;;;;;;;;;;;;;;;;;;;;52888:21;;;;;52937:23;;52986:21;;53035:23;;53096:45;;53167:33;53226;;52726:17;;;;52838:24;;53277:13;;53270:20;;;53277:13;53270:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53311:8;:16;;53301:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52348:987;;;;;;;;;;;;:::o;42246:1700::-;41905:10;-1:-1:-1;;;;;41927:7:0;41905:30;;41897:64;;;;;-1:-1:-1;;;41897:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;42431:17;42427:56:::1;;42465:7;;42427:56;42493:16;42512:23;:21;:23::i;:::-;-1:-1:-1::0;;;;;42567:19:0;::::1;42548:16;42567:19:::0;;;:11:::1;:19;::::0;;;;;;;:29;;;;;;;;;42493:42;;-1:-1:-1;42689:13:0;42685:52:::1;;42719:7;;;;42685:52;42828:58;42859:26;:8:::0;42872:12;42859:26:::1;:12;:26;:::i;:::-;42828;::::0;;;:16:::1;:26;::::0;;;;;;:58:::1;:30;:58;:::i;:::-;42799:26;::::0;;;:16:::1;:26;::::0;;;;;;;:87;;;;42996:14:::1;:24:::0;;;;;;42965:55;;;;;;::::1;::::0;;;;;;;;;;:28:::1;::::0;:55;;::::1;42996:24:::0;42965:55;;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;42965:55:0;;-1:-1:-1;43038:9:0::1;::::0;-1:-1:-1;;;;43033:906:0::1;43057:11;:18;43053:1;:22;43033:906;;;43097:18;43118:11;43130:1;43118:14;;;;;;;;;::::0;;::::1;::::0;;;;;;;-1:-1:-1;;;;;43171:25:0;::::1;43149:19;43171:25:::0;;;:17:::1;:25:::0;;;;;;:37;;;;;;;;;;;43118:14;;-1:-1:-1;43227:16:0;43223:65:::1;;43264:8;;;;43223:65;43332:25;43360:24:::0;;;:12:::1;:24;::::0;;;;43403:21:::1;::::0;::::1;::::0;43428:3:::1;-1:-1:-1::0;43399:529:0::1;;43685:25;::::0;::::1;:36:::0;:54:::1;::::0;43726:12;43685:54:::1;:40;:54;:::i;:::-;43625:25;::::0;::::1;:114:::0;43838:39;;;:56;;:74:::1;::::0;43899:12;;-1:-1:-1;;43878:15:0;;;43838:56;::::1;;;;:74;43758:39:::0;;;:56;;-1:-1:-1;;43798:15:0;;;43758:56;::::1;;;;;;::::0;;;::::1;::::0;;;::::1;:154:::0;43399:529:::1;43033:906;;;;43077:3;;43033:906;;;;41972:1;;;;42246:1700:::0;;:::o;55068:2445::-;55178:16;55255:24;;;:12;:24;;;;;55295:23;;55178:16;;55255:24;55295:23;;;;;55290:70;;-1:-1:-1;55343:1:0;;-1:-1:-1;55343:1:0;;-1:-1:-1;55335:13:0;;55290:70;55480:3;55456:8;:21;;;:27;55452:73;;;-1:-1:-1;55508:1:0;;-1:-1:-1;55508:1:0;;-1:-1:-1;55500:13:0;;55452:73;55559:23;;;;55666:16;55662:62;;-1:-1:-1;55707:1:0;;-1:-1:-1;55707:1:0;;-1:-1:-1;55699:13:0;;-1:-1:-1;55699:13:0;55662:62;55757:25;;;:36;55834:39;;;55804:69;;;;;;;;;;;;;;;;;;;:27;;:69;;55834:39;;55804:69;;55834:39;55804:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;55804:69:0;;-1:-1:-1;55929:21:0;;-1:-1:-1;55929:21:0;;-1:-1:-1;55929:21:0;;-1:-1:-1;;56001:307:0;56025:10;:17;56021:1;:21;56001:307;;;56084:13;56068:10;56079:1;56068:13;;;;;;;;;;;;;;:29;56064:233;;;56134:1;56138;56134:5;56118:21;;56174:10;56185:1;56174:13;;;;;;;;;;;;;;56158:29;;56064:233;;;56230:13;56213:10;56224:1;56213:13;;;;;;;;;;;;;;:30;56209:88;;;56280:1;56264:17;;56209:88;56044:3;;56001:307;;;-1:-1:-1;56377:18:0;56373:64;;-1:-1:-1;56420:1:0;;-1:-1:-1;56420:1:0;;-1:-1:-1;56412:13:0;;-1:-1:-1;;;;;56412:13:0;56373:64;56449:30;;:::i;:::-;-1:-1:-1;56449:53:0;;;;;;;;56482:20;;;56449:53;;;;;;;;;;;;;;;;;;;;;;56623:23;;;;-1:-1:-1;;56593:54:0;;:25;:10;31809:6;56593:25;:14;:25;:::i;:54::-;56567:80;;56792:15;56753:11;:36;;;:54;56749:100;;;-1:-1:-1;56832:1:0;;-1:-1:-1;56832:1:0;;-1:-1:-1;56824:13:0;;-1:-1:-1;;;;;;;56824:13:0;56749:100;56945:9;56957:60;31809:6;56957:45;56986:15;56957:11;:24;;;:28;;:45;;;;:::i;:60::-;56945:72;;57037:11;:24;;;57032:1;:29;57028:392;;57166:24;;;;57154:9;;57166:31;;57195:1;57166:31;:28;:31;:::i;:::-;57154:43;-1:-1:-1;57342:17:0;57154:43;57348:10;57342:17;:5;:17;:::i;:::-;57311:28;:13;31809:6;57311:28;:17;:28;:::i;:::-;:48;57307:102;;;-1:-1:-1;57388:1:0;;-1:-1:-1;57388:1:0;;-1:-1:-1;57380:13:0;;-1:-1:-1;;;;;;;;;57380:13:0;57307:102;57028:392;;57443:13;57432:24;;57475:8;:16;;57503:1;57492:8;:12;57475:30;;;;;;;;;;;;;;;;57467:38;;55068:2445;;;;;;;;;;;;;:::o;6124:44::-;;;;:::o;1369:136::-;1427:7;1454:43;1458:1;1461;1454:43;;;;;;;;;;;;;;;;;:3;:43::i;3182:132::-;3240:7;3267:39;3271:1;3274;3267:39;;;;;;;;;;;;;;;;;:3;:39::i;913:181::-;971:7;1003:5;;;1027:6;;;;1019:46;;;;;-1:-1:-1;;;1019:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;2243:471;2301:7;2546:6;2542:47;;-1:-1:-1;2576:1:0;2569:8;;2542:47;2613:5;;;2617:1;2613;:5;:1;2637:5;;;;;:10;2629:56;;;;-1:-1:-1;;;2629:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61483:3767;61864:3;61846:14;:21;;61838:67;;;;-1:-1:-1;;;61838:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62128:28;;62109:48;;:14;;:48;:18;:48;:::i;:::-;62086:19;:12;62103:1;62086:19;:16;:19;:::i;:::-;:71;;62064:161;;;;-1:-1:-1;;;62064:161:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62238:18;62259:30;62274:14;62259;:30::i;:::-;62238:51;;62300:16;62319:28;62334:12;62319:14;:28::i;:::-;62382:26;;;;:14;:26;;;;;:33;62300:47;;-1:-1:-1;37713:2:0;-1:-1:-1;62360:139:0;;;;-1:-1:-1;;;62360:139:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62606:8;62592:10;:22;62584:77;;;;-1:-1:-1;;;62584:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62674:20;62697:23;:21;:23::i;:::-;62674:46;-1:-1:-1;62767:19:0;62674:46;62784:1;62767:19;:16;:19;:::i;:::-;62753:10;:33;;62731:130;;;;-1:-1:-1;;;62731:130:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62932:14;;62992:1;62979:14;;:52;;;;;37819:1;62997:10;:34;;62979:52;62957:143;;;;-1:-1:-1;;;62957:143:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63191:20;63175:12;:36;;;;;;;;;63171:1708;;;63280:9;63275:151;63299:7;:14;63295:1;:18;63275:151;;;63360:1;63347:7;63355:1;63347:10;;;;;;;;;;;;;;:14;63339:71;;;;-1:-1:-1;;;63339:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63315:3;;63275:151;;;;63171:1708;;;63463:23;63447:12;:39;;;;;;;;;63443:1436;;;63529:31;;;;:19;:31;;;;;;:36;63503:161;;;;-1:-1:-1;;;63503:161:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63748:9;63743:397;63767:7;:14;63763:1;:18;63743:397;;;64023:1;32102:5;64017:7;64004;64012:1;64004:10;;;;;;;;;;;;;;:20;63974:150;;;;-1:-1:-1;;;63974:150:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63783:3;;63743:397;;63443:1436;64198:24;;;;:12;:24;;;;;;:29;64172:146;;;;-1:-1:-1;;;64172:146:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;64426:9;64421:447;64445:7;:14;64441:1;:18;64421:447;;;64565:19;64586;64630:38;64657:7;64665:1;64657:10;;;;;;;;;;;;;;64630:26;:38::i;:::-;64564:104;;-1:-1:-1;64564:104:0;-1:-1:-1;32102:5:0;64717:28;64564:104;;64717:28;:15;:28;:::i;:::-;:35;;64687:165;;;;-1:-1:-1;;;64687:165:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;64461:3:0;;64421:447;;;;63443:1436;31809:6;64959:24;:37;;64951:88;;;;-1:-1:-1;;;64951:88:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;65113:12:0;:24;65105:62;;;;;-1:-1:-1;;;65105:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;65188:12:0;:24;65180:62;;;;;-1:-1:-1;;;65180:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;61483:3767;;;;;;;;;;;:::o;65454:854::-;-1:-1:-1;;;;;65619:19:0;;65575:7;65619:19;;;:11;:19;;;;;;;;:26;;;;;;;;;65693:13;65689:54;;65730:1;65723:8;;;;;65689:54;65756:13;65771:22;65795;65834:7;-1:-1:-1;;;;;65834:24:0;;65859:6;65867:5;65834:39;;;;;;;;;;;;;-1:-1:-1;;;;;65834:39:0;-1:-1:-1;;;;;65834:39:0;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;65834:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;65834:39:0;;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;65834:39:0;;;;;;;;;;;;;-1:-1:-1;65834:39:0;;-1:-1:-1;65834:39:0;-1:-1:-1;65886:18:0;-1:-1:-1;;;;;65907:24:0;;;;;;;:69;;65962:14;65907:69;;;65934:25;:5;65944:14;65934:25;:9;:25;:::i;:::-;65886:90;-1:-1:-1;65991:15:0;65987:56;;66030:1;66023:8;;;;;;;;;65987:56;66055:14;66072:24;:8;66085:10;66072:24;:12;:24;:::i;:::-;66107:16;66126:23;;;:16;:23;;;;;;66055:41;;-1:-1:-1;66226:18:0;;;;66219:26;;;;66265:35;66291:8;66265:21;:6;31809;66265:21;:10;:21;:::i;:35::-;66258:42;65454:854;-1:-1:-1;;;;;;;;;;65454:854:0:o;60788:579::-;60877:25;60905:24;;;:12;:24;;;;;60948:23;;;;;;;60940:64;;;;;-1:-1:-1;;;60940:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;61052:3;61025:8;:23;;;:30;;61017:69;;;;;-1:-1:-1;;;61017:69:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;61130:3;61105:8;:21;;;:28;;61097:69;;;;;-1:-1:-1;;;61097:69:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;61251:1;61242:6;:10;61234:40;;;;;-1:-1:-1;;;61234:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;61303:16;;;:23;61293:33;;;61285:74;;;;;-1:-1:-1;;;61285:74:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;60788:579;;;:::o;1800:192::-;1886:7;1922:12;1914:6;;;;1906:29;;;;-1:-1:-1;;;1906:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;1906:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1958:5:0;;;1800:192::o;3802:345::-;3888:7;3990:12;3983:5;3975:28;;;;-1:-1:-1;;;3975:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;3975:28:0;;4014:9;4030:1;4026;:5;;;;;;;3802:345;-1:-1:-1;;;;;3802:345:0:o;37530:28781::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;37530:28781:0;;;-1:-1:-1;37530:28781:0;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Swarm Source

ipfs://e226a6302b84b358849f5b5e0f541d9614dcdad0cedb6d983293d343b1243995

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ 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.