ETH Price: $3,050.50 (+2.35%)
Gas: 1 Gwei

Contract

0x881A0BDF9514c116f4576F4Fba263bf5397fca83
 

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Transfer Asset T...95191902020-02-20 9:04:081598 days ago1582189448IN
0x881A0BDF...5397fca83
0 ETH0.000297047.3806009
Transfer Asset T...94649442020-02-12 0:25:551607 days ago1581467155IN
0x881A0BDF...5397fca83
0 ETH0.000164213
Transfer Asset T...94649442020-02-12 0:25:551607 days ago1581467155IN
0x881A0BDF...5397fca83
0 ETH0.000116553
Transfer Asset T...94649442020-02-12 0:25:551607 days ago1581467155IN
0x881A0BDF...5397fca83
0 ETH0.000158053
Transfer Asset T...94649442020-02-12 0:25:551607 days ago1581467155IN
0x881A0BDF...5397fca83
0 ETH0.000117543
Transfer Asset T...94649442020-02-12 0:25:551607 days ago1581467155IN
0x881A0BDF...5397fca83
0 ETH0.000117233
Transfer Asset T...94649442020-02-12 0:25:551607 days ago1581467155IN
0x881A0BDF...5397fca83
0 ETH0.000179663
Transfer Asset T...94649422020-02-12 0:25:231607 days ago1581467123IN
0x881A0BDF...5397fca83
0 ETH0.000045791.2
Transfer Asset T...94649422020-02-12 0:25:231607 days ago1581467123IN
0x881A0BDF...5397fca83
0 ETH0.000070641.2
Transfer Asset T...94649422020-02-12 0:25:231607 days ago1581467123IN
0x881A0BDF...5397fca83
0 ETH0.000064541.2
Transfer Asset T...94649422020-02-12 0:25:231607 days ago1581467123IN
0x881A0BDF...5397fca83
0 ETH0.00006381.2
Transfer Asset T...94649202020-02-12 0:20:171607 days ago1581466817IN
0x881A0BDF...5397fca83
0 ETH0.000108262
Transfer Asset T...94649182020-02-12 0:19:481607 days ago1581466788IN
0x881A0BDF...5397fca83
0 ETH0.000077662
Transfer Asset T...91902262019-12-31 9:38:271649 days ago1577785107IN
0x881A0BDF...5397fca83
0 ETH0.000352639
Migrate Owned Co...91901812019-12-31 9:22:071649 days ago1577784127IN
0x881A0BDF...5397fca83
0 ETH0.000533747.5
Redeem Commissio...91896812019-12-31 6:57:551649 days ago1577775475IN
0x881A0BDF...5397fca83
0 ETH0.000233621
Redeem Commissio...91894632019-12-31 5:49:291649 days ago1577771369IN
0x881A0BDF...5397fca83
0 ETH0.001631553.42221
Redeem Commissio...91879162019-12-30 22:19:151650 days ago1577744355IN
0x881A0BDF...5397fca83
0 ETH0.000603181
Withdraw Token91870132019-12-30 18:02:321650 days ago1577728952IN
0x881A0BDF...5397fca83
0 ETH0.001192611
Withdraw Token91865032019-12-30 15:36:171650 days ago1577720177IN
0x881A0BDF...5397fca83
0 ETH0.005835735
Redeem Commissio...91862812019-12-30 14:36:341650 days ago1577716594IN
0x881A0BDF...5397fca83
0 ETH0.001613244.78007812
Withdraw Token91861902019-12-30 14:07:441650 days ago1577714864IN
0x881A0BDF...5397fca83
0 ETH0.00118291.001
Withdraw Token91854692019-12-30 10:35:521650 days ago1577702152IN
0x881A0BDF...5397fca83
0 ETH0.004821163.7
Withdraw Ether91852302019-12-30 9:32:501650 days ago1577698370IN
0x881A0BDF...5397fca83
0 ETH0.000816281.1
Withdraw Ether91847512019-12-30 7:15:191650 days ago1577690119IN
0x881A0BDF...5397fca83
0 ETH0.002597453.5
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
95191902020-02-20 9:04:081598 days ago1582189448
0x881A0BDF...5397fca83
0.15510152 ETH
91852302019-12-30 9:32:501650 days ago1577698370
0x881A0BDF...5397fca83
0.03955611 ETH
91852302019-12-30 9:32:501650 days ago1577698370
0x881A0BDF...5397fca83
0.03955611 ETH
91847512019-12-30 7:15:191650 days ago1577690119
0x881A0BDF...5397fca83
0.32436007 ETH
91847512019-12-30 7:15:191650 days ago1577690119
0x881A0BDF...5397fca83
0.32436007 ETH
91846532019-12-30 6:48:311650 days ago1577688511
0x881A0BDF...5397fca83
0.01079326 ETH
91846532019-12-30 6:48:311650 days ago1577688511
0x881A0BDF...5397fca83
0.01079326 ETH
91806172019-12-29 11:28:431651 days ago1577618923
0x881A0BDF...5397fca83
1.5803891 ETH
91806172019-12-29 11:28:431651 days ago1577618923
0x881A0BDF...5397fca83
1.5803891 ETH
91789412019-12-29 3:23:451652 days ago1577589825
0x881A0BDF...5397fca83
0.51496017 ETH
91789412019-12-29 3:23:451652 days ago1577589825
0x881A0BDF...5397fca83
0.51496017 ETH
91766552019-12-28 16:35:441652 days ago1577550944
0x881A0BDF...5397fca83
14.75161617 ETH
91766552019-12-28 16:35:441652 days ago1577550944
0x881A0BDF...5397fca83
14.75161617 ETH
91766182019-12-28 16:25:031652 days ago1577550303
0x881A0BDF...5397fca83
8.72148489 ETH
91766182019-12-28 16:25:031652 days ago1577550303
0x881A0BDF...5397fca83
8.72148489 ETH
91763082019-12-28 14:58:581652 days ago1577545138
0x881A0BDF...5397fca83
5.98019459 ETH
91763082019-12-28 14:58:581652 days ago1577545138
0x881A0BDF...5397fca83
5.98019459 ETH
91761692019-12-28 14:21:011652 days ago1577542861
0x881A0BDF...5397fca83
0.00035136 ETH
91761692019-12-28 14:21:011652 days ago1577542861
0x881A0BDF...5397fca83
0.00035136 ETH
91758952019-12-28 13:00:191652 days ago1577538019
0x881A0BDF...5397fca83
0.00351364 ETH
91758952019-12-28 13:00:191652 days ago1577538019
0x881A0BDF...5397fca83
0.00351364 ETH
91757122019-12-28 12:07:491652 days ago1577534869
0x881A0BDF...5397fca83
0.0196155 ETH
91757122019-12-28 12:07:491652 days ago1577534869
0x881A0BDF...5397fca83
0.0196155 ETH
91748342019-12-28 7:51:411652 days ago1577519501
0x881A0BDF...5397fca83
5.95498671 ETH
91748342019-12-28 7:51:411652 days ago1577519501
0x881A0BDF...5397fca83
2.77546303 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BetokenFund

Compiler Version
v0.5.8+commit.23d335f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2019-07-01
*/

pragma solidity 0.5.8;

/**
 * @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) {
        require(b <= a, "SafeMath: subtraction overflow");
        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-solidity/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) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, "SafeMath: division by zero");
        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) {
        require(b != 0, "SafeMath: modulo by zero");
        return a % b;
    }
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be aplied to your functions to restrict their use to
 * the owner.
 */
contract Ownable {
    address private _owner;

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

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

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

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

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return msg.sender == _owner;
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the `nonReentrant` modifier
 * available, which can be aplied 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.
 */
contract ReentrancyGuard {
    /// @dev counter to allow mutex lock with only one SSTORE operation
    uint256 private _guardCounter;

    constructor () internal {
        // The counter starts at one to prevent changing it from zero to a non-zero
        // value, which is a more expensive operation.
        _guardCounter = 1;
    }

    /**
     * @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() {
        _guardCounter += 1;
        uint256 localCounter = _guardCounter;
        _;
        require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
    }
}

interface IMiniMeToken {
    function balanceOf(address _owner) external view returns (uint256 balance);
    function totalSupply() external view returns(uint);
    function generateTokens(address _owner, uint _amount) external returns (bool);
    function destroyTokens(address _owner, uint _amount) external returns (bool);
    function totalSupplyAt(uint _blockNumber) external view returns(uint);
    function balanceOfAt(address _holder, uint _blockNumber) external view returns (uint);
    function transferOwnership(address newOwner) external;
}

/// @dev The token controller contract must implement these functions
contract TokenController {
  /// @notice Called when `_owner` sends ether to the MiniMe Token contract
  /// @param _owner The address that sent the ether to create tokens
  /// @return True if the ether is accepted, false if it throws
  function proxyPayment(address _owner) public payable returns(bool);

  /// @notice Notifies the controller about a token transfer allowing the
  ///  controller to react if desired
  /// @param _from The origin of the transfer
  /// @param _to The destination of the transfer
  /// @param _amount The amount of the transfer
  /// @return False if the controller does not authorize the transfer
  function onTransfer(address _from, address _to, uint _amount) public returns(bool);

  /// @notice Notifies the controller about an approval allowing the
  ///  controller to react if desired
  /// @param _owner The address that calls `approve()`
  /// @param _spender The spender in the `approve()` call
  /// @param _amount The amount in the `approve()` call
  /// @return False if the controller does not authorize the approval
  function onApprove(address _owner, address _spender, uint _amount) public
    returns(bool);
}

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see `ERC20Detailed`.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

/**
 * @dev Optional functions from the ERC20 standard.
 */
contract ERC20Detailed is IERC20 {
    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
     * these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name, string memory symbol, uint8 decimals) public {
        _name = name;
        _symbol = symbol;
        _decimals = decimals;
    }

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

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

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

/**
 * @dev Collection of functions related to the address type,
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * This test is non-exhaustive, and there may be false-negatives: during the
     * execution of a contract's constructor, its address will be reported as
     * not containing a contract.
     *
     * > It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies in extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}

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

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

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

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

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves.

        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.
        // solhint-disable-next-line max-line-length
        require(address(token).isContract(), "SafeERC20: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");

        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

/**
 * @title The interface for the Kyber Network smart contract
 * @author Zefram Lou (Zebang Liu)
 */
interface KyberNetwork {
  function getExpectedRate(ERC20Detailed src, ERC20Detailed dest, uint srcQty) external view
      returns (uint expectedRate, uint slippageRate);

  function tradeWithHint(
    ERC20Detailed src, uint srcAmount, ERC20Detailed dest, address payable destAddress, uint maxDestAmount,
    uint minConversionRate, address walletId, bytes calldata hint) external payable returns(uint);
}

/**
 * @title The smart contract for useful utility functions and constants.
 * @author Zefram Lou (Zebang Liu)
 */
contract Utils {
  using SafeMath for uint256;
  using SafeERC20 for ERC20Detailed;

  /**
   * @notice Checks if `_token` is a valid token.
   * @param _token the token's address
   */
  modifier isValidToken(address _token) {
    require(_token != address(0));
    if (_token != address(ETH_TOKEN_ADDRESS)) {
      require(isContract(_token));
    }
    _;
  }

  address public DAI_ADDR;
  address payable public KYBER_ADDR;
  
  bytes public constant PERM_HINT = "PERM";

  ERC20Detailed internal constant ETH_TOKEN_ADDRESS = ERC20Detailed(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee);
  ERC20Detailed internal dai;
  KyberNetwork internal kyber;

  uint constant internal PRECISION = (10**18);
  uint constant internal MAX_QTY   = (10**28); // 10B tokens
  uint constant internal ETH_DECIMALS = 18;
  uint constant internal MAX_DECIMALS = 18;

  constructor(
    address _daiAddr,
    address payable _kyberAddr
  ) public {
    DAI_ADDR = _daiAddr;
    KYBER_ADDR = _kyberAddr;

    dai = ERC20Detailed(_daiAddr);
    kyber = KyberNetwork(_kyberAddr);
  }

  /**
   * @notice Get the number of decimals of a token
   * @param _token the token to be queried
   * @return number of decimals
   */
  function getDecimals(ERC20Detailed _token) internal view returns(uint256) {
    if (address(_token) == address(ETH_TOKEN_ADDRESS)) {
      return uint256(ETH_DECIMALS);
    }
    return uint256(_token.decimals());
  }

  /**
   * @notice Get the token balance of an account
   * @param _token the token to be queried
   * @param _addr the account whose balance will be returned
   * @return token balance of the account
   */
  function getBalance(ERC20Detailed _token, address _addr) internal view returns(uint256) {
    if (address(_token) == address(ETH_TOKEN_ADDRESS)) {
      return uint256(_addr.balance);
    }
    return uint256(_token.balanceOf(_addr));
  }

  /**
   * @notice Calculates the rate of a trade. The rate is the price of the source token in the dest token, in 18 decimals.
   *         Note: the rate is on the token level, not the wei level, so for example if 1 Atoken = 10 Btoken, then the rate
   *         from A to B is 10 * 10**18, regardless of how many decimals each token uses.
   * @param srcAmount amount of source token
   * @param destAmount amount of dest token
   * @param srcDecimals decimals used by source token
   * @param dstDecimals decimals used by dest token
   */
  function calcRateFromQty(uint srcAmount, uint destAmount, uint srcDecimals, uint dstDecimals)
        internal pure returns(uint)
  {
    require(srcAmount <= MAX_QTY);
    require(destAmount <= MAX_QTY);

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

  /**
   * @notice Wrapper function for doing token conversion on Kyber Network
   * @param _srcToken the token to convert from
   * @param _srcAmount the amount of tokens to be converted
   * @param _destToken the destination token
   * @return _destPriceInSrc the price of the dest token, in terms of source tokens
   *         _srcPriceInDest the price of the source token, in terms of dest tokens
   *         _actualDestAmount actual amount of dest token traded
   *         _actualSrcAmount actual amount of src token traded
   */
  function __kyberTrade(ERC20Detailed _srcToken, uint256 _srcAmount, ERC20Detailed _destToken)
    internal
    returns(
      uint256 _destPriceInSrc,
      uint256 _srcPriceInDest,
      uint256 _actualDestAmount,
      uint256 _actualSrcAmount
    )
  {
    require(_srcToken != _destToken);

    // Get current rate & ensure token is listed on Kyber
    (, uint256 rate) = kyber.getExpectedRate(_srcToken, _destToken, _srcAmount);
    require(rate > 0);

    uint256 beforeSrcBalance = getBalance(_srcToken, address(this));
    uint256 msgValue;
    if (_srcToken != ETH_TOKEN_ADDRESS) {
      msgValue = 0;
      _srcToken.safeApprove(KYBER_ADDR, 0);
      _srcToken.safeApprove(KYBER_ADDR, _srcAmount);
    } else {
      msgValue = _srcAmount;
    }
    _actualDestAmount = kyber.tradeWithHint.value(msgValue)(
      _srcToken,
      _srcAmount,
      _destToken,
      toPayableAddr(address(this)),
      MAX_QTY,
      rate,
      0x332D87209f7c8296389C307eAe170c2440830A47,
      PERM_HINT
    );
    require(_actualDestAmount > 0);
    if (_srcToken != ETH_TOKEN_ADDRESS) {
      _srcToken.safeApprove(KYBER_ADDR, 0);
    }

    _actualSrcAmount = beforeSrcBalance.sub(getBalance(_srcToken, address(this)));
    _destPriceInSrc = calcRateFromQty(_actualDestAmount, _actualSrcAmount, getDecimals(_destToken), getDecimals(_srcToken));
    _srcPriceInDest = calcRateFromQty(_actualSrcAmount, _actualDestAmount, getDecimals(_srcToken), getDecimals(_destToken));
  }

  /**
   * @notice Checks if an Ethereum account is a smart contract
   * @param _addr the account to be checked
   * @return True if the account is a smart contract, false otherwise
   */
  function isContract(address _addr) view internal returns(bool) {
    uint size;
    if (_addr == address(0)) return false;
    assembly {
        size := extcodesize(_addr)
    }
    return size>0;
  }

  function toPayableAddr(address _addr) pure internal returns (address payable) {
    return address(uint160(_addr));
  }
}

interface BetokenProxyInterface {
  function betokenFundAddress() external view returns (address payable);
  function updateBetokenFundAddress() external;
}

/**
 * @title The storage layout of BetokenFund
 * @author Zefram Lou (Zebang Liu)
 */
contract BetokenStorage is Ownable, ReentrancyGuard {
  using SafeMath for uint256;

  enum CyclePhase { Intermission, Manage }
  enum VoteDirection { Empty, For, Against }
  enum Subchunk { Propose, Vote }

  struct Investment {
    address tokenAddress;
    uint256 cycleNumber;
    uint256 stake;
    uint256 tokenAmount;
    uint256 buyPrice; // token buy price in 18 decimals in DAI
    uint256 sellPrice; // token sell price in 18 decimals in DAI
    uint256 buyTime;
    uint256 buyCostInDAI;
    bool isSold;
  }

  // Fund parameters
  uint256 public constant COMMISSION_RATE = 20 * (10 ** 16); // The proportion of profits that gets distributed to Kairo holders every cycle.
  uint256 public constant ASSET_FEE_RATE = 1 * (10 ** 15); // The proportion of fund balance that gets distributed to Kairo holders every cycle.
  uint256 public constant NEXT_PHASE_REWARD = 1 * (10 ** 18); // Amount of Kairo rewarded to the user who calls nextPhase().
  uint256 public constant MAX_BUY_KRO_PROP = 1 * (10 ** 16); // max Kairo you can buy is 1% of total supply
  uint256 public constant FALLBACK_MAX_DONATION = 100 * (10 ** 18); // If payment cap for registration is below 100 DAI, use 100 DAI instead
  uint256 public constant MIN_KRO_PRICE = 25 * (10 ** 17); // 1 KRO >= 2.5 DAI
  uint256 public constant COLLATERAL_RATIO_MODIFIER = 75 * (10 ** 16); // Modifies Compound's collateral ratio, gets 2:1 ratio from current 1.5:1 ratio
  uint256 public constant MIN_RISK_TIME = 3 days; // Mininum risk taken to get full commissions is 9 days * kairoBalance
  uint256 public constant INACTIVE_THRESHOLD = 6; // Number of inactive cycles after which a manager's Kairo balance can be burned
  // Upgrade constants
  uint256 public constant CHUNK_SIZE = 3 days;
  uint256 public constant PROPOSE_SUBCHUNK_SIZE = 1 days;
  uint256 public constant CYCLES_TILL_MATURITY = 3;
  uint256 public constant QUORUM = 10 * (10 ** 16); // 10% quorum
  uint256 public constant VOTE_SUCCESS_THRESHOLD = 75 * (10 ** 16); // Votes on upgrade candidates need >75% voting weight to pass

  // Instance variables

  // Checks if the token listing initialization has been completed.
  bool public hasInitializedTokenListings;

  // Address of the Kairo token contract.
  address public controlTokenAddr;

  // Address of the share token contract.
  address public shareTokenAddr;

  // Address of the BetokenProxy contract.
  address payable public proxyAddr;

  // Address of the CompoundOrderFactory contract.
  address public compoundFactoryAddr;

  // Address of the BetokenLogic contract.
  address public betokenLogic;

  // Address to which the development team funding will be sent.
  address payable public devFundingAccount;

  // Address of the previous version of BetokenFund.
  address payable public previousVersion;

  // The number of the current investment cycle.
  uint256 public cycleNumber;

  // The amount of funds held by the fund.
  uint256 public totalFundsInDAI;

  // The start time for the current investment cycle phase, in seconds since Unix epoch.
  uint256 public startTimeOfCyclePhase;

  // The proportion of Betoken Shares total supply to mint and use for funding the development team. Fixed point decimal.
  uint256 public devFundingRate;

  // Total amount of commission unclaimed by managers
  uint256 public totalCommissionLeft;

  // Stores the lengths of each cycle phase in seconds.
  uint256[2] public phaseLengths;

  // The last cycle where a user redeemed all of their remaining commission.
  mapping(address => uint256) public lastCommissionRedemption;

  // Marks whether a manager has redeemed their commission for a certain cycle
  mapping(address => mapping(uint256 => bool)) public hasRedeemedCommissionForCycle;

  // The stake-time measured risk that a manager has taken in a cycle
  mapping(address => mapping(uint256 => uint256)) public riskTakenInCycle;

  // In case a manager joined the fund during the current cycle, set the fallback base stake for risk threshold calculation
  mapping(address => uint256) public baseRiskStakeFallback;

  // List of investments of a manager in the current cycle.
  mapping(address => Investment[]) public userInvestments;

  // List of short/long orders of a manager in the current cycle.
  mapping(address => address payable[]) public userCompoundOrders;

  // Total commission to be paid for work done in a certain cycle (will be redeemed in the next cycle's Intermission)
  mapping(uint256 => uint256) public totalCommissionOfCycle;

  // The block number at which the Manage phase ended for a given cycle
  mapping(uint256 => uint256) public managePhaseEndBlock;

  // The last cycle where a manager made an investment
  mapping(address => uint256) public lastActiveCycle;

  // Checks if an address points to a whitelisted Kyber token.
  mapping(address => bool) public isKyberToken;

  // Checks if an address points to a whitelisted Compound token. Returns false for cDAI and other stablecoin CompoundTokens.
  mapping(address => bool) public isCompoundToken;

  // Check if an address points to a whitelisted Fulcrum position token.
  mapping(address => bool) public isPositionToken;

  // The current cycle phase.
  CyclePhase public cyclePhase;

  // Upgrade governance related variables
  bool public hasFinalizedNextVersion; // Denotes if the address of the next smart contract version has been finalized
  bool public upgradeVotingActive; // Denotes if the vote for which contract to upgrade to is active
  address payable public nextVersion; // Address of the next version of BetokenFund.
  address[5] public proposers; // Manager who proposed the upgrade candidate in a chunk
  address payable[5] public candidates; // Candidates for a chunk
  uint256[5] public forVotes; // For votes for a chunk
  uint256[5] public againstVotes; // Against votes for a chunk
  uint256 public proposersVotingWeight; // Total voting weight of previous and current proposers. This is used for excluding the voting weight of proposers.
  mapping(uint256 => mapping(address => VoteDirection[5])) public managerVotes; // Records each manager's vote
  mapping(uint256 => uint256) public upgradeSignalStrength; // Denotes the amount of Kairo that's signalling in support of beginning the upgrade process during a cycle
  mapping(uint256 => mapping(address => bool)) public upgradeSignal; // Maps manager address to whether they support initiating an upgrade

  // Contract instances
  IMiniMeToken internal cToken;
  IMiniMeToken internal sToken;
  BetokenProxyInterface internal proxy;

  // Events

  event ChangedPhase(uint256 indexed _cycleNumber, uint256 indexed _newPhase, uint256 _timestamp, uint256 _totalFundsInDAI);

  event Deposit(uint256 indexed _cycleNumber, address indexed _sender, address _tokenAddress, uint256 _tokenAmount, uint256 _daiAmount, uint256 _timestamp);
  event Withdraw(uint256 indexed _cycleNumber, address indexed _sender, address _tokenAddress, uint256 _tokenAmount, uint256 _daiAmount, uint256 _timestamp);

  event CreatedInvestment(uint256 indexed _cycleNumber, address indexed _sender, uint256 _id, address _tokenAddress, uint256 _stakeInWeis, uint256 _buyPrice, uint256 _costDAIAmount, uint256 _tokenAmount);
  event SoldInvestment(uint256 indexed _cycleNumber, address indexed _sender, uint256 _id, address _tokenAddress, uint256 _receivedKairo, uint256 _sellPrice, uint256 _earnedDAIAmount);

  event CreatedCompoundOrder(uint256 indexed _cycleNumber, address indexed _sender, uint256 _id, address _order, bool _orderType, address _tokenAddress, uint256 _stakeInWeis, uint256 _costDAIAmount);
  event SoldCompoundOrder(uint256 indexed _cycleNumber, address indexed _sender, uint256 _id, address _order,  bool _orderType, address _tokenAddress, uint256 _receivedKairo, uint256 _earnedDAIAmount);
  event RepaidCompoundOrder(uint256 indexed _cycleNumber, address indexed _sender, uint256 _id, address _order, uint256 _repaidDAIAmount);

  event CommissionPaid(uint256 indexed _cycleNumber, address indexed _sender, uint256 _commission);
  event TotalCommissionPaid(uint256 indexed _cycleNumber, uint256 _totalCommissionInDAI);

  event Register(address indexed _manager, uint256 _donationInDAI, uint256 _kairoReceived);
  
  event SignaledUpgrade(uint256 indexed _cycleNumber, address indexed _sender, bool indexed _inSupport);
  event DeveloperInitiatedUpgrade(uint256 indexed _cycleNumber, address _candidate);
  event InitiatedUpgrade(uint256 indexed _cycleNumber);
  event ProposedCandidate(uint256 indexed _cycleNumber, uint256 indexed _voteID, address indexed _sender, address _candidate);
  event Voted(uint256 indexed _cycleNumber, uint256 indexed _voteID, address indexed _sender, bool _inSupport, uint256 _weight);
  event FinalizedNextVersion(uint256 indexed _cycleNumber, address _nextVersion);

  /*
  Helper functions shared by both BetokenLogic & BetokenFund
  */

  /**
   * @notice The manage phase is divided into 9 3-day chunks. Determines which chunk the fund's in right now.
   * @return The index of the current chunk (starts from 0). Returns 0 if not in Manage phase.
   */
  function currentChunk() public view returns (uint) {
    if (cyclePhase != CyclePhase.Manage) {
      return 0;
    }
    return (now - startTimeOfCyclePhase) / CHUNK_SIZE;
  }

  /**
   * @notice There are two subchunks in each chunk: propose (1 day) and vote (2 days).
   *         Determines which subchunk the fund is in right now.
   * @return The Subchunk the fund is in right now
   */
  function currentSubchunk() public view returns (Subchunk _subchunk) {
    if (cyclePhase != CyclePhase.Manage) {
      return Subchunk.Vote;
    }
    uint256 timeIntoCurrChunk = (now - startTimeOfCyclePhase) % CHUNK_SIZE;
    return timeIntoCurrChunk < PROPOSE_SUBCHUNK_SIZE ? Subchunk.Propose : Subchunk.Vote;
  }

  /**
   * @notice Calculates an account's voting weight based on their Kairo balance
   *         3 cycles ago
   * @param _of the account to be queried
   * @return The account's voting weight
   */
  function getVotingWeight(address _of) public view returns (uint256 _weight) {
    if (cycleNumber <= CYCLES_TILL_MATURITY || _of == address(0)) {
      return 0;
    }
    return cToken.balanceOfAt(_of, managePhaseEndBlock[cycleNumber.sub(CYCLES_TILL_MATURITY)]);
  }

  /**
   * @notice Calculates the total voting weight based on the total Kairo supply
   *         3 cycles ago. The weights of proposers are deducted.
   * @return The total voting weight right now
   */
  function getTotalVotingWeight() public view returns (uint256 _weight) {
    if (cycleNumber <= CYCLES_TILL_MATURITY) {
      return 0;
    }
    return cToken.totalSupplyAt(managePhaseEndBlock[cycleNumber.sub(CYCLES_TILL_MATURITY)]).sub(proposersVotingWeight);
  }

  /**
   * @notice Calculates the current price of Kairo. The price is equal to the amount of DAI each Kairo
   *         can control, and it's kept above MIN_KRO_PRICE.
   * @return Kairo's current price
   */
  function kairoPrice() public view returns (uint256 _kairoPrice) {
    if (cToken.totalSupply() == 0) { return MIN_KRO_PRICE; }
    uint256 controlPerKairo = totalFundsInDAI.mul(10 ** 18).div(cToken.totalSupply());
    if (controlPerKairo < MIN_KRO_PRICE) {
      // keep price above minimum price
      return MIN_KRO_PRICE;
    }
    return controlPerKairo;
  }
}

// Compound finance comptroller
interface Comptroller {
    function enterMarkets(address[] calldata cTokens) external returns (uint[] memory);
    function markets(address cToken) external view returns (bool isListed, uint256 collateralFactorMantissa);
}

// Compound finance's price oracle
interface PriceOracle {
  function getPrice(address asset) external view returns (uint);
}

// Compound finance ERC20 market interface
interface CERC20 {
  function mint(uint mintAmount) external returns (uint);
  function redeemUnderlying(uint redeemAmount) external returns (uint);
  function borrow(uint borrowAmount) external returns (uint);
  function repayBorrow(uint repayAmount) external returns (uint);
  function borrowBalanceCurrent(address account) external returns (uint);
  function exchangeRateCurrent() external returns (uint);

  function balanceOf(address account) external view returns (uint);
  function decimals() external view returns (uint);
  function underlying() external view returns (address);
}

contract CompoundOrderStorage is Ownable {
  // Constants
  uint256 internal constant NEGLIGIBLE_DEBT = 10 ** 14; // we don't care about debts below 10^-4 DAI (0.1 cent)
  uint256 internal constant MAX_REPAY_STEPS = 3; // Max number of times we attempt to repay remaining debt

  // Contract instances
  Comptroller public COMPTROLLER; // The Compound comptroller
  PriceOracle public ORACLE; // The Compound price oracle
  CERC20 public CDAI; // The Compound DAI market token
  address public CETH_ADDR;

  // Instance variables
  uint256 public stake;
  uint256 public collateralAmountInDAI;
  uint256 public loanAmountInDAI;
  uint256 public cycleNumber;
  uint256 public buyTime; // Timestamp for order execution
  uint256 public outputAmount; // Records the total output DAI after order is sold
  address public compoundTokenAddr;
  bool public isSold;
  bool public orderType; // True for shorting, false for longing

  // The contract containing the code to be executed
  address public logicContract;
}

contract CompoundOrder is CompoundOrderStorage, Utils {
  constructor(
    address _compoundTokenAddr,
    uint256 _cycleNumber,
    uint256 _stake,
    uint256 _collateralAmountInDAI,
    uint256 _loanAmountInDAI,
    bool _orderType,
    address _logicContract,
    address _daiAddr,
    address payable _kyberAddr,
    address _comptrollerAddr,
    address _priceOracleAddr,
    address _cDAIAddr,
    address _cETHAddr
  ) public Utils(_daiAddr, _kyberAddr)  {
    // Initialize details of short order
    require(_compoundTokenAddr != _cDAIAddr);
    require(_stake > 0 && _collateralAmountInDAI > 0 && _loanAmountInDAI > 0); // Validate inputs
    stake = _stake;
    collateralAmountInDAI = _collateralAmountInDAI;
    loanAmountInDAI = _loanAmountInDAI;
    cycleNumber = _cycleNumber;
    compoundTokenAddr = _compoundTokenAddr;
    orderType = _orderType;
    logicContract = _logicContract;

    COMPTROLLER = Comptroller(_comptrollerAddr);
    ORACLE = PriceOracle(_priceOracleAddr);
    CDAI = CERC20(_cDAIAddr);
    CETH_ADDR = _cETHAddr;
  }
  
  /**
   * @notice Executes the Compound order
   * @param _minPrice the minimum token price
   * @param _maxPrice the maximum token price
   */
  function executeOrder(uint256 _minPrice, uint256 _maxPrice) public {
    (bool success,) = logicContract.delegatecall(abi.encodeWithSelector(this.executeOrder.selector, _minPrice, _maxPrice));
    if (!success) { revert(); }
  }

  /**
   * @notice Sells the Compound order and returns assets to BetokenFund
   * @param _minPrice the minimum token price
   * @param _maxPrice the maximum token price
   */
  function sellOrder(uint256 _minPrice, uint256 _maxPrice) public returns (uint256 _inputAmount, uint256 _outputAmount) {
    (bool success, bytes memory result) = logicContract.delegatecall(abi.encodeWithSelector(this.sellOrder.selector, _minPrice, _maxPrice));
    if (!success) { revert(); }
    return abi.decode(result, (uint256, uint256));
  }

  /**
   * @notice Repays the loans taken out to prevent the collateral ratio from dropping below threshold
   * @param _repayAmountInDAI the amount to repay, in DAI
   */
  function repayLoan(uint256 _repayAmountInDAI) public {
    (bool success,) = logicContract.delegatecall(abi.encodeWithSelector(this.repayLoan.selector, _repayAmountInDAI));
    if (!success) { revert(); }
  }

  /**
   * @notice Calculates the current liquidity (supply - collateral) on the Compound platform
   * @return the liquidity
   */
  function getCurrentLiquidityInDAI() public returns (bool _isNegative, uint256 _amount) {
    (bool success, bytes memory result) = logicContract.delegatecall(abi.encodeWithSelector(this.getCurrentLiquidityInDAI.selector));
    if (!success) { revert(); }
    return abi.decode(result, (bool, uint256));
  }

  /**
   * @notice Calculates the current collateral ratio on Compound, using 18 decimals
   * @return the collateral ratio
   */
  function getCurrentCollateralRatioInDAI() public returns (uint256 _amount) {
    (bool success, bytes memory result) = logicContract.delegatecall(abi.encodeWithSelector(this.getCurrentCollateralRatioInDAI.selector));
    if (!success) { revert(); }
    return abi.decode(result, (uint256));
  }

  /**
   * @notice Calculates the current profit in DAI
   * @return the profit amount
   */
  function getCurrentProfitInDAI() public returns (bool _isNegative, uint256 _amount) {
    (bool success, bytes memory result) = logicContract.delegatecall(abi.encodeWithSelector(this.getCurrentProfitInDAI.selector));
    if (!success) { revert(); }
    return abi.decode(result, (bool, uint256));
  }

  function getMarketCollateralFactor() public returns (uint256) {
    (bool success, bytes memory result) = logicContract.delegatecall(abi.encodeWithSelector(this.getMarketCollateralFactor.selector));
    if (!success) { revert(); }
    return abi.decode(result, (uint256));
  }

  function getCurrentCollateralInDAI() public returns (uint256 _amount) {
    (bool success, bytes memory result) = logicContract.delegatecall(abi.encodeWithSelector(this.getCurrentCollateralInDAI.selector));
    if (!success) { revert(); }
    return abi.decode(result, (uint256));
  }

  function getCurrentBorrowInDAI() public returns (uint256 _amount) {
    (bool success, bytes memory result) = logicContract.delegatecall(abi.encodeWithSelector(this.getCurrentBorrowInDAI.selector));
    if (!success) { revert(); }
    return abi.decode(result, (uint256));
  }

  function getCurrentCashInDAI() public returns (uint256 _amount) {
    (bool success, bytes memory result) = logicContract.delegatecall(abi.encodeWithSelector(this.getCurrentCashInDAI.selector));
    if (!success) { revert(); }
    return abi.decode(result, (uint256));
  }

  function() external payable {}
}

contract CompoundOrderFactory {
  address public SHORT_CERC20_LOGIC_CONTRACT;
  address public SHORT_CEther_LOGIC_CONTRACT;
  address public LONG_CERC20_LOGIC_CONTRACT;
  address public LONG_CEther_LOGIC_CONTRACT;

  address public DAI_ADDR;
  address payable public KYBER_ADDR;
  address public COMPTROLLER_ADDR;
  address public ORACLE_ADDR;
  address public CDAI_ADDR;
  address public CETH_ADDR;

  constructor(
    address _shortCERC20LogicContract,
    address _shortCEtherLogicContract,
    address _longCERC20LogicContract,
    address _longCEtherLogicContract,
    address _daiAddr,
    address payable _kyberAddr,
    address _comptrollerAddr,
    address _priceOracleAddr,
    address _cDAIAddr,
    address _cETHAddr
  ) public {
    SHORT_CERC20_LOGIC_CONTRACT = _shortCERC20LogicContract;
    SHORT_CEther_LOGIC_CONTRACT = _shortCEtherLogicContract;
    LONG_CERC20_LOGIC_CONTRACT = _longCERC20LogicContract;
    LONG_CEther_LOGIC_CONTRACT = _longCEtherLogicContract;

    DAI_ADDR = _daiAddr;
    KYBER_ADDR = _kyberAddr;
    COMPTROLLER_ADDR = _comptrollerAddr;
    ORACLE_ADDR = _priceOracleAddr;
    CDAI_ADDR = _cDAIAddr;
    CETH_ADDR = _cETHAddr;
  }

  function createOrder(
    address _compoundTokenAddr,
    uint256 _cycleNumber,
    uint256 _stake,
    uint256 _collateralAmountInDAI,
    uint256 _loanAmountInDAI,
    bool _orderType
  ) public returns (CompoundOrder) {
    require(_compoundTokenAddr != address(0));

    CompoundOrder order;
    address logicContract;

    if (_compoundTokenAddr != CETH_ADDR) {
      logicContract = _orderType ? SHORT_CERC20_LOGIC_CONTRACT : LONG_CERC20_LOGIC_CONTRACT;
    } else {
      logicContract = _orderType ? SHORT_CEther_LOGIC_CONTRACT : LONG_CEther_LOGIC_CONTRACT;
    }
    order = new CompoundOrder(_compoundTokenAddr, _cycleNumber, _stake, _collateralAmountInDAI, _loanAmountInDAI, _orderType, logicContract, DAI_ADDR, KYBER_ADDR, COMPTROLLER_ADDR, ORACLE_ADDR, CDAI_ADDR, CETH_ADDR);
    order.transferOwnership(msg.sender);
    return order;
  }

  function getMarketCollateralFactor(address _compoundTokenAddr) public view returns (uint256) {
    Comptroller troll = Comptroller(COMPTROLLER_ADDR);
    (, uint256 factor) = troll.markets(_compoundTokenAddr);
    return factor;
  }
}

/**
 * @title The main smart contract of the Betoken hedge fund.
 * @author Zefram Lou (Zebang Liu)
 */
contract BetokenFund is BetokenStorage, Utils, TokenController {
  /**
   * @notice Executes function only during the given cycle phase.
   * @param phase the cycle phase during which the function may be called
   */
  modifier during(CyclePhase phase) {
    require(cyclePhase == phase);
    _;
  }

  /**
   * @notice Passes if the fund is ready for migrating to the next version
   */
  modifier readyForUpgradeMigration {
    require(hasFinalizedNextVersion == true);
    require(now > startTimeOfCyclePhase.add(phaseLengths[uint(CyclePhase.Intermission)]));
    _;
  }

  /**
   * @notice Passes if the fund has not finalized the next smart contract to upgrade to
   */
  modifier notReadyForUpgrade {
    require(hasFinalizedNextVersion == false);
    _;
  }

  /**
   * Meta functions
   */

  constructor(
    address payable _kroAddr,
    address payable _sTokenAddr,
    address payable _devFundingAccount,
    uint256[2] memory _phaseLengths,
    uint256 _devFundingRate,
    address payable _previousVersion,
    address _daiAddr,
    address payable _kyberAddr,
    address _compoundFactoryAddr,
    address _betokenLogic
  )
    public
    Utils(_daiAddr, _kyberAddr)
  {
    controlTokenAddr = _kroAddr;
    shareTokenAddr = _sTokenAddr;
    devFundingAccount = _devFundingAccount;
    phaseLengths = _phaseLengths;
    devFundingRate = _devFundingRate;
    cyclePhase = CyclePhase.Manage;
    compoundFactoryAddr = _compoundFactoryAddr;
    betokenLogic = _betokenLogic;
    previousVersion = _previousVersion;

    cToken = IMiniMeToken(_kroAddr);
    sToken = IMiniMeToken(_sTokenAddr);
  }

  function initTokenListings(
    address[] memory _kyberTokens,
    address[] memory _compoundTokens,
    address[] memory _positionTokens
  )
    public
    onlyOwner
  {
    // May only initialize once
    require(!hasInitializedTokenListings);
    hasInitializedTokenListings = true;

    uint256 i;
    for (i = 0; i < _kyberTokens.length; i = i.add(1)) {
      isKyberToken[_kyberTokens[i]] = true;
    }

    for (i = 0; i < _compoundTokens.length; i = i.add(1)) {
      isCompoundToken[_compoundTokens[i]] = true;
    }

    for (i = 0; i < _positionTokens.length; i = i.add(1)) {
      isPositionToken[_positionTokens[i]] = true;
    }
  }

  /**
   * @notice Used during deployment to set the BetokenProxy contract address.
   * @param _proxyAddr the proxy's address
   */
  function setProxy(address payable _proxyAddr) public onlyOwner {
    require(_proxyAddr != address(0));
    require(proxyAddr == address(0));
    proxyAddr = _proxyAddr;
    proxy = BetokenProxyInterface(_proxyAddr);
  }

  /**
   * Upgrading functions
   */

  /**
   * @notice Allows the developer to propose a candidate smart contract for the fund to upgrade to.
   *          The developer may change the candidate during the Intermission phase.
   * @param _candidate the address of the candidate smart contract
   * @return True if successfully changed candidate, false otherwise.
   */
  function developerInitiateUpgrade(address payable _candidate) public during(CyclePhase.Intermission) onlyOwner notReadyForUpgrade returns (bool _success) {
    (bool success, bytes memory result) = betokenLogic.delegatecall(abi.encodeWithSelector(this.developerInitiateUpgrade.selector, _candidate));
    if (!success) { return false; }
    return abi.decode(result, (bool));
  }

  /**
   * @notice Allows a manager to signal their support of initiating an upgrade. They can change their signal before the end of the Intermission phase.
   *          Managers who oppose initiating an upgrade don't need to call this function, unless they origianlly signalled in support.
   *          Signals are reset every cycle.
   * @param _inSupport True if the manager supports initiating upgrade, false if the manager opposes it.
   * @return True if successfully changed signal, false if no changes were made.
   */
  function signalUpgrade(bool _inSupport) public during(CyclePhase.Intermission) notReadyForUpgrade returns (bool _success) {
    (bool success, bytes memory result) = betokenLogic.delegatecall(abi.encodeWithSelector(this.signalUpgrade.selector, _inSupport));
    if (!success) { return false; }
    return abi.decode(result, (bool));
  }

  /**
   * @notice Allows manager to propose a candidate smart contract for the fund to upgrade to. Among the managers who have proposed a candidate,
   *          the manager with the most voting weight's candidate will be used in the vote. Ties are broken in favor of the larger address.
   *          The proposer may change the candidate they support during the Propose subchunk in their chunk.
   * @param _chunkNumber the chunk for which the sender is proposing the candidate
   * @param _candidate the address of the candidate smart contract
   * @return True if successfully proposed/changed candidate, false otherwise.
   */
  function proposeCandidate(uint256 _chunkNumber, address payable _candidate) public during(CyclePhase.Manage) notReadyForUpgrade returns (bool _success) {
    (bool success, bytes memory result) = betokenLogic.delegatecall(abi.encodeWithSelector(this.proposeCandidate.selector, _chunkNumber, _candidate));
    if (!success) { return false; }
    return abi.decode(result, (bool));
  }

  /**
   * @notice Allows a manager to vote for or against a candidate smart contract the fund will upgrade to. The manager may change their vote during
   *          the Vote subchunk. A manager who has been a proposer may not vote.
   * @param _inSupport True if the manager supports initiating upgrade, false if the manager opposes it.
   * @return True if successfully changed vote, false otherwise.
   */
  function voteOnCandidate(uint256 _chunkNumber, bool _inSupport) public during(CyclePhase.Manage) notReadyForUpgrade returns (bool _success) {
    (bool success, bytes memory result) = betokenLogic.delegatecall(abi.encodeWithSelector(this.voteOnCandidate.selector, _chunkNumber, _inSupport));
    if (!success) { return false; }
    return abi.decode(result, (bool));
  }

  /**
   * @notice Performs the necessary state changes after a successful vote
   * @param _chunkNumber the chunk number of the successful vote
   * @return True if successful, false otherwise
   */
  function finalizeSuccessfulVote(uint256 _chunkNumber) public during(CyclePhase.Manage) notReadyForUpgrade returns (bool _success) {
    (bool success, bytes memory result) = betokenLogic.delegatecall(abi.encodeWithSelector(this.finalizeSuccessfulVote.selector, _chunkNumber));
    if (!success) { return false; }
    return abi.decode(result, (bool));
  }

  /**
   * @notice Transfers ownership of Kairo & Share token contracts to the next version. Also updates BetokenFund's
   *         address in BetokenProxy.
   */
  function migrateOwnedContractsToNextVersion() public nonReentrant readyForUpgradeMigration {
    cToken.transferOwnership(nextVersion);
    sToken.transferOwnership(nextVersion);
    proxy.updateBetokenFundAddress();
  }

  /**
   * @notice Transfers assets to the next version.
   * @param _assetAddress the address of the asset to be transferred. Use ETH_TOKEN_ADDRESS to transfer Ether.
   */
  function transferAssetToNextVersion(address _assetAddress) public nonReentrant readyForUpgradeMigration isValidToken(_assetAddress) {
    if (_assetAddress == address(ETH_TOKEN_ADDRESS)) {
      nextVersion.transfer(address(this).balance);
    } else {
      ERC20Detailed token = ERC20Detailed(_assetAddress);
      token.safeTransfer(nextVersion, token.balanceOf(address(this)));
    }
  }

  /**
   * Getters
   */

  /**
   * @notice Returns the length of the user's investments array.
   * @return length of the user's investments array
   */
  function investmentsCount(address _userAddr) public view returns(uint256 _count) {
    return userInvestments[_userAddr].length;
  }

  /**
   * @notice Returns the length of the user's compound orders array.
   * @return length of the user's compound orders array
   */
  function compoundOrdersCount(address _userAddr) public view returns(uint256 _count) {
    return userCompoundOrders[_userAddr].length;
  }

  /**
   * @notice Returns the phaseLengths array.
   * @return the phaseLengths array
   */
  function getPhaseLengths() public view returns(uint256[2] memory _phaseLengths) {
    return phaseLengths;
  }

  /**
   * @notice Returns the commission balance of `_manager`
   * @return the commission balance and the received penalty, denoted in DAI
   */
  function commissionBalanceOf(address _manager) public view returns (uint256 _commission, uint256 _penalty) {
    if (lastCommissionRedemption[_manager] >= cycleNumber) { return (0, 0); }
    uint256 cycle = lastCommissionRedemption[_manager] > 0 ? lastCommissionRedemption[_manager] : 1;
    uint256 cycleCommission;
    uint256 cyclePenalty;
    for (; cycle < cycleNumber; cycle = cycle.add(1)) {
      (cycleCommission, cyclePenalty) = commissionOfAt(_manager, cycle);
      _commission = _commission.add(cycleCommission);
      _penalty = _penalty.add(cyclePenalty);
    }
  }

  /**
   * @notice Returns the commission amount received by `_manager` in the `_cycle`th cycle
   * @return the commission amount and the received penalty, denoted in DAI
   */
  function commissionOfAt(address _manager, uint256 _cycle) public view returns (uint256 _commission, uint256 _penalty) {
    if (hasRedeemedCommissionForCycle[_manager][_cycle]) { return (0, 0); }
    // take risk into account
    uint256 baseKairoBalance = cToken.balanceOfAt(_manager, managePhaseEndBlock[_cycle.sub(1)]);
    uint256 baseStake = baseKairoBalance == 0 ? baseRiskStakeFallback[_manager] : baseKairoBalance;
    if (baseKairoBalance == 0 && baseRiskStakeFallback[_manager] == 0) { return (0, 0); }
    uint256 riskTakenProportion = riskTakenInCycle[_manager][_cycle].mul(PRECISION).div(baseStake.mul(MIN_RISK_TIME)); // risk / threshold
    riskTakenProportion = riskTakenProportion > PRECISION ? PRECISION : riskTakenProportion; // max proportion is 1

    uint256 fullCommission = totalCommissionOfCycle[_cycle].mul(cToken.balanceOfAt(_manager, managePhaseEndBlock[_cycle]))
      .div(cToken.totalSupplyAt(managePhaseEndBlock[_cycle]));

    _commission = fullCommission.mul(riskTakenProportion).div(PRECISION);
    _penalty = fullCommission.sub(_commission);
  }

  /**
   * Parameter setters
   */

  /**
   * @notice Changes the address to which the developer fees will be sent. Only callable by owner.
   * @param _newAddr the new developer fee address
   */
  function changeDeveloperFeeAccount(address payable _newAddr) public onlyOwner {
    require(_newAddr != address(0) && _newAddr != address(this));
    devFundingAccount = _newAddr;
  }

  /**
   * @notice Changes the proportion of fund balance sent to the developers each cycle. May only decrease. Only callable by owner.
   * @param _newProp the new proportion, fixed point decimal
   */
  function changeDeveloperFeeRate(uint256 _newProp) public onlyOwner {
    require(_newProp < PRECISION);
    require(_newProp < devFundingRate);
    devFundingRate = _newProp;
  }

  /**
   * @notice Allows managers to invest in a token. Only callable by owner.
   * @param _token address of the token to be listed
   */
  function listKyberToken(address _token) public onlyOwner {
    isKyberToken[_token] = true;
  }

  /**
   * @notice Moves the fund to the next phase in the investment cycle.
   */
  function nextPhase()
    public
  {
    (bool success,) = betokenLogic.delegatecall(abi.encodeWithSelector(this.nextPhase.selector));
    if (!success) { revert(); }
  }


  /**
   * Manager registration
   */

  /**
   * @notice Registers `msg.sender` as a manager, using DAI as payment. The more one pays, the more Kairo one gets.
   *         There's a max Kairo amount that can be bought, and excess payment will be sent back to sender.
   * @param _donationInDAI the amount of DAI to be used for registration
   */
  function registerWithDAI(uint256 _donationInDAI) public nonReentrant {
    (bool success,) = betokenLogic.delegatecall(abi.encodeWithSelector(this.registerWithDAI.selector, _donationInDAI));
    if (!success) { revert(); }
  }

  /**
   * @notice Registers `msg.sender` as a manager, using ETH as payment. The more one pays, the more Kairo one gets.
   *         There's a max Kairo amount that can be bought, and excess payment will be sent back to sender.
   */
  function registerWithETH() public payable nonReentrant {
    (bool success,) = betokenLogic.delegatecall(abi.encodeWithSelector(this.registerWithETH.selector));
    if (!success) { revert(); }
  }

  /**
   * @notice Registers `msg.sender` as a manager, using tokens as payment. The more one pays, the more Kairo one gets.
   *         There's a max Kairo amount that can be bought, and excess payment will be sent back to sender.
   * @param _token the token to be used for payment
   * @param _donationInTokens the amount of tokens to be used for registration, should use the token's native decimals
   */
  function registerWithToken(address _token, uint256 _donationInTokens) public nonReentrant {
    (bool success,) = betokenLogic.delegatecall(abi.encodeWithSelector(this.registerWithToken.selector, _token, _donationInTokens));
    if (!success) { revert(); }
  }


  /**
   * Intermission phase functions
   */

   /**
   * @notice Deposit Ether into the fund. Ether will be converted into DAI.
   */
  function depositEther()
    public
    payable
    during(CyclePhase.Intermission)
    nonReentrant
    notReadyForUpgrade
  {
    // Buy DAI with ETH
    uint256 actualDAIDeposited;
    uint256 actualETHDeposited;
    (,, actualDAIDeposited, actualETHDeposited) = __kyberTrade(ETH_TOKEN_ADDRESS, msg.value, dai);

    // Send back leftover ETH
    uint256 leftOverETH = msg.value.sub(actualETHDeposited);
    if (leftOverETH > 0) {
      msg.sender.transfer(leftOverETH);
    }

    // Register investment
    __deposit(actualDAIDeposited);

    // Emit event
    emit Deposit(cycleNumber, msg.sender, address(ETH_TOKEN_ADDRESS), actualETHDeposited, actualDAIDeposited, now);
  }

  /**
   * @notice Deposit DAI Stablecoin into the fund.
   * @param _daiAmount The amount of DAI to be deposited. May be different from actual deposited amount.
   */
  function depositDAI(uint256 _daiAmount)
    public
    during(CyclePhase.Intermission)
    nonReentrant
    notReadyForUpgrade
  {
    dai.safeTransferFrom(msg.sender, address(this), _daiAmount);

    // Register investment
    __deposit(_daiAmount);

    // Emit event
    emit Deposit(cycleNumber, msg.sender, DAI_ADDR, _daiAmount, _daiAmount, now);
  }

  /**
   * @notice Deposit ERC20 tokens into the fund. Tokens will be converted into DAI.
   * @param _tokenAddr the address of the token to be deposited
   * @param _tokenAmount The amount of tokens to be deposited. May be different from actual deposited amount.
   */
  function depositToken(address _tokenAddr, uint256 _tokenAmount)
    public
    nonReentrant
    during(CyclePhase.Intermission)
    isValidToken(_tokenAddr)  
    notReadyForUpgrade
  {
    require(_tokenAddr != DAI_ADDR && _tokenAddr != address(ETH_TOKEN_ADDRESS));

    ERC20Detailed token = ERC20Detailed(_tokenAddr);

    token.safeTransferFrom(msg.sender, address(this), _tokenAmount);

    // Convert token into DAI
    uint256 actualDAIDeposited;
    uint256 actualTokenDeposited;
    (,, actualDAIDeposited, actualTokenDeposited) = __kyberTrade(token, _tokenAmount, dai);

    // Give back leftover tokens
    uint256 leftOverTokens = _tokenAmount.sub(actualTokenDeposited);
    if (leftOverTokens > 0) {
      token.safeTransfer(msg.sender, leftOverTokens);
    }

    // Register investment
    __deposit(actualDAIDeposited);

    // Emit event
    emit Deposit(cycleNumber, msg.sender, _tokenAddr, actualTokenDeposited, actualDAIDeposited, now);
  }


  /**
   * @notice Withdraws Ether by burning Shares.
   * @param _amountInDAI Amount of funds to be withdrawn expressed in DAI. Fixed-point decimal. May be different from actual amount.
   */
  function withdrawEther(uint256 _amountInDAI)
    public
    during(CyclePhase.Intermission)
    nonReentrant
  {
    // Buy ETH
    uint256 actualETHWithdrawn;
    uint256 actualDAIWithdrawn;
    (,, actualETHWithdrawn, actualDAIWithdrawn) = __kyberTrade(dai, _amountInDAI, ETH_TOKEN_ADDRESS);

    __withdraw(actualDAIWithdrawn);

    // Transfer Ether to user
    msg.sender.transfer(actualETHWithdrawn);

    // Emit event
    emit Withdraw(cycleNumber, msg.sender, address(ETH_TOKEN_ADDRESS), actualETHWithdrawn, actualDAIWithdrawn, now);
  }

  /**
   * @notice Withdraws Ether by burning Shares.
   * @param _amountInDAI Amount of funds to be withdrawn expressed in DAI. Fixed-point decimal. May be different from actual amount.
   */
  function withdrawDAI(uint256 _amountInDAI)
    public
    during(CyclePhase.Intermission)
    nonReentrant
  {
    __withdraw(_amountInDAI);

    // Transfer DAI to user
    dai.safeTransfer(msg.sender, _amountInDAI);

    // Emit event
    emit Withdraw(cycleNumber, msg.sender, DAI_ADDR, _amountInDAI, _amountInDAI, now);
  }

  /**
   * @notice Withdraws funds by burning Shares, and converts the funds into the specified token using Kyber Network.
   * @param _tokenAddr the address of the token to be withdrawn into the caller's account
   * @param _amountInDAI The amount of funds to be withdrawn expressed in DAI. Fixed-point decimal. May be different from actual amount.
   */
  function withdrawToken(address _tokenAddr, uint256 _amountInDAI)
    public
    nonReentrant
    during(CyclePhase.Intermission)
    isValidToken(_tokenAddr)
  {
    require(_tokenAddr != DAI_ADDR && _tokenAddr != address(ETH_TOKEN_ADDRESS));

    ERC20Detailed token = ERC20Detailed(_tokenAddr);

    // Convert DAI into desired tokens
    uint256 actualTokenWithdrawn;
    uint256 actualDAIWithdrawn;
    (,, actualTokenWithdrawn, actualDAIWithdrawn) = __kyberTrade(dai, _amountInDAI, token);

    __withdraw(actualDAIWithdrawn);

    // Transfer tokens to user
    token.safeTransfer(msg.sender, actualTokenWithdrawn);

    // Emit event
    emit Withdraw(cycleNumber, msg.sender, _tokenAddr, actualTokenWithdrawn, actualDAIWithdrawn, now);
  }

  /**
   * @notice Redeems commission.
   */
  function redeemCommission(bool _inShares)
    public
    during(CyclePhase.Intermission)
    nonReentrant
  {
    uint256 commission = __redeemCommission();

    if (_inShares) {
      // Deposit commission into fund
      __deposit(commission);

      // Emit deposit event
      emit Deposit(cycleNumber, msg.sender, DAI_ADDR, commission, commission, now);
    } else {
      // Transfer the commission in DAI
      dai.safeTransfer(msg.sender, commission);
    }
  }

  /**
   * @notice Redeems commission for a particular cycle.
   * @param _inShares true to redeem in Betoken Shares, false to redeem in DAI
   * @param _cycle the cycle for which the commission will be redeemed.
   *        Commissions for a cycle will be redeemed during the Intermission phase of the next cycle, so _cycle must < cycleNumber.
   */
  function redeemCommissionForCycle(bool _inShares, uint256 _cycle)
    public
    during(CyclePhase.Intermission)
    nonReentrant
  {
    require(_cycle < cycleNumber);

    uint256 commission = __redeemCommissionForCycle(_cycle);

    if (_inShares) {
      // Deposit commission into fund
      __deposit(commission);

      // Emit deposit event
      emit Deposit(cycleNumber, msg.sender, DAI_ADDR, commission, commission, now);
    } else {
      // Transfer the commission in DAI
      dai.safeTransfer(msg.sender, commission);
    }
  }

  /**
   * @notice Sells tokens left over due to manager not selling or KyberNetwork not having enough volume. Callable by anyone. Money goes to developer.
   * @param _tokenAddr address of the token to be sold
   */
  function sellLeftoverToken(address _tokenAddr)
    public
    nonReentrant
    during(CyclePhase.Intermission)
    isValidToken(_tokenAddr)
  {
    ERC20Detailed token = ERC20Detailed(_tokenAddr);
    (,,uint256 actualDAIReceived,) = __kyberTrade(token, getBalance(token, address(this)), dai);
    totalFundsInDAI = totalFundsInDAI.add(actualDAIReceived);
  }

  /**
   * @notice Sells CompoundOrder left over due to manager not selling or KyberNetwork not having enough volume. Callable by anyone. Money goes to developer.
   * @param _orderAddress address of the CompoundOrder to be sold
   */
  function sellLeftoverCompoundOrder(address payable _orderAddress)
    public
    nonReentrant
    during(CyclePhase.Intermission)
  {
    // Load order info
    require(_orderAddress != address(0));
    CompoundOrder order = CompoundOrder(_orderAddress);
    require(order.isSold() == false && order.cycleNumber() < cycleNumber);

    // Sell short order
    // Not using outputAmount returned by order.sellOrder() because _orderAddress could point to a malicious contract
    uint256 beforeDAIBalance = dai.balanceOf(address(this));
    order.sellOrder(0, MAX_QTY);
    uint256 actualDAIReceived = dai.balanceOf(address(this)).sub(beforeDAIBalance);

    totalFundsInDAI = totalFundsInDAI.add(actualDAIReceived);
  }

  /**
   * @notice Burns the Kairo balance of a manager who has been inactive for a certain number of cycles
   * @param _deadman the manager whose Kairo balance will be burned
   */
  function burnDeadman(address _deadman)
    public
    nonReentrant
    during(CyclePhase.Intermission)
  {
    require(_deadman != address(this));
    require(cycleNumber.sub(lastActiveCycle[_deadman]) >= INACTIVE_THRESHOLD);
    require(cToken.destroyTokens(_deadman, cToken.balanceOf(_deadman)));
  }

  /**
   * Manage phase functions
   */

  /**
   * @notice Creates a new investment for an ERC20 token.
   * @param _tokenAddress address of the ERC20 token contract
   * @param _stake amount of Kairos to be staked in support of the investment
   * @param _minPrice the minimum price for the trade
   * @param _maxPrice the maximum price for the trade
   */
  function createInvestment(
    address _tokenAddress,
    uint256 _stake,
    uint256 _minPrice,
    uint256 _maxPrice
  )
    public
    nonReentrant
    isValidToken(_tokenAddress)
    during(CyclePhase.Manage)
  {
    (bool success,) = betokenLogic.delegatecall(abi.encodeWithSelector(this.createInvestment.selector, _tokenAddress, _stake, _minPrice, _maxPrice));
    if (!success) { revert(); }
  }

  /**
   * @notice Called by user to sell the assets an investment invested in. Returns the staked Kairo plus rewards/penalties to the user.
   *         The user can sell only part of the investment by changing _tokenAmount.
   * @dev When selling only part of an investment, the old investment would be "fully" sold and a new investment would be created with
   *   the original buy price and however much tokens that are not sold.
   * @param _investmentId the ID of the investment
   * @param _tokenAmount the amount of tokens to be sold.
   * @param _minPrice the minimum price for the trade
   * @param _maxPrice the maximum price for the trade
   */
  function sellInvestmentAsset(
    uint256 _investmentId,
    uint256 _tokenAmount,
    uint256 _minPrice,
    uint256 _maxPrice
  )
    public
    during(CyclePhase.Manage)
    nonReentrant
  {
    (bool success,) = betokenLogic.delegatecall(abi.encodeWithSelector(this.sellInvestmentAsset.selector, _investmentId, _tokenAmount, _minPrice, _maxPrice));
    if (!success) { revert(); }
  }

  /**
   * @notice Creates a new Compound order to either short or leverage long a token.
   * @param _orderType true for a short order, false for a levarage long order
   * @param _tokenAddress address of the Compound token to be traded
   * @param _stake amount of Kairos to be staked
   * @param _minPrice the minimum token price for the trade
   * @param _maxPrice the maximum token price for the trade
   */
  function createCompoundOrder(
    bool _orderType,
    address _tokenAddress,
    uint256 _stake,
    uint256 _minPrice,
    uint256 _maxPrice
  )
    public
    nonReentrant
    during(CyclePhase.Manage)
    isValidToken(_tokenAddress)
  {
    (bool success,) = betokenLogic.delegatecall(abi.encodeWithSelector(this.createCompoundOrder.selector, _orderType, _tokenAddress, _stake, _minPrice, _maxPrice));
    if (!success) { revert(); }
  }

  /**
   * @notice Sells a compound order
   * @param _orderId the ID of the order to be sold (index in userCompoundOrders[msg.sender])
   * @param _minPrice the minimum token price for the trade
   * @param _maxPrice the maximum token price for the trade
   */
  function sellCompoundOrder(
    uint256 _orderId,
    uint256 _minPrice,
    uint256 _maxPrice
  )
    public
    during(CyclePhase.Manage)
    nonReentrant
  {
    (bool success,) = betokenLogic.delegatecall(abi.encodeWithSelector(this.sellCompoundOrder.selector, _orderId, _minPrice, _maxPrice));
    if (!success) { revert(); }
  }

  /**
   * @notice Repys debt for a Compound order to prevent the collateral ratio from dropping below threshold.
   * @param _orderId the ID of the Compound order
   * @param _repayAmountInDAI amount of DAI to use for repaying debt
   */
  function repayCompoundOrder(uint256 _orderId, uint256 _repayAmountInDAI) public during(CyclePhase.Manage) nonReentrant {
    (bool success,) = betokenLogic.delegatecall(abi.encodeWithSelector(this.repayCompoundOrder.selector, _orderId, _repayAmountInDAI));
    if (!success) { revert(); }
  }

  /**
   * Internal use functions
   */

  // MiniMe TokenController functions, not used right now
  /**
   * @notice Called when `_owner` sends ether to the MiniMe Token contract
   * @param _owner The address that sent the ether to create tokens
   * @return True if the ether is accepted, false if it throws
   */
  function proxyPayment(address _owner) public payable returns(bool) {
    return false;
  }

  /**
   * @notice Notifies the controller about a token transfer allowing the
   *  controller to react if desired
   * @param _from The origin of the transfer
   * @param _to The destination of the transfer
   * @param _amount The amount of the transfer
   * @return False if the controller does not authorize the transfer
   */
  function onTransfer(address _from, address _to, uint _amount) public returns(bool) {
    return true;
  }

  /**
   * @notice Notifies the controller about an approval allowing the
   *  controller to react if desired
   * @param _owner The address that calls `approve()`
   * @param _spender The spender in the `approve()` call
   * @param _amount The amount in the `approve()` call
   * @return False if the controller does not authorize the approval
   */
  function onApprove(address _owner, address _spender, uint _amount) public
      returns(bool) {
    return true;
  }

  /**
   * @notice Handles deposits by minting Betoken Shares & updating total funds.
   * @param _depositDAIAmount The amount of the deposit in DAI
   */
  function __deposit(uint256 _depositDAIAmount) internal {
    // Register investment and give shares
    if (sToken.totalSupply() == 0 || totalFundsInDAI == 0) {
      require(sToken.generateTokens(msg.sender, _depositDAIAmount));
    } else {
      require(sToken.generateTokens(msg.sender, _depositDAIAmount.mul(sToken.totalSupply()).div(totalFundsInDAI)));
    }
    totalFundsInDAI = totalFundsInDAI.add(_depositDAIAmount);
  }

  /**
   * @notice Handles deposits by burning Betoken Shares & updating total funds.
   * @param _withdrawDAIAmount The amount of the withdrawal in DAI
   */
  function __withdraw(uint256 _withdrawDAIAmount) internal {
    // Burn Shares
    require(sToken.destroyTokens(msg.sender, _withdrawDAIAmount.mul(sToken.totalSupply()).div(totalFundsInDAI)));
    totalFundsInDAI = totalFundsInDAI.sub(_withdrawDAIAmount);
  }

  /**
   * @notice Redeems the commission for all previous cycles. Updates the related variables.
   * @return the amount of commission to be redeemed
   */
  function __redeemCommission() internal returns (uint256 _commission) {
    require(lastCommissionRedemption[msg.sender] < cycleNumber);

    uint256 penalty; // penalty received for not taking enough risk
    (_commission, penalty) = commissionBalanceOf(msg.sender);

    // record the redemption to prevent double-redemption
    for (uint256 i = lastCommissionRedemption[msg.sender]; i < cycleNumber; i = i.add(1)) {
      hasRedeemedCommissionForCycle[msg.sender][i] = true;
    }
    lastCommissionRedemption[msg.sender] = cycleNumber;

    // record the decrease in commission pool
    totalCommissionLeft = totalCommissionLeft.sub(_commission);
    // include commission penalty to this cycle's total commission pool
    totalCommissionOfCycle[cycleNumber] = totalCommissionOfCycle[cycleNumber].add(penalty);
    // clear investment arrays to save space
    delete userInvestments[msg.sender];
    delete userCompoundOrders[msg.sender];

    emit CommissionPaid(cycleNumber, msg.sender, _commission);
  }

  /**
   * @notice Redeems commission for a particular cycle. Updates the related variables.
   * @param _cycle the cycle for which the commission will be redeemed
   * @return the amount of commission to be redeemed
   */
  function __redeemCommissionForCycle(uint256 _cycle) internal returns (uint256 _commission) {
    require(!hasRedeemedCommissionForCycle[msg.sender][_cycle]);

    uint256 penalty; // penalty received for not taking enough risk
    (_commission, penalty) = commissionOfAt(msg.sender, _cycle);

    hasRedeemedCommissionForCycle[msg.sender][_cycle] = true;

    // record the decrease in commission pool
    totalCommissionLeft = totalCommissionLeft.sub(_commission);
    // include commission penalty to this cycle's total commission pool
    totalCommissionOfCycle[cycleNumber] = totalCommissionOfCycle[cycleNumber].add(penalty);
    // clear investment arrays to save space
    delete userInvestments[msg.sender];
    delete userCompoundOrders[msg.sender];

    emit CommissionPaid(_cycle, msg.sender, _commission);
  }

  function() external payable {}
}

Contract Security Audit

Contract ABI

[{"constant":false,"inputs":[],"name":"migrateOwnedContractsToNextVersion","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nextVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderId","type":"uint256"},{"name":"_repayAmountInDAI","type":"uint256"}],"name":"repayCompoundOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_inSupport","type":"bool"}],"name":"signalUpgrade","outputs":[{"name":"_success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalFundsInDAI","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderAddress","type":"address"}],"name":"sellLeftoverCompoundOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isKyberToken","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"devFundingRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_tokenAddr","type":"address"}],"name":"sellLeftoverToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"COMMISSION_RATE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderId","type":"uint256"},{"name":"_minPrice","type":"uint256"},{"name":"_maxPrice","type":"uint256"}],"name":"sellCompoundOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_orderType","type":"bool"},{"name":"_tokenAddress","type":"address"},{"name":"_stake","type":"uint256"},{"name":"_minPrice","type":"uint256"},{"name":"_maxPrice","type":"uint256"}],"name":"createCompoundOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"startTimeOfCyclePhase","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isCompoundToken","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalVotingWeight","outputs":[{"name":"_weight","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"betokenLogic","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newProp","type":"uint256"}],"name":"changeDeveloperFeeRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenAddress","type":"address"},{"name":"_stake","type":"uint256"},{"name":"_minPrice","type":"uint256"},{"name":"_maxPrice","type":"uint256"}],"name":"createInvestment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"address"}],"name":"upgradeSignal","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_donationInTokens","type":"uint256"}],"name":"registerWithToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"QUORUM","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cycleNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_BUY_KRO_PROP","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_inShares","type":"bool"},{"name":"_cycle","type":"uint256"}],"name":"redeemCommissionForCycle","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_deadman","type":"address"}],"name":"burnDeadman","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenAddr","type":"address"},{"name":"_tokenAmount","type":"uint256"}],"name":"depositToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidates","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_daiAmount","type":"uint256"}],"name":"depositDAI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_chunkNumber","type":"uint256"},{"name":"_inSupport","type":"bool"}],"name":"voteOnCandidate","outputs":[{"name":"_success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amountInDAI","type":"uint256"}],"name":"withdrawEther","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_manager","type":"address"}],"name":"commissionBalanceOf","outputs":[{"name":"_commission","type":"uint256"},{"name":"_penalty","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"nextPhase","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_candidate","type":"address"}],"name":"developerInitiateUpgrade","outputs":[{"name":"_success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"userCompoundOrders","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getPhaseLengths","outputs":[{"name":"_phaseLengths","type":"uint256[2]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_donationInDAI","type":"uint256"}],"name":"registerWithDAI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"CYCLES_TILL_MATURITY","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MIN_RISK_TIME","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"phaseLengths","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"baseRiskStakeFallback","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"againstVotes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hasFinalizedNextVersion","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposers","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"proposersVotingWeight","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"COLLATERAL_RATIO_MODIFIER","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_userAddr","type":"address"}],"name":"investmentsCount","outputs":[{"name":"_count","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_investmentId","type":"uint256"},{"name":"_tokenAmount","type":"uint256"},{"name":"_minPrice","type":"uint256"},{"name":"_maxPrice","type":"uint256"}],"name":"sellInvestmentAsset","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"totalCommissionOfCycle","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"lastCommissionRedemption","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_manager","type":"address"},{"name":"_cycle","type":"uint256"}],"name":"commissionOfAt","outputs":[{"name":"_commission","type":"uint256"},{"name":"_penalty","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PROPOSE_SUBCHUNK_SIZE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_kyberTokens","type":"address[]"},{"name":"_compoundTokens","type":"address[]"},{"name":"_positionTokens","type":"address[]"}],"name":"initTokenListings","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PERM_HINT","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kairoPrice","outputs":[{"name":"_kairoPrice","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"userInvestments","outputs":[{"name":"tokenAddress","type":"address"},{"name":"cycleNumber","type":"uint256"},{"name":"stake","type":"uint256"},{"name":"tokenAmount","type":"uint256"},{"name":"buyPrice","type":"uint256"},{"name":"sellPrice","type":"uint256"},{"name":"buyTime","type":"uint256"},{"name":"buyCostInDAI","type":"uint256"},{"name":"isSold","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"upgradeSignalStrength","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isPositionToken","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_proxyAddr","type":"address"}],"name":"setProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"depositEther","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"compoundFactoryAddr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_amountInDAI","type":"uint256"}],"name":"withdrawDAI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_chunkNumber","type":"uint256"},{"name":"_candidate","type":"address"}],"name":"proposeCandidate","outputs":[{"name":"_success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentSubchunk","outputs":[{"name":"_subchunk","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_tokenAddr","type":"address"},{"name":"_amountInDAI","type":"uint256"}],"name":"withdrawToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"proxyAddr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_inShares","type":"bool"}],"name":"redeemCommission","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"NEXT_PHASE_REWARD","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"managePhaseEndBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalCommissionLeft","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newAddr","type":"address"}],"name":"changeDeveloperFeeAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ASSET_FEE_RATE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MIN_KRO_PRICE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_userAddr","type":"address"}],"name":"compoundOrdersCount","outputs":[{"name":"_count","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"INACTIVE_THRESHOLD","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hasInitializedTokenListings","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_assetAddress","type":"address"}],"name":"transferAssetToNextVersion","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"riskTakenInCycle","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"registerWithETH","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"KYBER_ADDR","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FALLBACK_MAX_DONATION","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"hasRedeemedCommissionForCycle","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_chunkNumber","type":"uint256"}],"name":"finalizeSuccessfulVote","outputs":[{"name":"_success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_of","type":"address"}],"name":"getVotingWeight","outputs":[{"name":"_weight","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"shareTokenAddr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DAI_ADDR","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"onApprove","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"previousVersion","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"upgradeVotingActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"controlTokenAddr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"listKyberToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"CHUNK_SIZE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"forVotes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentChunk","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"},{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"managerVotes","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"proxyPayment","outputs":[{"name":"","type":"bool"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"VOTE_SUCCESS_THRESHOLD","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cyclePhase","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"lastActiveCycle","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"devFundingAccount","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_kroAddr","type":"address"},{"name":"_sTokenAddr","type":"address"},{"name":"_devFundingAccount","type":"address"},{"name":"_phaseLengths","type":"uint256[2]"},{"name":"_devFundingRate","type":"uint256"},{"name":"_previousVersion","type":"address"},{"name":"_daiAddr","type":"address"},{"name":"_kyberAddr","type":"address"},{"name":"_compoundFactoryAddr","type":"address"},{"name":"_betokenLogic","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_newPhase","type":"uint256"},{"indexed":false,"name":"_timestamp","type":"uint256"},{"indexed":false,"name":"_totalFundsInDAI","type":"uint256"}],"name":"ChangedPhase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_tokenAddress","type":"address"},{"indexed":false,"name":"_tokenAmount","type":"uint256"},{"indexed":false,"name":"_daiAmount","type":"uint256"},{"indexed":false,"name":"_timestamp","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_tokenAddress","type":"address"},{"indexed":false,"name":"_tokenAmount","type":"uint256"},{"indexed":false,"name":"_daiAmount","type":"uint256"},{"indexed":false,"name":"_timestamp","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_id","type":"uint256"},{"indexed":false,"name":"_tokenAddress","type":"address"},{"indexed":false,"name":"_stakeInWeis","type":"uint256"},{"indexed":false,"name":"_buyPrice","type":"uint256"},{"indexed":false,"name":"_costDAIAmount","type":"uint256"},{"indexed":false,"name":"_tokenAmount","type":"uint256"}],"name":"CreatedInvestment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_id","type":"uint256"},{"indexed":false,"name":"_tokenAddress","type":"address"},{"indexed":false,"name":"_receivedKairo","type":"uint256"},{"indexed":false,"name":"_sellPrice","type":"uint256"},{"indexed":false,"name":"_earnedDAIAmount","type":"uint256"}],"name":"SoldInvestment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_id","type":"uint256"},{"indexed":false,"name":"_order","type":"address"},{"indexed":false,"name":"_orderType","type":"bool"},{"indexed":false,"name":"_tokenAddress","type":"address"},{"indexed":false,"name":"_stakeInWeis","type":"uint256"},{"indexed":false,"name":"_costDAIAmount","type":"uint256"}],"name":"CreatedCompoundOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_id","type":"uint256"},{"indexed":false,"name":"_order","type":"address"},{"indexed":false,"name":"_orderType","type":"bool"},{"indexed":false,"name":"_tokenAddress","type":"address"},{"indexed":false,"name":"_receivedKairo","type":"uint256"},{"indexed":false,"name":"_earnedDAIAmount","type":"uint256"}],"name":"SoldCompoundOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_id","type":"uint256"},{"indexed":false,"name":"_order","type":"address"},{"indexed":false,"name":"_repaidDAIAmount","type":"uint256"}],"name":"RepaidCompoundOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_commission","type":"uint256"}],"name":"CommissionPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":false,"name":"_totalCommissionInDAI","type":"uint256"}],"name":"TotalCommissionPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_manager","type":"address"},{"indexed":false,"name":"_donationInDAI","type":"uint256"},{"indexed":false,"name":"_kairoReceived","type":"uint256"}],"name":"Register","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":true,"name":"_inSupport","type":"bool"}],"name":"SignaledUpgrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":false,"name":"_candidate","type":"address"}],"name":"DeveloperInitiatedUpgrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"}],"name":"InitiatedUpgrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_voteID","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_candidate","type":"address"}],"name":"ProposedCandidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":true,"name":"_voteID","type":"uint256"},{"indexed":true,"name":"_sender","type":"address"},{"indexed":false,"name":"_inSupport","type":"bool"},{"indexed":false,"name":"_weight","type":"uint256"}],"name":"Voted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_cycleNumber","type":"uint256"},{"indexed":false,"name":"_nextVersion","type":"address"}],"name":"FinalizedNextVersion","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]

60806040523480156200001157600080fd5b50604051610160806200613283398101806040526101608110156200003557600080fd5b508051602082015160408084015160a085015160c086015160e08701516101008801516101208901516101408a0151600080546001600160a01b031916331780825598519a9b999a979960600198969795969495939492939192869286926001600160a01b039290921691907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a360018055603880546001600160a01b03199081166001600160a01b039485169081179092556039805482169385169384179055603a80548216909217909155603b8054821690921790915560028054610100600160a81b0319166101008e8516021781556003805483168d851617905560078054909216928b169290921790556200015690600e908990620001d8565b50600c95909555601c805460ff19166001179055600580546001600160a01b039283166001600160a01b03199182161790915560068054968316968216969096179095556008805494821694861694909417909355505060358054968216968316969096179095556036805494909516931692909217909255506200023b9050565b826002810192821562000209579160200282015b8281111562000209578251825591602001919060010190620001ec565b50620002179291506200021b565b5090565b6200023891905b8082111562000217576000815560010162000222565b90565b615ee7806200024b6000396000f3fe6080604052600436106105fa5760003560e01c80638606c91a1161030e578063b7ac4ff31161019b578063db77839b116100e7578063ee00f705116100a0578063f49008631161007a578063f490086314610d8e578063f6558b0014611767578063fa845ca91461177c578063fbf35f46146117af576105fa565b8063ee00f705146116bf578063f2fde38b1461170e578063f48c305414611741576105fa565b8063db77839b14611623578063dc87454c14611638578063e1024b4d1461164d578063e91e13a914610c9e578063e96e22b914611680578063e9fc335d146116aa576105fa565b8063ce977bc211610154578063d7615d371161012e578063d7615d37146115e4578063d95393eb146115f9578063da682aeb14610c1c578063db3d1ccf1461160e576105fa565b8063ce977bc21461154e578063d2ec1fe714611587578063d5da24b9146115b1576105fa565b8063b7ac4ff31461149b578063b8fc41ac146114b0578063bdbcb576146114e3578063bf8519bd1461151c578063cb0ef21d14611524578063cdf8b9f814611539576105fa565b80639bcc8e7b1161025a578063a940646d11610213578063b1ace0b0116101ed578063b1ace0b014611429578063b38ca2f21461143e578063b4230d1a14611453578063b5050ea814611486576105fa565b8063a940646d146113b7578063ae2f89c2146113e1578063b18e8a8d146113f6576105fa565b80639bcc8e7b146112b65780639c3f1150146112ef5780639e281a9814611328578063a03040c314611361578063a6f561ec14611376578063a8b6b2b6146113a2576105fa565b80639244adcd116102c757806397107d6d116102a157806397107d6d1461123c57806398ea5fca1461126f5780639a8a2145146112775780639add74381461128c576105fa565b80639244adcd1461115357806392bba1fc146111df57806392d64c9d14611209576105fa565b80638606c91a14610ebd5780638b14799d14610ed25780638b98a2c51461108a5780638da5cb5b146111145780638f32d59b146111295780638feb82ba1461113e576105fa565b80633477ee2e1161048c57806356f7e7ff116103d8578063675fb9c411610391578063715018a61161036b578063715018a614610e125780637cd9fb1c14610e27578063821f982414610e51578063852a89d514610e84576105fa565b8063675fb9c414610d8e57806368063a7414610da35780637113aef214610dd6576105fa565b806356f7e7ff14610cb35780635825b04c14610cdd5780635ebad71414610d105780635f88967b14610d3a578063623e3d1a14610d4f578063627d50df14610d79576105fa565b80633f677210116104455780634a3931491161041f5780634a39314914610c1c5780634b25fe9214610c5f5780634cc0fc3914610c895780634f2094a114610c9e576105fa565b80633f67721014610b60578063404c568f14610b93578063407fa2a314610bcc576105fa565b80633477ee2e14610a4f578063365833e114610a79578063381f253c14610aa35780633bed33ce14610ad55780633d98147414610aff5780633eadb6db14610b4b576105fa565b80632893f5cc1161054b5780632e1ed949116105045780632f9fb6a4116104de5780632f9fb6a41461099c5780632fcfb8ab146109b157806331f55422146109e3578063338b5dea14610a16576105fa565b80632e1ed949146109395780632e80d9b6146109725780632f88471014610987576105fa565b80632893f5cc1461083457806328ad7cef146108675780632914af341461087c5780632a5addf3146108915780632b23c8a0146108bb5780632df182c914610900576105fa565b80630e187cac116105b85780631a454ea6116105925780631a454ea6146107875780631f5c6a511461079c57806322d40045146107d257806325f842c51461081f576105fa565b80630e187cac1461070c57806313d3d00e1461073f578063173e770714610754576105fa565b806276b283146105fc5780630bafd60e146106115780630c06b1e1146106425780630c99c9ea146106725780630cba5355146106b25780630d52aeec146106d9575b005b34801561060857600080fd5b506105fa6117c4565b34801561061d57600080fd5b506106266119ad565b604080516001600160a01b039092168252519081900360200190f35b34801561064e57600080fd5b506105fa6004803603604081101561066557600080fd5b50803590602001356119c3565b34801561067e57600080fd5b5061069e6004803603602081101561069557600080fd5b50351515611b26565b604080519115158252519081900360200190f35b3480156106be57600080fd5b506106c7611c75565b60408051918252519081900360200190f35b3480156106e557600080fd5b506105fa600480360360208110156106fc57600080fd5b50356001600160a01b0316611c7b565b34801561071857600080fd5b5061069e6004803603602081101561072f57600080fd5b50356001600160a01b0316611f9b565b34801561074b57600080fd5b506106c7611fb0565b34801561076057600080fd5b506105fa6004803603602081101561077757600080fd5b50356001600160a01b0316611fb6565b34801561079357600080fd5b506106c761205e565b3480156107a857600080fd5b506105fa600480360360608110156107bf57600080fd5b508035906020810135906040013561206a565b3480156107de57600080fd5b506105fa600480360360a08110156107f557600080fd5b5080351515906001600160a01b0360208201351690604081013590606081013590608001356121d5565b34801561082b57600080fd5b506106c761239b565b34801561084057600080fd5b5061069e6004803603602081101561085757600080fd5b50356001600160a01b03166123a1565b34801561087357600080fd5b506106c76123b6565b34801561088857600080fd5b50610626612448565b34801561089d57600080fd5b506105fa600480360360208110156108b457600080fd5b5035612457565b3480156108c757600080fd5b506105fa600480360360808110156108de57600080fd5b506001600160a01b0381351690602081013590604081013590606001356124c8565b34801561090c57600080fd5b5061069e6004803603604081101561092357600080fd5b50803590602001356001600160a01b0316612680565b34801561094557600080fd5b506105fa6004803603604081101561095c57600080fd5b506001600160a01b0381351690602001356126a0565b34801561097e57600080fd5b506106c76127eb565b34801561099357600080fd5b506106c76127f7565b3480156109a857600080fd5b506106c76127fd565b3480156109bd57600080fd5b506105fa600480360360408110156109d457600080fd5b50803515159060200135612808565b3480156109ef57600080fd5b506105fa60048036036020811015610a0657600080fd5b50356001600160a01b03166128c4565b348015610a2257600080fd5b506105fa60048036036040811015610a3957600080fd5b506001600160a01b038135169060200135612a8a565b348015610a5b57600080fd5b5061062660048036036020811015610a7257600080fd5b5035612c5a565b348015610a8557600080fd5b506105fa60048036036020811015610a9c57600080fd5b5035612c77565b348015610aaf57600080fd5b5061069e60048036036040811015610ac657600080fd5b50803590602001351515612d6a565b348015610ae157600080fd5b506105fa60048036036020811015610af857600080fd5b5035612ec2565b348015610b0b57600080fd5b50610b3260048036036020811015610b2257600080fd5b50356001600160a01b0316612ff8565b6040805192835260208301919091528051918290030190f35b348015610b5757600080fd5b506105fa6130ca565b348015610b6c57600080fd5b5061069e60048036036020811015610b8357600080fd5b50356001600160a01b03166131a1565b348015610b9f57600080fd5b5061062660048036036040811015610bb657600080fd5b506001600160a01b03813516906020013561329a565b348015610bd857600080fd5b50610be16132cf565b6040518082600260200280838360005b83811015610c09578181015183820152602001610bf1565b5050505090500191505060405180910390f35b348015610c2857600080fd5b5061069e60048036036060811015610c3f57600080fd5b506001600160a01b03813581169160208101359091169060400135613309565b348015610c6b57600080fd5b506105fa60048036036020811015610c8257600080fd5b5035613312565b348015610c9557600080fd5b506106c7613402565b348015610caa57600080fd5b506106c7613407565b348015610cbf57600080fd5b506106c760048036036020811015610cd657600080fd5b503561340e565b348015610ce957600080fd5b506106c760048036036020811015610d0057600080fd5b50356001600160a01b0316613422565b348015610d1c57600080fd5b506106c760048036036020811015610d3357600080fd5b5035613434565b348015610d4657600080fd5b5061069e613441565b348015610d5b57600080fd5b5061062660048036036020811015610d7257600080fd5b503561344f565b348015610d8557600080fd5b506106c761345c565b348015610d9a57600080fd5b506106c7613462565b348015610daf57600080fd5b506106c760048036036020811015610dc657600080fd5b50356001600160a01b031661346e565b348015610de257600080fd5b506105fa60048036036080811015610df957600080fd5b508035906020810135906040810135906060013561348d565b348015610e1e57600080fd5b506105fa6135f8565b348015610e3357600080fd5b506106c760048036036020811015610e4a57600080fd5b503561368c565b348015610e5d57600080fd5b506106c760048036036020811015610e7457600080fd5b50356001600160a01b031661369e565b348015610e9057600080fd5b50610b3260048036036040811015610ea757600080fd5b506001600160a01b0381351690602001356136b0565b348015610ec957600080fd5b506106c76139fd565b348015610ede57600080fd5b506105fa60048036036060811015610ef557600080fd5b810190602081018135640100000000811115610f1057600080fd5b820183602082011115610f2257600080fd5b80359060200191846020830284011164010000000083111715610f4457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610f9457600080fd5b820183602082011115610fa657600080fd5b80359060200191846020830284011164010000000083111715610fc857600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561101857600080fd5b82018360208201111561102a57600080fd5b8035906020019184602083028401116401000000008311171561104c57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613a04945050505050565b34801561109657600080fd5b5061109f613b93565b6040805160208082528351818301528351919283929083019185019080838360005b838110156110d95781810151838201526020016110c1565b50505050905090810190601f1680156111065780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561112057600080fd5b50610626613bb6565b34801561113557600080fd5b5061069e613bc5565b34801561114a57600080fd5b506106c7613bd6565b34801561115f57600080fd5b5061118c6004803603604081101561117657600080fd5b506001600160a01b038135169060200135613d1a565b604080516001600160a01b03909a168a5260208a0198909852888801969096526060880194909452608087019290925260a086015260c085015260e0840152151561010083015251908190036101200190f35b3480156111eb57600080fd5b506106c76004803603602081101561120257600080fd5b5035613d8c565b34801561121557600080fd5b5061069e6004803603602081101561122c57600080fd5b50356001600160a01b0316613d9e565b34801561124857600080fd5b506105fa6004803603602081101561125f57600080fd5b50356001600160a01b0316613db3565b6105fa613e52565b34801561128357600080fd5b50610626613fa9565b34801561129857600080fd5b506105fa600480360360208110156112af57600080fd5b5035613fb8565b3480156112c257600080fd5b5061069e600480360360408110156112d957600080fd5b50803590602001356001600160a01b03166140a7565b3480156112fb57600080fd5b5061130461415e565b6040518082600181111561131457fe5b60ff16815260200191505060405180910390f35b34801561133457600080fd5b506105fa6004803603604081101561134b57600080fd5b506001600160a01b0381351690602001356141af565b34801561136d57600080fd5b50610626614345565b34801561138257600080fd5b506105fa6004803603602081101561139957600080fd5b50351515614354565b3480156113ae57600080fd5b506106c7614401565b3480156113c357600080fd5b506106c7600480360360208110156113da57600080fd5b503561440d565b3480156113ed57600080fd5b506106c761441f565b34801561140257600080fd5b506105fa6004803603602081101561141957600080fd5b50356001600160a01b0316614425565b34801561143557600080fd5b506106c76144bb565b34801561144a57600080fd5b506106c76144c6565b34801561145f57600080fd5b506106c76004803603602081101561147657600080fd5b50356001600160a01b03166144d2565b34801561149257600080fd5b506106c76144ed565b3480156114a757600080fd5b5061069e6144f2565b3480156114bc57600080fd5b506105fa600480360360208110156114d357600080fd5b50356001600160a01b03166144fb565b3480156114ef57600080fd5b506106c76004803603604081101561150657600080fd5b506001600160a01b0381351690602001356146cc565b6105fa6146e9565b34801561153057600080fd5b50610626614812565b34801561154557600080fd5b506106c7614821565b34801561155a57600080fd5b5061069e6004803603604081101561157157600080fd5b506001600160a01b03813516906020013561482e565b34801561159357600080fd5b5061069e600480360360208110156115aa57600080fd5b503561484e565b3480156115bd57600080fd5b506106c7600480360360208110156115d457600080fd5b50356001600160a01b03166148fd565b3480156115f057600080fd5b506106266149e4565b34801561160557600080fd5b506106266149f3565b34801561161a57600080fd5b50610626614a02565b34801561162f57600080fd5b5061069e614a11565b34801561164457600080fd5b50610626614a20565b34801561165957600080fd5b506105fa6004803603602081101561167057600080fd5b50356001600160a01b0316614a34565b34801561168c57600080fd5b506106c7600480360360208110156116a357600080fd5b5035614aa2565b3480156116b657600080fd5b506106c7614aaf565b3480156116cb57600080fd5b506116fe600480360360608110156116e257600080fd5b508035906001600160a01b036020820135169060400135614ae7565b6040518082600281111561131457fe5b34801561171a57600080fd5b506105fa6004803603602081101561173157600080fd5b50356001600160a01b0316614b2a565b61069e6004803603602081101561175757600080fd5b50356001600160a01b0316614b7d565b34801561177357600080fd5b50611304614b83565b34801561178857600080fd5b506106c76004803603602081101561179f57600080fd5b50356001600160a01b0316614b8c565b3480156117bb57600080fd5b50610626614b9e565b600180548101808255601c54909161010090910460ff161515146117e757600080fd5b61180a600e60005b600281106117f957fe5b0154600b549063ffffffff614bad16565b421161181557600080fd5b603554601c5460408051600160e01b63f2fde38b02815263010000009092046001600160a01b039081166004840152905192169163f2fde38b9160248082019260009290919082900301818387803b15801561187057600080fd5b505af1158015611884573d6000803e3d6000fd5b5050603654601c5460408051600160e01b63f2fde38b02815263010000009092046001600160a01b03908116600484015290519216935063f2fde38b925060248082019260009290919082900301818387803b1580156118e357600080fd5b505af11580156118f7573d6000803e3d6000fd5b50505050603760009054906101000a90046001600160a01b03166001600160a01b0316631aa3ba166040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561194b57600080fd5b505af115801561195f573d6000803e3d6000fd5b5050505060015481146119aa5760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b50565b601c54630100000090046001600160a01b031681565b600180601c5460ff1660018111156119d757fe5b146119e157600080fd5b600180548101908190556006546040805160248101879052604480820187905282518083039091018152606490910182526020810180516001600160e01b0316600160e01b630c06b1e102178152915181516000946001600160a01b03169382918083835b60208310611a655780518252601f199092019160209182019101611a46565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114611ac5576040519150601f19603f3d011682016040523d82523d6000602084013e611aca565b606091505b5050905080611ad857600080fd5b506001548114611b205760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b50505050565b60008080601c5460ff166001811115611b3b57fe5b14611b4557600080fd5b601c54610100900460ff1615611b5a57600080fd5b6006546040805185151560248083019190915282518083039091018152604490910182526020810180516001600160e01b0316600160e11b63064ce4f502178152915181516000946060946001600160a01b039091169392918291908083835b60208310611bd95780518252601f199092019160209182019101611bba565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114611c39576040519150601f19603f3d011682016040523d82523d6000602084013e611c3e565b606091505b509150915081611c5357600093505050611c6f565b808060200190516020811015611c6857600080fd5b5051935050505b50919050565b600a5481565b60018054810190819055600080601c5460ff166001811115611c9957fe5b14611ca357600080fd5b6001600160a01b038316611cb657600080fd5b6000839050806001600160a01b031663e852e7416040518163ffffffff1660e01b815260040160206040518083038186803b158015611cf457600080fd5b505afa158015611d08573d6000803e3d6000fd5b505050506040513d6020811015611d1e57600080fd5b5051158015611d925750600954816001600160a01b0316632f8847106040518163ffffffff1660e01b815260040160206040518083038186803b158015611d6457600080fd5b505afa158015611d78573d6000803e3d6000fd5b505050506040513d6020811015611d8e57600080fd5b5051105b611d9b57600080fd5b603a5460408051600160e01b6370a0823102815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611de957600080fd5b505afa158015611dfd573d6000803e3d6000fd5b505050506040513d6020811015611e1357600080fd5b505160408051600160e11b6366b0d4ad0281526000600482018190526b204fce5e3e25026110000000602483015282519394506001600160a01b0386169363cd61a95a936044808501949193918390030190829087803b158015611e7657600080fd5b505af1158015611e8a573d6000803e3d6000fd5b505050506040513d6040811015611ea057600080fd5b5050603a5460408051600160e01b6370a082310281523060048201529051600092611f319285926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015611ef957600080fd5b505afa158015611f0d573d6000803e3d6000fd5b505050506040513d6020811015611f2357600080fd5b50519063ffffffff614c1316565b600a54909150611f47908263ffffffff614bad16565b600a55505060015483149150611f9790505760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b5050565b60196020526000908152604090205460ff1681565b600c5481565b60018054810190819055600080601c5460ff166001811115611fd457fe5b14611fde57600080fd5b826001600160a01b038116611ff257600080fd5b6001600160a01b038116600080516020615dfc833981519152146120225761201981614c73565b61202257600080fd5b836000612044826120338130614c96565b603a546001600160a01b0316614d51565b5092505050611f4781600a54614bad90919063ffffffff16565b6702c68af0bb14000081565b600180601c5460ff16600181111561207e57fe5b1461208857600080fd5b60018054810190819055600654604080516024810188905260448101879052606480820187905282518083039091018152608490910182526020810180516001600160e01b0316600160e01b631f5c6a5102178152915181516000946001600160a01b03169382918083835b602083106121135780518252601f1990920191602091820191016120f4565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114612173576040519150601f19603f3d011682016040523d82523d6000602084013e612178565b606091505b505090508061218657600080fd5b5060015481146121ce5760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b5050505050565b6001805481018082559080601c5460ff1660018111156121f157fe5b146121fb57600080fd5b856001600160a01b03811661220f57600080fd5b6001600160a01b038116600080516020615dfc8339815191521461223f5761223681614c73565b61223f57600080fd5b600654604080518a151560248201526001600160a01b038a81166044830152606482018a90526084820189905260a48083018990528351808403909101815260c490920183526020820180516001600160e01b0316600160e01b6322d400450217815292518251600095929092169390918291908083835b602083106122d65780518252601f1990920191602091820191016122b7565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114612336576040519150601f19603f3d011682016040523d82523d6000602084013e61233b565b606091505b505090508061234957600080fd5b50505060015481146123935760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b505050505050565b600b5481565b601a6020526000908152604090205460ff1681565b60006003600954116123ca57506000612445565b60315460355460095461244292916001600160a01b03169063981b24d0906017906000906123ff90600363ffffffff614c1316565b8152602001908152602001600020546040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611ef957600080fd5b90505b90565b6006546001600160a01b031681565b61245f613bc5565b6124a15760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b670de0b6b3a764000081106124b557600080fd5b600c5481106124c357600080fd5b600c55565b60018054810190819055846001600160a01b0381166124e657600080fd5b6001600160a01b038116600080516020615dfc833981519152146125165761250d81614c73565b61251657600080fd5b600180601c5460ff16600181111561252a57fe5b1461253457600080fd5b600654604080516001600160a01b038a81166024830152604482018a90526064820189905260848083018990528351808403909101815260a490920183526020820180516001600160e01b0316600160e51b6301591e450217815292518251600095929092169390918291908083835b602083106125c35780518252601f1990920191602091820191016125a4565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114612623576040519150601f19603f3d011682016040523d82523d6000602084013e612628565b606091505b505090508061263657600080fd5b50505060015481146121ce5760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b603460209081526000928352604080842090915290825290205460ff1681565b60018054810190819055600654604080516001600160a01b038681166024830152604480830187905283518084039091018152606490920183526020820180516001600160e01b0316600160e01b632e1ed9490217815292518251600095929092169390918291908083835b6020831061272b5780518252601f19909201916020918201910161270c565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461278b576040519150601f19603f3d011682016040523d82523d6000602084013e612790565b606091505b505090508061279e57600080fd5b5060015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b505050565b67016345785d8a000081565b60095481565b662386f26fc1000081565b600080601c5460ff16600181111561281c57fe5b1461282657600080fd5b60018054810190819055600954831061283e57600080fd5b6000612849846150d1565b905084156128a75761285a816151e7565b600954603854604080516001600160a01b039290921682526020820184905281810184905242606083015251339291600080516020615e3c833981519152919081900360800190a3611ad8565b603a54611ad8906001600160a01b0316338363ffffffff61543616565b60018054810190819055600080601c5460ff1660018111156128e257fe5b146128ec57600080fd5b6001600160a01b03831630141561290257600080fd5b6001600160a01b038316600090815260186020526040902054600954600691612931919063ffffffff614c1316565b101561293c57600080fd5b60355460408051600160e01b6370a082310281526001600160a01b0386811660048301529151919092169163d3ce77fe91869184916370a0823191602480820192602092909190829003018186803b15801561299757600080fd5b505afa1580156129ab573d6000803e3d6000fd5b505050506040513d60208110156129c157600080fd5b50516040805163ffffffff851660e01b81526001600160a01b03909316600484015260248301919091525160448083019260209291908290030181600087803b158015612a0d57600080fd5b505af1158015612a21573d6000803e3d6000fd5b505050506040513d6020811015612a3757600080fd5b5051612a4257600080fd5b506001548114611f975760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b60018054810190819055600080601c5460ff166001811115612aa857fe5b14612ab257600080fd5b836001600160a01b038116612ac657600080fd5b6001600160a01b038116600080516020615dfc83398151915214612af657612aed81614c73565b612af657600080fd5b601c54610100900460ff1615612b0b57600080fd5b6038546001600160a01b03868116911614801590612b4057506001600160a01b038516600080516020615dfc83398151915214155b612b4957600080fd5b84612b656001600160a01b03821633308863ffffffff61548b16565b603a546000908190612b8390849089906001600160a01b0316614d51565b909450925060009150612b9e9050888363ffffffff614c1316565b90508015612bc057612bc06001600160a01b038516338363ffffffff61543616565b612bc9836151e7565b600954604080516001600160a01b038c168152602081018590528082018690524260608201529051339291600080516020615e3c833981519152919081900360800190a350505050505060015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b60228160058110612c6757fe5b01546001600160a01b0316905081565b600080601c5460ff166001811115612c8b57fe5b14612c9557600080fd5b60018054810190819055601c54610100900460ff1615612cb457600080fd5b603a54612cd2906001600160a01b031633308663ffffffff61548b16565b612cdb836151e7565b600954603854604080516001600160a01b039290921682526020820186905281810186905242606083015251339291600080516020615e3c833981519152919081900360800190a360015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6000600180601c5460ff166001811115612d8057fe5b14612d8a57600080fd5b601c54610100900460ff1615612d9f57600080fd5b600654604080516024810187905285151560448083019190915282518083039091018152606490910182526020810180516001600160e01b0316600160e21b630e07c94f02178152915181516000946060946001600160a01b039091169392918291908083835b60208310612e255780518252601f199092019160209182019101612e06565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114612e85576040519150601f19603f3d011682016040523d82523d6000602084013e612e8a565b606091505b509150915081612e9f57600093505050612ebb565b808060200190516020811015612eb457600080fd5b5051935050505b5092915050565b600080601c5460ff166001811115612ed657fe5b14612ee057600080fd5b60018054810190819055603a546000908190612f14906001600160a01b031686600080516020615dfc833981519152614d51565b9094509250612f2691508290506154e8565b604051339083156108fc029084906000818181858888f19350505050158015612f53573d6000803e3d6000fd5b5060095460408051600080516020615dfc83398151915281526020810185905280820184905242606082015290513392917fae96a66bcd5a00556ad548b9a949f8f45220d5859c013e5cedbddd6af8cf7b9d919081900360800190a3505060015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6009546001600160a01b0382166000908152601060205260408120549091829110613028575060009050806130c5565b6001600160a01b03831660009081526010602052604081205461304c576001613066565b6001600160a01b0384166000908152601060205260409020545b90506000805b6009548310156130c15761308086846136b0565b9092509050613095858363ffffffff614bad16565b94506130a7848263ffffffff614bad16565b93506130ba83600163ffffffff614bad16565b925061306c565b5050505b915091565b60065460408051600481526024810182526020810180516001600160e01b0316600160e01b633eadb6db02178152915181516000946001600160a01b03169382918083835b6020831061312e5780518252601f19909201916020918201910161310f565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461318e576040519150601f19603f3d011682016040523d82523d6000602084013e613193565b606091505b50509050806119aa57600080fd5b60008080601c5460ff1660018111156131b657fe5b146131c057600080fd5b6131c8613bc5565b61320a5760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b601c54610100900460ff161561321f57600080fd5b600654604080516001600160a01b0386811660248084019190915283518084039091018152604490920183526020820180516001600160e01b0316600160e41b6303f67721021781529251825160009560609593169392829180838360208310611bd95780518252601f199092019160209182019101611bba565b601560205281600052604060002081815481106132b357fe5b6000918252602090912001546001600160a01b03169150829050565b6132d7615cb8565b604080518082019182905290600e9060029082845b8154815260200190600101908083116132ec575050505050905090565b60019392505050565b6001805481019081905560065460408051602480820186905282518083039091018152604490910182526020810180516001600160e01b0316600160e11b632592ff4902178152915181516000946001600160a01b03169382918083835b6020831061338f5780518252601f199092019160209182019101613370565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146133ef576040519150601f19603f3d011682016040523d82523d6000602084013e6133f4565b606091505b5050905080612a4257600080fd5b600381565b6203f48081565b600e816002811061341b57fe5b0154905081565b60136020526000908152604090205481565b602c816005811061341b57fe5b601c54610100900460ff1681565b601d8160058110612c6757fe5b60315481565b670a688906bd8b000081565b6001600160a01b0381166000908152601460205260409020545b919050565b600180601c5460ff1660018111156134a157fe5b146134ab57600080fd5b600180548101908190556006546040805160248101899052604481018890526064810187905260848082018790528251808303909101815260a490910182526020810180516001600160e01b0316600160e11b633889d77902178152915181516000946001600160a01b03169382918083835b6020831061353d5780518252601f19909201916020918201910161351e565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461359d576040519150601f19603f3d011682016040523d82523d6000602084013e6135a2565b606091505b50509050806135b057600080fd5b5060015481146123935760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b613600613bc5565b6136425760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b60166020526000908152604090205481565b60106020526000908152604090205481565b6001600160a01b0382166000908152601160209081526040808320848452909152812054819060ff16156136e9575060009050806139f6565b6035546000906001600160a01b0316634ee2cd7e8660178461371289600163ffffffff614c1316565b8152602001908152602001600020546040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060206040518083038186803b15801561376e57600080fd5b505afa158015613782573d6000803e3d6000fd5b505050506040513d602081101561379857600080fd5b50519050600081156137aa57816137c4565b6001600160a01b0386166000908152601360205260409020545b9050811580156137ea57506001600160a01b038616600090815260136020526040902054155b156137fe5750600092508291506139f69050565b600061385e613816836203f48063ffffffff6155dc16565b6001600160a01b03891660009081526012602090815260408083208b845290915290205461385290670de0b6b3a764000063ffffffff6155dc16565b9063ffffffff61563816565b9050670de0b6b3a76400008111613875578061387f565b670de0b6b3a76400005b6035546000888152601760209081526040808320548151600160e41b630981b24d0281526004810191909152905194955091936139bf936001600160a01b03169263981b24d0926024808301939192829003018186803b1580156138e257600080fd5b505afa1580156138f6573d6000803e3d6000fd5b505050506040513d602081101561390c57600080fd5b505160355460008a815260176020908152604091829020548251600160e11b63277166bf0281526001600160a01b038f8116600483015260248201929092529251613852949190911692634ee2cd7e926044808301939192829003018186803b15801561397857600080fd5b505afa15801561398c573d6000803e3d6000fd5b505050506040513d60208110156139a257600080fd5b505160008b8152601660205260409020549063ffffffff6155dc16565b90506139dd670de0b6b3a7640000613852838563ffffffff6155dc16565b95506139ef818763ffffffff614c1316565b9450505050505b9250929050565b6201518081565b613a0c613bc5565b613a4e5760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b60025460ff1615613a5e57600080fd5b6002805460ff1916600117905560005b8351811015613acd57600160196000868481518110613a8957fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055613ac6816001614bad565b9050613a6e565b5060005b8251811015613b30576001601a6000858481518110613aec57fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055613b29816001614bad565b9050613ad1565b5060005b8151811015611b20576001601b6000848481518110613b4f57fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055613b8c816001614bad565b9050613b34565b604051806040016040528060048152602001600160e01b635045524d0281525081565b6000546001600160a01b031690565b6000546001600160a01b0316331490565b60355460408051600160e01b6318160ddd02815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b158015613c1e57600080fd5b505afa158015613c32573d6000803e3d6000fd5b505050506040513d6020811015613c4857600080fd5b5051613c5d57506722b1c8c1227a0000612445565b6000613cf7603560009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015613cb057600080fd5b505afa158015613cc4573d6000803e3d6000fd5b505050506040513d6020811015613cda57600080fd5b5051600a5461385290670de0b6b3a764000063ffffffff6155dc16565b90506722b1c8c1227a0000811015612442576722b1c8c1227a0000915050612445565b60146020528160005260406000208181548110613d3357fe5b60009182526020909120600990910201805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b039097169950949750929591949093919060ff1689565b60336020526000908152604090205481565b601b6020526000908152604090205460ff1681565b613dbb613bc5565b613dfd5760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b6001600160a01b038116613e1057600080fd5b6004546001600160a01b031615613e2657600080fd5b600480546001600160a01b039092166001600160a01b0319928316811790915560378054909216179055565b600080601c5460ff166001811115613e6657fe5b14613e7057600080fd5b60018054810190819055601c54610100900460ff1615613e8f57600080fd5b603a546000908190613ebb90600080516020615dfc8339815191529034906001600160a01b0316614d51565b909450925060009150613ed69050348363ffffffff614c1316565b90508015613f0d57604051339082156108fc029083906000818181858888f19350505050158015613f0b573d6000803e3d6000fd5b505b613f16836151e7565b60095460408051600080516020615dfc8339815191528152602081018590528082018690524260608201529051339291600080516020615e3c833981519152919081900360800190a35050506001548114611f975760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6005546001600160a01b031681565b600080601c5460ff166001811115613fcc57fe5b14613fd657600080fd5b60018054810190819055613fe9836154e8565b603a54614006906001600160a01b0316338563ffffffff61543616565b600954603854604080516001600160a01b0392909216825260208201869052818101869052426060830152513392917fae96a66bcd5a00556ad548b9a949f8f45220d5859c013e5cedbddd6af8cf7b9d919081900360800190a360015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6000600180601c5460ff1660018111156140bd57fe5b146140c757600080fd5b601c54610100900460ff16156140dc57600080fd5b60065460408051602481018790526001600160a01b0386811660448084019190915283518084039091018152606490920183526020820180516001600160e01b0316600160e01b639bcc8e7b021781529251825160009560609593169392829180838360208310612e255780518252601f199092019160209182019101612e06565b60006001601c5460ff16600181111561417357fe5b1461418057506001612445565b60006203f480600b5442038161419257fe5b0690506201518081106141a65760016141a9565b60005b91505090565b60018054810190819055600080601c5460ff1660018111156141cd57fe5b146141d757600080fd5b836001600160a01b0381166141eb57600080fd5b6001600160a01b038116600080516020615dfc8339815191521461421b5761421281614c73565b61421b57600080fd5b6038546001600160a01b0386811691161480159061425057506001600160a01b038516600080516020615dfc83398151915214155b61425957600080fd5b603a5485906000908190614277906001600160a01b03168885614d51565b909450925061428991508290506154e8565b6142a36001600160a01b038416338463ffffffff61543616565b600954604080516001600160a01b038b1681526020810185905280820184905242606082015290513392917fae96a66bcd5a00556ad548b9a949f8f45220d5859c013e5cedbddd6af8cf7b9d919081900360800190a3505050505060015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6004546001600160a01b031681565b600080601c5460ff16600181111561436857fe5b1461437257600080fd5b6001805481019081905560006143866156a5565b905083156143e457614397816151e7565b600954603854604080516001600160a01b039290921682526020820184905281810184905242606083015251339291600080516020615e3c833981519152919081900360800190a361279e565b603a5461279e906001600160a01b0316338363ffffffff61543616565b670de0b6b3a764000081565b60176020526000908152604090205481565b600d5481565b61442d613bc5565b61446f5760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b6001600160a01b0381161580159061449057506001600160a01b0381163014155b61449957600080fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b66038d7ea4c6800081565b6722b1c8c1227a000081565b6001600160a01b031660009081526015602052604090205490565b600681565b60025460ff1681565b600180548101808255601c54909161010090910460ff1615151461451e57600080fd5b61452a600e60006117ef565b421161453557600080fd5b816001600160a01b03811661454957600080fd5b6001600160a01b038116600080516020615dfc833981519152146145795761457081614c73565b61457957600080fd5b6001600160a01b038316600080516020615dfc83398151915214156145e157601c546040516001600160a01b0363010000009092049190911690303180156108fc02916000818181858888f193505050501580156145db573d6000803e3d6000fd5b50612a42565b601c5460408051600160e01b6370a0823102815230600482015290518592614683926001600160a01b036301000000909204821692918516916370a0823191602480820192602092909190829003018186803b15801561464057600080fd5b505afa158015614654573d6000803e3d6000fd5b505050506040513d602081101561466a57600080fd5b50516001600160a01b038416919063ffffffff61543616565b50506001548114611f975760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b601260209081526000928352604080842090915290825290205481565b6001805481019081905560065460408051600481526024810182526020810180516001600160e01b0316600160e01b63bf8519bd02178152915181516000946001600160a01b03169382918083835b602083106147575780518252601f199092019160209182019101614738565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146147b7576040519150601f19603f3d011682016040523d82523d6000602084013e6147bc565b606091505b50509050806147ca57600080fd5b5060015481146119aa5760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6039546001600160a01b031681565b68056bc75e2d6310000081565b601160209081526000928352604080842090915290825290205460ff1681565b6000600180601c5460ff16600181111561486457fe5b1461486e57600080fd5b601c54610100900460ff161561488357600080fd5b60065460408051602480820187905282518083039091018152604490910182526020810180516001600160e01b0316600160e01b63d2ec1fe702178152915181516000946060946001600160a01b0390911693929182919080838360208310611bd95780518252601f199092019160209182019101611bba565b6000600360095411158061491857506001600160a01b038216155b1561492557506000613488565b6035546009546001600160a01b0390911690634ee2cd7e90849060179060009061495690600363ffffffff614c1316565b8152602001908152602001600020546040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060206040518083038186803b1580156149b257600080fd5b505afa1580156149c6573d6000803e3d6000fd5b505050506040513d60208110156149dc57600080fd5b505192915050565b6003546001600160a01b031681565b6038546001600160a01b031681565b6008546001600160a01b031681565b601c5462010000900460ff1681565b60025461010090046001600160a01b031681565b614a3c613bc5565b614a7e5760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b6001600160a01b03166000908152601960205260409020805460ff19166001179055565b6027816005811061341b57fe5b60006001601c5460ff166001811115614ac457fe5b14614ad157506000612445565b6203f480600b54420381614ae157fe5b04905090565b60326020528260005260406000206020528160005260406000208160058110614b0c57fe5b602081049091015460ff601f9092166101000a900416925083915050565b614b32613bc5565b614b745760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b6119aa816157fc565b50600090565b601c5460ff1681565b60186020526000908152604090205481565b6007546001600160a01b031681565b600082820183811015614c0a5760408051600160e51b62461bcd02815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b600082821115614c6d5760408051600160e51b62461bcd02815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000806001600160a01b038316614c8e576000915050613488565b50503b151590565b60006001600160a01b038316600080516020615dfc8339815191521415614cc857506001600160a01b03811631614c0d565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015614d1e57600080fd5b505afa158015614d32573d6000803e3d6000fd5b505050506040513d6020811015614d4857600080fd5b50519392505050565b600080600080846001600160a01b0316876001600160a01b03161415614d7657600080fd5b603b5460408051600160e01b63809a9e550281526001600160a01b038a811660048301528881166024830152604482018a90528251600094919091169263809a9e559260648082019391829003018186803b158015614dd457600080fd5b505afa158015614de8573d6000803e3d6000fd5b505050506040513d6040811015614dfe57600080fd5b5060200151905080614e0f57600080fd5b6000614e1b8930614c96565b905060006001600160a01b038a16600080516020615dfc83398151915214614e865750603954600090614e61906001600160a01b038c811691168363ffffffff61589f16565b603954614e81906001600160a01b038c811691168b63ffffffff61589f16565b614e89565b50875b603b546001600160a01b03166329589f61828c8c8c614ea730612445565b6b204fce5e3e250261100000008a73332d87209f7c8296389c307eae170c2440830a47604051806040016040528060048152602001600160e01b635045524d028152506040518a63ffffffff1660e01b815260040180896001600160a01b03166001600160a01b03168152602001888152602001876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b03168152602001858152602001848152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614fa8578181015183820152602001614f90565b50505050905090810190601f168015614fd55780820380516001836020036101000a031916815260200191505b5099505050505050505050506020604051808303818588803b158015614ffa57600080fd5b505af115801561500e573d6000803e3d6000fd5b50505050506040513d602081101561502557600080fd5b505194508461503357600080fd5b6001600160a01b038a16600080516020615dfc8339815191521461507257603954615072906001600160a01b038c81169116600063ffffffff61589f16565b61508c61507f8b30614c96565b839063ffffffff614c1316565b93506150aa858561509c8b6159bb565b6150a58e6159bb565b615a52565b96506150c384866150ba8d6159bb565b6150a58c6159bb565b955050505093509350935093565b33600090815260116020908152604080832084845290915281205460ff16156150f957600080fd5b600061510533846136b0565b3360009081526011602090815260408083208884529091529020805460ff19166001179055600d549193509150615142908363ffffffff614c1316565b600d55600954600090815260166020526040902054615167908263ffffffff614bad16565b6009546000908152601660209081526040808320939093553382526014905290812061519291615cd6565b3360009081526015602052604081206151aa91615cf7565b604080518381529051339185917fec530ab710fdaa2b5968fe15f486992441a96f643219cf0150904aa5b9eedf829181900360200190a350919050565b603660009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561523557600080fd5b505afa158015615249573d6000803e3d6000fd5b505050506040513d602081101561525f57600080fd5b5051158061526d5750600a54155b156153035760365460408051600160e61b630209fccb0281523360048201526024810184905290516001600160a01b039092169163827f32c0916044808201926020929091908290030181600087803b1580156152c957600080fd5b505af11580156152dd573d6000803e3d6000fd5b505050506040513d60208110156152f357600080fd5b50516152fe57600080fd5b61541d565b603654600a5460408051600160e01b6318160ddd02815290516001600160a01b039093169263827f32c0923392615399926138529187916318160ddd91600480820192602092909190829003018186803b15801561536057600080fd5b505afa158015615374573d6000803e3d6000fd5b505050506040513d602081101561538a57600080fd5b5051879063ffffffff6155dc16565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156153e857600080fd5b505af11580156153fc573d6000803e3d6000fd5b505050506040513d602081101561541257600080fd5b505161541d57600080fd5b600a54615430908263ffffffff614bad16565b600a5550565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0316600160e01b63a9059cbb021790526127e6908490615af1565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b0316600160e01b6323b872dd02179052611b20908590615af1565b603654600a5460408051600160e01b6318160ddd02815290516001600160a01b039093169263d3ce77fe923392615545926138529187916318160ddd91600480820192602092909190829003018186803b15801561536057600080fd5b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561559457600080fd5b505af11580156155a8573d6000803e3d6000fd5b505050506040513d60208110156155be57600080fd5b50516155c957600080fd5b600a54615430908263ffffffff614c1316565b6000826155eb57506000614c0d565b828202828482816155f857fe5b0414614c0a57604051600160e51b62461bcd028152600401808060200182810382526021815260200180615ddb6021913960400191505060405180910390fd5b60008082116156915760408051600160e51b62461bcd02815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b600082848161569c57fe5b04949350505050565b600954336000908152601060205260408120549091116156c457600080fd5b60006156cf33612ff8565b3360009081526010602052604090205491935091505b60095481101561572f573360009081526011602090815260408083208484529091529020805460ff1916600190811790915561572890829063ffffffff614bad16565b90506156e5565b5060095433600090815260106020526040902055600d54615756908363ffffffff614c1316565b600d5560095460009081526016602052604090205461577b908263ffffffff614bad16565b600954600090815260166020908152604080832093909355338252601490529081206157a691615cd6565b3360009081526015602052604081206157be91615cf7565b6009546040805184815290513392917fec530ab710fdaa2b5968fe15f486992441a96f643219cf0150904aa5b9eedf82919081900360200190a35090565b6001600160a01b03811661584457604051600160e51b62461bcd028152600401808060200182810382526026815260200180615db56026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b801580615928575060408051600160e11b636eb1769f0281523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b1580156158fa57600080fd5b505afa15801561590e573d6000803e3d6000fd5b505050506040513d602081101561592457600080fd5b5051155b61596657604051600160e51b62461bcd028152600401808060200182810382526036815260200180615e866036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0316600160e01b63095ea7b3021790526127e6908490615af1565b60006001600160a01b038216600080516020615dfc83398151915214156159e457506012613488565b816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015615a1d57600080fd5b505afa158015615a31573d6000803e3d6000fd5b505050506040513d6020811015615a4757600080fd5b505160ff1692915050565b60006b204fce5e3e25026110000000851115615a6d57600080fd5b6b204fce5e3e25026110000000841115615a8657600080fd5b828210615abf5760128383031115615a9d57600080fd5b84838303600a0a02670de0b6b3a7640000850281615ab757fe5b049050615ae9565b60128284031115615acf57600080fd5b84828403600a0a670de0b6b3a764000086020281615ab757fe5b949350505050565b615b03826001600160a01b0316615cb2565b615b575760408051600160e51b62461bcd02815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310615b955780518252601f199092019160209182019101615b76565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114615bf7576040519150601f19603f3d011682016040523d82523d6000602084013e615bfc565b606091505b509150915081615c565760408051600160e51b62461bcd02815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115611b2057808060200190516020811015615c7257600080fd5b5051611b2057604051600160e51b62461bcd02815260040180806020018281038252602a815260200180615e5c602a913960400191505060405180910390fd5b3b151590565b60405180604001604052806002906020820280388339509192915050565b50805460008255600902906000526020600020908101906119aa9190615d15565b50805460008255906000526020600020908101906119aa9190615d7a565b61244591905b80821115615d765780546001600160a01b03191681556000600182018190556002820181905560038201819055600482018190556005820181905560068201819055600782015560088101805460ff19169055600901615d1b565b5090565b61244591905b80821115615d765760008155600101615d8056fe5265656e7472616e637947756172643a207265656e7472616e742063616c6c004f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65727ee7a1de9c18ce695c95b8b19fbdf26cce3544e3ca9e08c9f487776783d7599f5361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a165627a7a723058204e1bbf357632776bcdcb838d2032d64c5b23cdecf17f5064fa399480001069510029000000000000000000000000952bbd5344ca0a898a1b8b2ffcfe3acb1351ebd50000000000000000000000001689dcfef3e695ac4cc1e5b7e77f9135f1d58a50000000000000000000000000332d87209f7c8296389c307eae170c2440830a47000000000000000000000000000000000000000000000000000000000003f480000000000000000000000000000000000000000000000000000000000023988000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000818e6fecd516ecc3849daf6845e3ec868087b755000000000000000000000000f9b8d8137de64de61cd582518ebc5345d01d5039000000000000000000000000d176ff3d44fdae552bdc5b566fa1f0066e81fe0b

Deployed Bytecode

0x6080604052600436106105fa5760003560e01c80638606c91a1161030e578063b7ac4ff31161019b578063db77839b116100e7578063ee00f705116100a0578063f49008631161007a578063f490086314610d8e578063f6558b0014611767578063fa845ca91461177c578063fbf35f46146117af576105fa565b8063ee00f705146116bf578063f2fde38b1461170e578063f48c305414611741576105fa565b8063db77839b14611623578063dc87454c14611638578063e1024b4d1461164d578063e91e13a914610c9e578063e96e22b914611680578063e9fc335d146116aa576105fa565b8063ce977bc211610154578063d7615d371161012e578063d7615d37146115e4578063d95393eb146115f9578063da682aeb14610c1c578063db3d1ccf1461160e576105fa565b8063ce977bc21461154e578063d2ec1fe714611587578063d5da24b9146115b1576105fa565b8063b7ac4ff31461149b578063b8fc41ac146114b0578063bdbcb576146114e3578063bf8519bd1461151c578063cb0ef21d14611524578063cdf8b9f814611539576105fa565b80639bcc8e7b1161025a578063a940646d11610213578063b1ace0b0116101ed578063b1ace0b014611429578063b38ca2f21461143e578063b4230d1a14611453578063b5050ea814611486576105fa565b8063a940646d146113b7578063ae2f89c2146113e1578063b18e8a8d146113f6576105fa565b80639bcc8e7b146112b65780639c3f1150146112ef5780639e281a9814611328578063a03040c314611361578063a6f561ec14611376578063a8b6b2b6146113a2576105fa565b80639244adcd116102c757806397107d6d116102a157806397107d6d1461123c57806398ea5fca1461126f5780639a8a2145146112775780639add74381461128c576105fa565b80639244adcd1461115357806392bba1fc146111df57806392d64c9d14611209576105fa565b80638606c91a14610ebd5780638b14799d14610ed25780638b98a2c51461108a5780638da5cb5b146111145780638f32d59b146111295780638feb82ba1461113e576105fa565b80633477ee2e1161048c57806356f7e7ff116103d8578063675fb9c411610391578063715018a61161036b578063715018a614610e125780637cd9fb1c14610e27578063821f982414610e51578063852a89d514610e84576105fa565b8063675fb9c414610d8e57806368063a7414610da35780637113aef214610dd6576105fa565b806356f7e7ff14610cb35780635825b04c14610cdd5780635ebad71414610d105780635f88967b14610d3a578063623e3d1a14610d4f578063627d50df14610d79576105fa565b80633f677210116104455780634a3931491161041f5780634a39314914610c1c5780634b25fe9214610c5f5780634cc0fc3914610c895780634f2094a114610c9e576105fa565b80633f67721014610b60578063404c568f14610b93578063407fa2a314610bcc576105fa565b80633477ee2e14610a4f578063365833e114610a79578063381f253c14610aa35780633bed33ce14610ad55780633d98147414610aff5780633eadb6db14610b4b576105fa565b80632893f5cc1161054b5780632e1ed949116105045780632f9fb6a4116104de5780632f9fb6a41461099c5780632fcfb8ab146109b157806331f55422146109e3578063338b5dea14610a16576105fa565b80632e1ed949146109395780632e80d9b6146109725780632f88471014610987576105fa565b80632893f5cc1461083457806328ad7cef146108675780632914af341461087c5780632a5addf3146108915780632b23c8a0146108bb5780632df182c914610900576105fa565b80630e187cac116105b85780631a454ea6116105925780631a454ea6146107875780631f5c6a511461079c57806322d40045146107d257806325f842c51461081f576105fa565b80630e187cac1461070c57806313d3d00e1461073f578063173e770714610754576105fa565b806276b283146105fc5780630bafd60e146106115780630c06b1e1146106425780630c99c9ea146106725780630cba5355146106b25780630d52aeec146106d9575b005b34801561060857600080fd5b506105fa6117c4565b34801561061d57600080fd5b506106266119ad565b604080516001600160a01b039092168252519081900360200190f35b34801561064e57600080fd5b506105fa6004803603604081101561066557600080fd5b50803590602001356119c3565b34801561067e57600080fd5b5061069e6004803603602081101561069557600080fd5b50351515611b26565b604080519115158252519081900360200190f35b3480156106be57600080fd5b506106c7611c75565b60408051918252519081900360200190f35b3480156106e557600080fd5b506105fa600480360360208110156106fc57600080fd5b50356001600160a01b0316611c7b565b34801561071857600080fd5b5061069e6004803603602081101561072f57600080fd5b50356001600160a01b0316611f9b565b34801561074b57600080fd5b506106c7611fb0565b34801561076057600080fd5b506105fa6004803603602081101561077757600080fd5b50356001600160a01b0316611fb6565b34801561079357600080fd5b506106c761205e565b3480156107a857600080fd5b506105fa600480360360608110156107bf57600080fd5b508035906020810135906040013561206a565b3480156107de57600080fd5b506105fa600480360360a08110156107f557600080fd5b5080351515906001600160a01b0360208201351690604081013590606081013590608001356121d5565b34801561082b57600080fd5b506106c761239b565b34801561084057600080fd5b5061069e6004803603602081101561085757600080fd5b50356001600160a01b03166123a1565b34801561087357600080fd5b506106c76123b6565b34801561088857600080fd5b50610626612448565b34801561089d57600080fd5b506105fa600480360360208110156108b457600080fd5b5035612457565b3480156108c757600080fd5b506105fa600480360360808110156108de57600080fd5b506001600160a01b0381351690602081013590604081013590606001356124c8565b34801561090c57600080fd5b5061069e6004803603604081101561092357600080fd5b50803590602001356001600160a01b0316612680565b34801561094557600080fd5b506105fa6004803603604081101561095c57600080fd5b506001600160a01b0381351690602001356126a0565b34801561097e57600080fd5b506106c76127eb565b34801561099357600080fd5b506106c76127f7565b3480156109a857600080fd5b506106c76127fd565b3480156109bd57600080fd5b506105fa600480360360408110156109d457600080fd5b50803515159060200135612808565b3480156109ef57600080fd5b506105fa60048036036020811015610a0657600080fd5b50356001600160a01b03166128c4565b348015610a2257600080fd5b506105fa60048036036040811015610a3957600080fd5b506001600160a01b038135169060200135612a8a565b348015610a5b57600080fd5b5061062660048036036020811015610a7257600080fd5b5035612c5a565b348015610a8557600080fd5b506105fa60048036036020811015610a9c57600080fd5b5035612c77565b348015610aaf57600080fd5b5061069e60048036036040811015610ac657600080fd5b50803590602001351515612d6a565b348015610ae157600080fd5b506105fa60048036036020811015610af857600080fd5b5035612ec2565b348015610b0b57600080fd5b50610b3260048036036020811015610b2257600080fd5b50356001600160a01b0316612ff8565b6040805192835260208301919091528051918290030190f35b348015610b5757600080fd5b506105fa6130ca565b348015610b6c57600080fd5b5061069e60048036036020811015610b8357600080fd5b50356001600160a01b03166131a1565b348015610b9f57600080fd5b5061062660048036036040811015610bb657600080fd5b506001600160a01b03813516906020013561329a565b348015610bd857600080fd5b50610be16132cf565b6040518082600260200280838360005b83811015610c09578181015183820152602001610bf1565b5050505090500191505060405180910390f35b348015610c2857600080fd5b5061069e60048036036060811015610c3f57600080fd5b506001600160a01b03813581169160208101359091169060400135613309565b348015610c6b57600080fd5b506105fa60048036036020811015610c8257600080fd5b5035613312565b348015610c9557600080fd5b506106c7613402565b348015610caa57600080fd5b506106c7613407565b348015610cbf57600080fd5b506106c760048036036020811015610cd657600080fd5b503561340e565b348015610ce957600080fd5b506106c760048036036020811015610d0057600080fd5b50356001600160a01b0316613422565b348015610d1c57600080fd5b506106c760048036036020811015610d3357600080fd5b5035613434565b348015610d4657600080fd5b5061069e613441565b348015610d5b57600080fd5b5061062660048036036020811015610d7257600080fd5b503561344f565b348015610d8557600080fd5b506106c761345c565b348015610d9a57600080fd5b506106c7613462565b348015610daf57600080fd5b506106c760048036036020811015610dc657600080fd5b50356001600160a01b031661346e565b348015610de257600080fd5b506105fa60048036036080811015610df957600080fd5b508035906020810135906040810135906060013561348d565b348015610e1e57600080fd5b506105fa6135f8565b348015610e3357600080fd5b506106c760048036036020811015610e4a57600080fd5b503561368c565b348015610e5d57600080fd5b506106c760048036036020811015610e7457600080fd5b50356001600160a01b031661369e565b348015610e9057600080fd5b50610b3260048036036040811015610ea757600080fd5b506001600160a01b0381351690602001356136b0565b348015610ec957600080fd5b506106c76139fd565b348015610ede57600080fd5b506105fa60048036036060811015610ef557600080fd5b810190602081018135640100000000811115610f1057600080fd5b820183602082011115610f2257600080fd5b80359060200191846020830284011164010000000083111715610f4457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610f9457600080fd5b820183602082011115610fa657600080fd5b80359060200191846020830284011164010000000083111715610fc857600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561101857600080fd5b82018360208201111561102a57600080fd5b8035906020019184602083028401116401000000008311171561104c57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613a04945050505050565b34801561109657600080fd5b5061109f613b93565b6040805160208082528351818301528351919283929083019185019080838360005b838110156110d95781810151838201526020016110c1565b50505050905090810190601f1680156111065780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561112057600080fd5b50610626613bb6565b34801561113557600080fd5b5061069e613bc5565b34801561114a57600080fd5b506106c7613bd6565b34801561115f57600080fd5b5061118c6004803603604081101561117657600080fd5b506001600160a01b038135169060200135613d1a565b604080516001600160a01b03909a168a5260208a0198909852888801969096526060880194909452608087019290925260a086015260c085015260e0840152151561010083015251908190036101200190f35b3480156111eb57600080fd5b506106c76004803603602081101561120257600080fd5b5035613d8c565b34801561121557600080fd5b5061069e6004803603602081101561122c57600080fd5b50356001600160a01b0316613d9e565b34801561124857600080fd5b506105fa6004803603602081101561125f57600080fd5b50356001600160a01b0316613db3565b6105fa613e52565b34801561128357600080fd5b50610626613fa9565b34801561129857600080fd5b506105fa600480360360208110156112af57600080fd5b5035613fb8565b3480156112c257600080fd5b5061069e600480360360408110156112d957600080fd5b50803590602001356001600160a01b03166140a7565b3480156112fb57600080fd5b5061130461415e565b6040518082600181111561131457fe5b60ff16815260200191505060405180910390f35b34801561133457600080fd5b506105fa6004803603604081101561134b57600080fd5b506001600160a01b0381351690602001356141af565b34801561136d57600080fd5b50610626614345565b34801561138257600080fd5b506105fa6004803603602081101561139957600080fd5b50351515614354565b3480156113ae57600080fd5b506106c7614401565b3480156113c357600080fd5b506106c7600480360360208110156113da57600080fd5b503561440d565b3480156113ed57600080fd5b506106c761441f565b34801561140257600080fd5b506105fa6004803603602081101561141957600080fd5b50356001600160a01b0316614425565b34801561143557600080fd5b506106c76144bb565b34801561144a57600080fd5b506106c76144c6565b34801561145f57600080fd5b506106c76004803603602081101561147657600080fd5b50356001600160a01b03166144d2565b34801561149257600080fd5b506106c76144ed565b3480156114a757600080fd5b5061069e6144f2565b3480156114bc57600080fd5b506105fa600480360360208110156114d357600080fd5b50356001600160a01b03166144fb565b3480156114ef57600080fd5b506106c76004803603604081101561150657600080fd5b506001600160a01b0381351690602001356146cc565b6105fa6146e9565b34801561153057600080fd5b50610626614812565b34801561154557600080fd5b506106c7614821565b34801561155a57600080fd5b5061069e6004803603604081101561157157600080fd5b506001600160a01b03813516906020013561482e565b34801561159357600080fd5b5061069e600480360360208110156115aa57600080fd5b503561484e565b3480156115bd57600080fd5b506106c7600480360360208110156115d457600080fd5b50356001600160a01b03166148fd565b3480156115f057600080fd5b506106266149e4565b34801561160557600080fd5b506106266149f3565b34801561161a57600080fd5b50610626614a02565b34801561162f57600080fd5b5061069e614a11565b34801561164457600080fd5b50610626614a20565b34801561165957600080fd5b506105fa6004803603602081101561167057600080fd5b50356001600160a01b0316614a34565b34801561168c57600080fd5b506106c7600480360360208110156116a357600080fd5b5035614aa2565b3480156116b657600080fd5b506106c7614aaf565b3480156116cb57600080fd5b506116fe600480360360608110156116e257600080fd5b508035906001600160a01b036020820135169060400135614ae7565b6040518082600281111561131457fe5b34801561171a57600080fd5b506105fa6004803603602081101561173157600080fd5b50356001600160a01b0316614b2a565b61069e6004803603602081101561175757600080fd5b50356001600160a01b0316614b7d565b34801561177357600080fd5b50611304614b83565b34801561178857600080fd5b506106c76004803603602081101561179f57600080fd5b50356001600160a01b0316614b8c565b3480156117bb57600080fd5b50610626614b9e565b600180548101808255601c54909161010090910460ff161515146117e757600080fd5b61180a600e60005b600281106117f957fe5b0154600b549063ffffffff614bad16565b421161181557600080fd5b603554601c5460408051600160e01b63f2fde38b02815263010000009092046001600160a01b039081166004840152905192169163f2fde38b9160248082019260009290919082900301818387803b15801561187057600080fd5b505af1158015611884573d6000803e3d6000fd5b5050603654601c5460408051600160e01b63f2fde38b02815263010000009092046001600160a01b03908116600484015290519216935063f2fde38b925060248082019260009290919082900301818387803b1580156118e357600080fd5b505af11580156118f7573d6000803e3d6000fd5b50505050603760009054906101000a90046001600160a01b03166001600160a01b0316631aa3ba166040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561194b57600080fd5b505af115801561195f573d6000803e3d6000fd5b5050505060015481146119aa5760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b50565b601c54630100000090046001600160a01b031681565b600180601c5460ff1660018111156119d757fe5b146119e157600080fd5b600180548101908190556006546040805160248101879052604480820187905282518083039091018152606490910182526020810180516001600160e01b0316600160e01b630c06b1e102178152915181516000946001600160a01b03169382918083835b60208310611a655780518252601f199092019160209182019101611a46565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114611ac5576040519150601f19603f3d011682016040523d82523d6000602084013e611aca565b606091505b5050905080611ad857600080fd5b506001548114611b205760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b50505050565b60008080601c5460ff166001811115611b3b57fe5b14611b4557600080fd5b601c54610100900460ff1615611b5a57600080fd5b6006546040805185151560248083019190915282518083039091018152604490910182526020810180516001600160e01b0316600160e11b63064ce4f502178152915181516000946060946001600160a01b039091169392918291908083835b60208310611bd95780518252601f199092019160209182019101611bba565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114611c39576040519150601f19603f3d011682016040523d82523d6000602084013e611c3e565b606091505b509150915081611c5357600093505050611c6f565b808060200190516020811015611c6857600080fd5b5051935050505b50919050565b600a5481565b60018054810190819055600080601c5460ff166001811115611c9957fe5b14611ca357600080fd5b6001600160a01b038316611cb657600080fd5b6000839050806001600160a01b031663e852e7416040518163ffffffff1660e01b815260040160206040518083038186803b158015611cf457600080fd5b505afa158015611d08573d6000803e3d6000fd5b505050506040513d6020811015611d1e57600080fd5b5051158015611d925750600954816001600160a01b0316632f8847106040518163ffffffff1660e01b815260040160206040518083038186803b158015611d6457600080fd5b505afa158015611d78573d6000803e3d6000fd5b505050506040513d6020811015611d8e57600080fd5b5051105b611d9b57600080fd5b603a5460408051600160e01b6370a0823102815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611de957600080fd5b505afa158015611dfd573d6000803e3d6000fd5b505050506040513d6020811015611e1357600080fd5b505160408051600160e11b6366b0d4ad0281526000600482018190526b204fce5e3e25026110000000602483015282519394506001600160a01b0386169363cd61a95a936044808501949193918390030190829087803b158015611e7657600080fd5b505af1158015611e8a573d6000803e3d6000fd5b505050506040513d6040811015611ea057600080fd5b5050603a5460408051600160e01b6370a082310281523060048201529051600092611f319285926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015611ef957600080fd5b505afa158015611f0d573d6000803e3d6000fd5b505050506040513d6020811015611f2357600080fd5b50519063ffffffff614c1316565b600a54909150611f47908263ffffffff614bad16565b600a55505060015483149150611f9790505760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b5050565b60196020526000908152604090205460ff1681565b600c5481565b60018054810190819055600080601c5460ff166001811115611fd457fe5b14611fde57600080fd5b826001600160a01b038116611ff257600080fd5b6001600160a01b038116600080516020615dfc833981519152146120225761201981614c73565b61202257600080fd5b836000612044826120338130614c96565b603a546001600160a01b0316614d51565b5092505050611f4781600a54614bad90919063ffffffff16565b6702c68af0bb14000081565b600180601c5460ff16600181111561207e57fe5b1461208857600080fd5b60018054810190819055600654604080516024810188905260448101879052606480820187905282518083039091018152608490910182526020810180516001600160e01b0316600160e01b631f5c6a5102178152915181516000946001600160a01b03169382918083835b602083106121135780518252601f1990920191602091820191016120f4565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114612173576040519150601f19603f3d011682016040523d82523d6000602084013e612178565b606091505b505090508061218657600080fd5b5060015481146121ce5760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b5050505050565b6001805481018082559080601c5460ff1660018111156121f157fe5b146121fb57600080fd5b856001600160a01b03811661220f57600080fd5b6001600160a01b038116600080516020615dfc8339815191521461223f5761223681614c73565b61223f57600080fd5b600654604080518a151560248201526001600160a01b038a81166044830152606482018a90526084820189905260a48083018990528351808403909101815260c490920183526020820180516001600160e01b0316600160e01b6322d400450217815292518251600095929092169390918291908083835b602083106122d65780518252601f1990920191602091820191016122b7565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114612336576040519150601f19603f3d011682016040523d82523d6000602084013e61233b565b606091505b505090508061234957600080fd5b50505060015481146123935760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b505050505050565b600b5481565b601a6020526000908152604090205460ff1681565b60006003600954116123ca57506000612445565b60315460355460095461244292916001600160a01b03169063981b24d0906017906000906123ff90600363ffffffff614c1316565b8152602001908152602001600020546040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015611ef957600080fd5b90505b90565b6006546001600160a01b031681565b61245f613bc5565b6124a15760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b670de0b6b3a764000081106124b557600080fd5b600c5481106124c357600080fd5b600c55565b60018054810190819055846001600160a01b0381166124e657600080fd5b6001600160a01b038116600080516020615dfc833981519152146125165761250d81614c73565b61251657600080fd5b600180601c5460ff16600181111561252a57fe5b1461253457600080fd5b600654604080516001600160a01b038a81166024830152604482018a90526064820189905260848083018990528351808403909101815260a490920183526020820180516001600160e01b0316600160e51b6301591e450217815292518251600095929092169390918291908083835b602083106125c35780518252601f1990920191602091820191016125a4565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114612623576040519150601f19603f3d011682016040523d82523d6000602084013e612628565b606091505b505090508061263657600080fd5b50505060015481146121ce5760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b603460209081526000928352604080842090915290825290205460ff1681565b60018054810190819055600654604080516001600160a01b038681166024830152604480830187905283518084039091018152606490920183526020820180516001600160e01b0316600160e01b632e1ed9490217815292518251600095929092169390918291908083835b6020831061272b5780518252601f19909201916020918201910161270c565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461278b576040519150601f19603f3d011682016040523d82523d6000602084013e612790565b606091505b505090508061279e57600080fd5b5060015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b505050565b67016345785d8a000081565b60095481565b662386f26fc1000081565b600080601c5460ff16600181111561281c57fe5b1461282657600080fd5b60018054810190819055600954831061283e57600080fd5b6000612849846150d1565b905084156128a75761285a816151e7565b600954603854604080516001600160a01b039290921682526020820184905281810184905242606083015251339291600080516020615e3c833981519152919081900360800190a3611ad8565b603a54611ad8906001600160a01b0316338363ffffffff61543616565b60018054810190819055600080601c5460ff1660018111156128e257fe5b146128ec57600080fd5b6001600160a01b03831630141561290257600080fd5b6001600160a01b038316600090815260186020526040902054600954600691612931919063ffffffff614c1316565b101561293c57600080fd5b60355460408051600160e01b6370a082310281526001600160a01b0386811660048301529151919092169163d3ce77fe91869184916370a0823191602480820192602092909190829003018186803b15801561299757600080fd5b505afa1580156129ab573d6000803e3d6000fd5b505050506040513d60208110156129c157600080fd5b50516040805163ffffffff851660e01b81526001600160a01b03909316600484015260248301919091525160448083019260209291908290030181600087803b158015612a0d57600080fd5b505af1158015612a21573d6000803e3d6000fd5b505050506040513d6020811015612a3757600080fd5b5051612a4257600080fd5b506001548114611f975760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b60018054810190819055600080601c5460ff166001811115612aa857fe5b14612ab257600080fd5b836001600160a01b038116612ac657600080fd5b6001600160a01b038116600080516020615dfc83398151915214612af657612aed81614c73565b612af657600080fd5b601c54610100900460ff1615612b0b57600080fd5b6038546001600160a01b03868116911614801590612b4057506001600160a01b038516600080516020615dfc83398151915214155b612b4957600080fd5b84612b656001600160a01b03821633308863ffffffff61548b16565b603a546000908190612b8390849089906001600160a01b0316614d51565b909450925060009150612b9e9050888363ffffffff614c1316565b90508015612bc057612bc06001600160a01b038516338363ffffffff61543616565b612bc9836151e7565b600954604080516001600160a01b038c168152602081018590528082018690524260608201529051339291600080516020615e3c833981519152919081900360800190a350505050505060015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b60228160058110612c6757fe5b01546001600160a01b0316905081565b600080601c5460ff166001811115612c8b57fe5b14612c9557600080fd5b60018054810190819055601c54610100900460ff1615612cb457600080fd5b603a54612cd2906001600160a01b031633308663ffffffff61548b16565b612cdb836151e7565b600954603854604080516001600160a01b039290921682526020820186905281810186905242606083015251339291600080516020615e3c833981519152919081900360800190a360015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6000600180601c5460ff166001811115612d8057fe5b14612d8a57600080fd5b601c54610100900460ff1615612d9f57600080fd5b600654604080516024810187905285151560448083019190915282518083039091018152606490910182526020810180516001600160e01b0316600160e21b630e07c94f02178152915181516000946060946001600160a01b039091169392918291908083835b60208310612e255780518252601f199092019160209182019101612e06565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114612e85576040519150601f19603f3d011682016040523d82523d6000602084013e612e8a565b606091505b509150915081612e9f57600093505050612ebb565b808060200190516020811015612eb457600080fd5b5051935050505b5092915050565b600080601c5460ff166001811115612ed657fe5b14612ee057600080fd5b60018054810190819055603a546000908190612f14906001600160a01b031686600080516020615dfc833981519152614d51565b9094509250612f2691508290506154e8565b604051339083156108fc029084906000818181858888f19350505050158015612f53573d6000803e3d6000fd5b5060095460408051600080516020615dfc83398151915281526020810185905280820184905242606082015290513392917fae96a66bcd5a00556ad548b9a949f8f45220d5859c013e5cedbddd6af8cf7b9d919081900360800190a3505060015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6009546001600160a01b0382166000908152601060205260408120549091829110613028575060009050806130c5565b6001600160a01b03831660009081526010602052604081205461304c576001613066565b6001600160a01b0384166000908152601060205260409020545b90506000805b6009548310156130c15761308086846136b0565b9092509050613095858363ffffffff614bad16565b94506130a7848263ffffffff614bad16565b93506130ba83600163ffffffff614bad16565b925061306c565b5050505b915091565b60065460408051600481526024810182526020810180516001600160e01b0316600160e01b633eadb6db02178152915181516000946001600160a01b03169382918083835b6020831061312e5780518252601f19909201916020918201910161310f565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461318e576040519150601f19603f3d011682016040523d82523d6000602084013e613193565b606091505b50509050806119aa57600080fd5b60008080601c5460ff1660018111156131b657fe5b146131c057600080fd5b6131c8613bc5565b61320a5760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b601c54610100900460ff161561321f57600080fd5b600654604080516001600160a01b0386811660248084019190915283518084039091018152604490920183526020820180516001600160e01b0316600160e41b6303f67721021781529251825160009560609593169392829180838360208310611bd95780518252601f199092019160209182019101611bba565b601560205281600052604060002081815481106132b357fe5b6000918252602090912001546001600160a01b03169150829050565b6132d7615cb8565b604080518082019182905290600e9060029082845b8154815260200190600101908083116132ec575050505050905090565b60019392505050565b6001805481019081905560065460408051602480820186905282518083039091018152604490910182526020810180516001600160e01b0316600160e11b632592ff4902178152915181516000946001600160a01b03169382918083835b6020831061338f5780518252601f199092019160209182019101613370565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146133ef576040519150601f19603f3d011682016040523d82523d6000602084013e6133f4565b606091505b5050905080612a4257600080fd5b600381565b6203f48081565b600e816002811061341b57fe5b0154905081565b60136020526000908152604090205481565b602c816005811061341b57fe5b601c54610100900460ff1681565b601d8160058110612c6757fe5b60315481565b670a688906bd8b000081565b6001600160a01b0381166000908152601460205260409020545b919050565b600180601c5460ff1660018111156134a157fe5b146134ab57600080fd5b600180548101908190556006546040805160248101899052604481018890526064810187905260848082018790528251808303909101815260a490910182526020810180516001600160e01b0316600160e11b633889d77902178152915181516000946001600160a01b03169382918083835b6020831061353d5780518252601f19909201916020918201910161351e565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461359d576040519150601f19603f3d011682016040523d82523d6000602084013e6135a2565b606091505b50509050806135b057600080fd5b5060015481146123935760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b613600613bc5565b6136425760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b60166020526000908152604090205481565b60106020526000908152604090205481565b6001600160a01b0382166000908152601160209081526040808320848452909152812054819060ff16156136e9575060009050806139f6565b6035546000906001600160a01b0316634ee2cd7e8660178461371289600163ffffffff614c1316565b8152602001908152602001600020546040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060206040518083038186803b15801561376e57600080fd5b505afa158015613782573d6000803e3d6000fd5b505050506040513d602081101561379857600080fd5b50519050600081156137aa57816137c4565b6001600160a01b0386166000908152601360205260409020545b9050811580156137ea57506001600160a01b038616600090815260136020526040902054155b156137fe5750600092508291506139f69050565b600061385e613816836203f48063ffffffff6155dc16565b6001600160a01b03891660009081526012602090815260408083208b845290915290205461385290670de0b6b3a764000063ffffffff6155dc16565b9063ffffffff61563816565b9050670de0b6b3a76400008111613875578061387f565b670de0b6b3a76400005b6035546000888152601760209081526040808320548151600160e41b630981b24d0281526004810191909152905194955091936139bf936001600160a01b03169263981b24d0926024808301939192829003018186803b1580156138e257600080fd5b505afa1580156138f6573d6000803e3d6000fd5b505050506040513d602081101561390c57600080fd5b505160355460008a815260176020908152604091829020548251600160e11b63277166bf0281526001600160a01b038f8116600483015260248201929092529251613852949190911692634ee2cd7e926044808301939192829003018186803b15801561397857600080fd5b505afa15801561398c573d6000803e3d6000fd5b505050506040513d60208110156139a257600080fd5b505160008b8152601660205260409020549063ffffffff6155dc16565b90506139dd670de0b6b3a7640000613852838563ffffffff6155dc16565b95506139ef818763ffffffff614c1316565b9450505050505b9250929050565b6201518081565b613a0c613bc5565b613a4e5760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b60025460ff1615613a5e57600080fd5b6002805460ff1916600117905560005b8351811015613acd57600160196000868481518110613a8957fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055613ac6816001614bad565b9050613a6e565b5060005b8251811015613b30576001601a6000858481518110613aec57fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055613b29816001614bad565b9050613ad1565b5060005b8151811015611b20576001601b6000848481518110613b4f57fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055613b8c816001614bad565b9050613b34565b604051806040016040528060048152602001600160e01b635045524d0281525081565b6000546001600160a01b031690565b6000546001600160a01b0316331490565b60355460408051600160e01b6318160ddd02815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b158015613c1e57600080fd5b505afa158015613c32573d6000803e3d6000fd5b505050506040513d6020811015613c4857600080fd5b5051613c5d57506722b1c8c1227a0000612445565b6000613cf7603560009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015613cb057600080fd5b505afa158015613cc4573d6000803e3d6000fd5b505050506040513d6020811015613cda57600080fd5b5051600a5461385290670de0b6b3a764000063ffffffff6155dc16565b90506722b1c8c1227a0000811015612442576722b1c8c1227a0000915050612445565b60146020528160005260406000208181548110613d3357fe5b60009182526020909120600990910201805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b039097169950949750929591949093919060ff1689565b60336020526000908152604090205481565b601b6020526000908152604090205460ff1681565b613dbb613bc5565b613dfd5760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b6001600160a01b038116613e1057600080fd5b6004546001600160a01b031615613e2657600080fd5b600480546001600160a01b039092166001600160a01b0319928316811790915560378054909216179055565b600080601c5460ff166001811115613e6657fe5b14613e7057600080fd5b60018054810190819055601c54610100900460ff1615613e8f57600080fd5b603a546000908190613ebb90600080516020615dfc8339815191529034906001600160a01b0316614d51565b909450925060009150613ed69050348363ffffffff614c1316565b90508015613f0d57604051339082156108fc029083906000818181858888f19350505050158015613f0b573d6000803e3d6000fd5b505b613f16836151e7565b60095460408051600080516020615dfc8339815191528152602081018590528082018690524260608201529051339291600080516020615e3c833981519152919081900360800190a35050506001548114611f975760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6005546001600160a01b031681565b600080601c5460ff166001811115613fcc57fe5b14613fd657600080fd5b60018054810190819055613fe9836154e8565b603a54614006906001600160a01b0316338563ffffffff61543616565b600954603854604080516001600160a01b0392909216825260208201869052818101869052426060830152513392917fae96a66bcd5a00556ad548b9a949f8f45220d5859c013e5cedbddd6af8cf7b9d919081900360800190a360015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6000600180601c5460ff1660018111156140bd57fe5b146140c757600080fd5b601c54610100900460ff16156140dc57600080fd5b60065460408051602481018790526001600160a01b0386811660448084019190915283518084039091018152606490920183526020820180516001600160e01b0316600160e01b639bcc8e7b021781529251825160009560609593169392829180838360208310612e255780518252601f199092019160209182019101612e06565b60006001601c5460ff16600181111561417357fe5b1461418057506001612445565b60006203f480600b5442038161419257fe5b0690506201518081106141a65760016141a9565b60005b91505090565b60018054810190819055600080601c5460ff1660018111156141cd57fe5b146141d757600080fd5b836001600160a01b0381166141eb57600080fd5b6001600160a01b038116600080516020615dfc8339815191521461421b5761421281614c73565b61421b57600080fd5b6038546001600160a01b0386811691161480159061425057506001600160a01b038516600080516020615dfc83398151915214155b61425957600080fd5b603a5485906000908190614277906001600160a01b03168885614d51565b909450925061428991508290506154e8565b6142a36001600160a01b038416338463ffffffff61543616565b600954604080516001600160a01b038b1681526020810185905280820184905242606082015290513392917fae96a66bcd5a00556ad548b9a949f8f45220d5859c013e5cedbddd6af8cf7b9d919081900360800190a3505050505060015481146127e65760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6004546001600160a01b031681565b600080601c5460ff16600181111561436857fe5b1461437257600080fd5b6001805481019081905560006143866156a5565b905083156143e457614397816151e7565b600954603854604080516001600160a01b039290921682526020820184905281810184905242606083015251339291600080516020615e3c833981519152919081900360800190a361279e565b603a5461279e906001600160a01b0316338363ffffffff61543616565b670de0b6b3a764000081565b60176020526000908152604090205481565b600d5481565b61442d613bc5565b61446f5760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b6001600160a01b0381161580159061449057506001600160a01b0381163014155b61449957600080fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b66038d7ea4c6800081565b6722b1c8c1227a000081565b6001600160a01b031660009081526015602052604090205490565b600681565b60025460ff1681565b600180548101808255601c54909161010090910460ff1615151461451e57600080fd5b61452a600e60006117ef565b421161453557600080fd5b816001600160a01b03811661454957600080fd5b6001600160a01b038116600080516020615dfc833981519152146145795761457081614c73565b61457957600080fd5b6001600160a01b038316600080516020615dfc83398151915214156145e157601c546040516001600160a01b0363010000009092049190911690303180156108fc02916000818181858888f193505050501580156145db573d6000803e3d6000fd5b50612a42565b601c5460408051600160e01b6370a0823102815230600482015290518592614683926001600160a01b036301000000909204821692918516916370a0823191602480820192602092909190829003018186803b15801561464057600080fd5b505afa158015614654573d6000803e3d6000fd5b505050506040513d602081101561466a57600080fd5b50516001600160a01b038416919063ffffffff61543616565b50506001548114611f975760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b601260209081526000928352604080842090915290825290205481565b6001805481019081905560065460408051600481526024810182526020810180516001600160e01b0316600160e01b63bf8519bd02178152915181516000946001600160a01b03169382918083835b602083106147575780518252601f199092019160209182019101614738565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146147b7576040519150601f19603f3d011682016040523d82523d6000602084013e6147bc565b606091505b50509050806147ca57600080fd5b5060015481146119aa5760408051600160e51b62461bcd02815260206004820152601f6024820152600080516020615d95833981519152604482015290519081900360640190fd5b6039546001600160a01b031681565b68056bc75e2d6310000081565b601160209081526000928352604080842090915290825290205460ff1681565b6000600180601c5460ff16600181111561486457fe5b1461486e57600080fd5b601c54610100900460ff161561488357600080fd5b60065460408051602480820187905282518083039091018152604490910182526020810180516001600160e01b0316600160e01b63d2ec1fe702178152915181516000946060946001600160a01b0390911693929182919080838360208310611bd95780518252601f199092019160209182019101611bba565b6000600360095411158061491857506001600160a01b038216155b1561492557506000613488565b6035546009546001600160a01b0390911690634ee2cd7e90849060179060009061495690600363ffffffff614c1316565b8152602001908152602001600020546040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060206040518083038186803b1580156149b257600080fd5b505afa1580156149c6573d6000803e3d6000fd5b505050506040513d60208110156149dc57600080fd5b505192915050565b6003546001600160a01b031681565b6038546001600160a01b031681565b6008546001600160a01b031681565b601c5462010000900460ff1681565b60025461010090046001600160a01b031681565b614a3c613bc5565b614a7e5760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b6001600160a01b03166000908152601960205260409020805460ff19166001179055565b6027816005811061341b57fe5b60006001601c5460ff166001811115614ac457fe5b14614ad157506000612445565b6203f480600b54420381614ae157fe5b04905090565b60326020528260005260406000206020528160005260406000208160058110614b0c57fe5b602081049091015460ff601f9092166101000a900416925083915050565b614b32613bc5565b614b745760408051600160e51b62461bcd0281526020600482018190526024820152600080516020615e1c833981519152604482015290519081900360640190fd5b6119aa816157fc565b50600090565b601c5460ff1681565b60186020526000908152604090205481565b6007546001600160a01b031681565b600082820183811015614c0a5760408051600160e51b62461bcd02815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b600082821115614c6d5760408051600160e51b62461bcd02815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000806001600160a01b038316614c8e576000915050613488565b50503b151590565b60006001600160a01b038316600080516020615dfc8339815191521415614cc857506001600160a01b03811631614c0d565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015614d1e57600080fd5b505afa158015614d32573d6000803e3d6000fd5b505050506040513d6020811015614d4857600080fd5b50519392505050565b600080600080846001600160a01b0316876001600160a01b03161415614d7657600080fd5b603b5460408051600160e01b63809a9e550281526001600160a01b038a811660048301528881166024830152604482018a90528251600094919091169263809a9e559260648082019391829003018186803b158015614dd457600080fd5b505afa158015614de8573d6000803e3d6000fd5b505050506040513d6040811015614dfe57600080fd5b5060200151905080614e0f57600080fd5b6000614e1b8930614c96565b905060006001600160a01b038a16600080516020615dfc83398151915214614e865750603954600090614e61906001600160a01b038c811691168363ffffffff61589f16565b603954614e81906001600160a01b038c811691168b63ffffffff61589f16565b614e89565b50875b603b546001600160a01b03166329589f61828c8c8c614ea730612445565b6b204fce5e3e250261100000008a73332d87209f7c8296389c307eae170c2440830a47604051806040016040528060048152602001600160e01b635045524d028152506040518a63ffffffff1660e01b815260040180896001600160a01b03166001600160a01b03168152602001888152602001876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b03168152602001858152602001848152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614fa8578181015183820152602001614f90565b50505050905090810190601f168015614fd55780820380516001836020036101000a031916815260200191505b5099505050505050505050506020604051808303818588803b158015614ffa57600080fd5b505af115801561500e573d6000803e3d6000fd5b50505050506040513d602081101561502557600080fd5b505194508461503357600080fd5b6001600160a01b038a16600080516020615dfc8339815191521461507257603954615072906001600160a01b038c81169116600063ffffffff61589f16565b61508c61507f8b30614c96565b839063ffffffff614c1316565b93506150aa858561509c8b6159bb565b6150a58e6159bb565b615a52565b96506150c384866150ba8d6159bb565b6150a58c6159bb565b955050505093509350935093565b33600090815260116020908152604080832084845290915281205460ff16156150f957600080fd5b600061510533846136b0565b3360009081526011602090815260408083208884529091529020805460ff19166001179055600d549193509150615142908363ffffffff614c1316565b600d55600954600090815260166020526040902054615167908263ffffffff614bad16565b6009546000908152601660209081526040808320939093553382526014905290812061519291615cd6565b3360009081526015602052604081206151aa91615cf7565b604080518381529051339185917fec530ab710fdaa2b5968fe15f486992441a96f643219cf0150904aa5b9eedf829181900360200190a350919050565b603660009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561523557600080fd5b505afa158015615249573d6000803e3d6000fd5b505050506040513d602081101561525f57600080fd5b5051158061526d5750600a54155b156153035760365460408051600160e61b630209fccb0281523360048201526024810184905290516001600160a01b039092169163827f32c0916044808201926020929091908290030181600087803b1580156152c957600080fd5b505af11580156152dd573d6000803e3d6000fd5b505050506040513d60208110156152f357600080fd5b50516152fe57600080fd5b61541d565b603654600a5460408051600160e01b6318160ddd02815290516001600160a01b039093169263827f32c0923392615399926138529187916318160ddd91600480820192602092909190829003018186803b15801561536057600080fd5b505afa158015615374573d6000803e3d6000fd5b505050506040513d602081101561538a57600080fd5b5051879063ffffffff6155dc16565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156153e857600080fd5b505af11580156153fc573d6000803e3d6000fd5b505050506040513d602081101561541257600080fd5b505161541d57600080fd5b600a54615430908263ffffffff614bad16565b600a5550565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0316600160e01b63a9059cbb021790526127e6908490615af1565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b0316600160e01b6323b872dd02179052611b20908590615af1565b603654600a5460408051600160e01b6318160ddd02815290516001600160a01b039093169263d3ce77fe923392615545926138529187916318160ddd91600480820192602092909190829003018186803b15801561536057600080fd5b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561559457600080fd5b505af11580156155a8573d6000803e3d6000fd5b505050506040513d60208110156155be57600080fd5b50516155c957600080fd5b600a54615430908263ffffffff614c1316565b6000826155eb57506000614c0d565b828202828482816155f857fe5b0414614c0a57604051600160e51b62461bcd028152600401808060200182810382526021815260200180615ddb6021913960400191505060405180910390fd5b60008082116156915760408051600160e51b62461bcd02815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b600082848161569c57fe5b04949350505050565b600954336000908152601060205260408120549091116156c457600080fd5b60006156cf33612ff8565b3360009081526010602052604090205491935091505b60095481101561572f573360009081526011602090815260408083208484529091529020805460ff1916600190811790915561572890829063ffffffff614bad16565b90506156e5565b5060095433600090815260106020526040902055600d54615756908363ffffffff614c1316565b600d5560095460009081526016602052604090205461577b908263ffffffff614bad16565b600954600090815260166020908152604080832093909355338252601490529081206157a691615cd6565b3360009081526015602052604081206157be91615cf7565b6009546040805184815290513392917fec530ab710fdaa2b5968fe15f486992441a96f643219cf0150904aa5b9eedf82919081900360200190a35090565b6001600160a01b03811661584457604051600160e51b62461bcd028152600401808060200182810382526026815260200180615db56026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b801580615928575060408051600160e11b636eb1769f0281523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b1580156158fa57600080fd5b505afa15801561590e573d6000803e3d6000fd5b505050506040513d602081101561592457600080fd5b5051155b61596657604051600160e51b62461bcd028152600401808060200182810382526036815260200180615e866036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0316600160e01b63095ea7b3021790526127e6908490615af1565b60006001600160a01b038216600080516020615dfc83398151915214156159e457506012613488565b816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015615a1d57600080fd5b505afa158015615a31573d6000803e3d6000fd5b505050506040513d6020811015615a4757600080fd5b505160ff1692915050565b60006b204fce5e3e25026110000000851115615a6d57600080fd5b6b204fce5e3e25026110000000841115615a8657600080fd5b828210615abf5760128383031115615a9d57600080fd5b84838303600a0a02670de0b6b3a7640000850281615ab757fe5b049050615ae9565b60128284031115615acf57600080fd5b84828403600a0a670de0b6b3a764000086020281615ab757fe5b949350505050565b615b03826001600160a01b0316615cb2565b615b575760408051600160e51b62461bcd02815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310615b955780518252601f199092019160209182019101615b76565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114615bf7576040519150601f19603f3d011682016040523d82523d6000602084013e615bfc565b606091505b509150915081615c565760408051600160e51b62461bcd02815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115611b2057808060200190516020811015615c7257600080fd5b5051611b2057604051600160e51b62461bcd02815260040180806020018281038252602a815260200180615e5c602a913960400191505060405180910390fd5b3b151590565b60405180604001604052806002906020820280388339509192915050565b50805460008255600902906000526020600020908101906119aa9190615d15565b50805460008255906000526020600020908101906119aa9190615d7a565b61244591905b80821115615d765780546001600160a01b03191681556000600182018190556002820181905560038201819055600482018190556005820181905560068201819055600782015560088101805460ff19169055600901615d1b565b5090565b61244591905b80821115615d765760008155600101615d8056fe5265656e7472616e637947756172643a207265656e7472616e742063616c6c004f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65727ee7a1de9c18ce695c95b8b19fbdf26cce3544e3ca9e08c9f487776783d7599f5361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a165627a7a723058204e1bbf357632776bcdcb838d2032d64c5b23cdecf17f5064fa399480001069510029

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

000000000000000000000000952bbd5344ca0a898a1b8b2ffcfe3acb1351ebd50000000000000000000000001689dcfef3e695ac4cc1e5b7e77f9135f1d58a50000000000000000000000000332d87209f7c8296389c307eae170c2440830a47000000000000000000000000000000000000000000000000000000000003f480000000000000000000000000000000000000000000000000000000000023988000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000818e6fecd516ecc3849daf6845e3ec868087b755000000000000000000000000f9b8d8137de64de61cd582518ebc5345d01d5039000000000000000000000000d176ff3d44fdae552bdc5b566fa1f0066e81fe0b

-----Decoded View---------------
Arg [0] : _kroAddr (address): 0x952BBd5344CA0A898a1b8b2fFcfE3acb1351ebd5
Arg [1] : _sTokenAddr (address): 0x1689dCfef3E695ac4CC1e5B7E77F9135f1d58A50
Arg [2] : _devFundingAccount (address): 0x332D87209f7c8296389C307eAe170c2440830A47
Arg [3] : _phaseLengths (uint256[2]): 259200,2332800
Arg [4] : _devFundingRate (uint256): 1000000000000000
Arg [5] : _previousVersion (address): 0x0000000000000000000000000000000000000000
Arg [6] : _daiAddr (address): 0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359
Arg [7] : _kyberAddr (address): 0x818E6FECD516Ecc3849DAf6845e3EC868087B755
Arg [8] : _compoundFactoryAddr (address): 0xf9B8d8137dE64DE61cD582518Ebc5345D01D5039
Arg [9] : _betokenLogic (address): 0xD176ff3D44fDAe552bDC5b566fa1F0066E81fe0b

-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 000000000000000000000000952bbd5344ca0a898a1b8b2ffcfe3acb1351ebd5
Arg [1] : 0000000000000000000000001689dcfef3e695ac4cc1e5b7e77f9135f1d58a50
Arg [2] : 000000000000000000000000332d87209f7c8296389c307eae170c2440830a47
Arg [3] : 000000000000000000000000000000000000000000000000000000000003f480
Arg [4] : 0000000000000000000000000000000000000000000000000000000000239880
Arg [5] : 00000000000000000000000000000000000000000000000000038d7ea4c68000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 00000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359
Arg [8] : 000000000000000000000000818e6fecd516ecc3849daf6845e3ec868087b755
Arg [9] : 000000000000000000000000f9b8d8137de64de61cd582518ebc5345d01d5039
Arg [10] : 000000000000000000000000d176ff3d44fdae552bdc5b566fa1f0066e81fe0b


Swarm Source

bzzr://4e1bbf357632776bcdcb838d2032d64c5b23cdecf17f5064fa39948000106951

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.