ETH Price: $2,417.45 (-1.25%)
Gas: 1.6 Gwei

Token

ERC20 ***
 

Overview

Max Total Supply

1,107,523.61715148 ERC20 ***

Holders

40

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 8 Decimals)

Filtered by Token Holder
Uniswap: ocDai 2
Balance
2,255.70086607 ERC20 ***

Value
$0.00
0x8a0976500eed661202810bab030a057df15c4cc9
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
oToken

Compiler Version
v0.5.10+commit.5a6ea5b1

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, Unlicense license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-02-11
*/

// File: @openzeppelin/contracts/GSN/Context.sol

pragma solidity ^0.5.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

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

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol

pragma solidity ^0.5.0;

/**
 * @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.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

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

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

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

// File: @openzeppelin/contracts/math/SafeMath.sol

pragma solidity ^0.5.0;

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

        return c;
    }

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

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

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

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

        return c;
    }

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

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

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

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

// File: @openzeppelin/contracts/token/ERC20/ERC20.sol

pragma solidity ^0.5.0;




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

    mapping (address => uint256) private _balances;

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

    uint256 private _totalSupply;

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

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

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

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

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

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

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

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

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

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

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

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

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

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

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

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

    /**
     * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
     * from the caller's allowance.
     *
     * See {_burn} and {_approve}.
     */
    function _burnFrom(address account, uint256 amount) internal {
        _burn(account, amount);
        _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
    }
}

// File: contracts/lib/CompoundOracleInterface.sol

pragma solidity ^0.5.0;
// AT MAINNET ADDRESS: 0x02557a5E05DeFeFFD4cAe6D83eA3d173B272c904

contract CompoundOracleInterface {
    // returns asset:eth -- to get USDC:eth, have to do 10**24/result,


    constructor() public {
    }

    /**
  * @notice retrieves price of an asset
  * @dev function to get price for an asset
  * @param asset Asset for which to get the price
  * @return uint mantissa of asset price (scaled by 1e18) or zero if unset or contract paused
  */
    function getPrice(address asset) public view returns (uint);
    function getUnderlyingPrice(ERC20 cToken) public view returns (uint);
    // function getPrice(address asset) public view returns (uint) {
    //     return 527557000000000;
    // }

}

// File: contracts/lib/UniswapExchangeInterface.sol

pragma solidity 0.5.10;


// Solidity Interface
contract UniswapExchangeInterface {
    // Address of ERC20 token sold on this exchange
    function tokenAddress() external view returns (address token);
    // Address of Uniswap Factory
    function factoryAddress() external view returns (address factory);
    // Provide Liquidity
    function addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline) external payable returns (uint256);
    function removeLiquidity(uint256 amount, uint256 min_eth, uint256 min_tokens, uint256 deadline) external returns (uint256, uint256);
    // Get Prices
    function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought);
    function getEthToTokenOutputPrice(uint256 tokens_bought) external view returns (uint256 eth_sold);
    function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 eth_bought);
    function getTokenToEthOutputPrice(uint256 eth_bought) external view returns (uint256 tokens_sold);
    // Trade ETH to ERC20
    function ethToTokenSwapInput(uint256 min_tokens, uint256 deadline) external payable returns (uint256  tokens_bought);
    function ethToTokenTransferInput(uint256 min_tokens, uint256 deadline, address recipient) external payable returns (uint256  tokens_bought);
    function ethToTokenSwapOutput(uint256 tokens_bought, uint256 deadline) external payable returns (uint256  eth_sold);
    function ethToTokenTransferOutput(uint256 tokens_bought, uint256 deadline, address recipient) external payable returns (uint256  eth_sold);
    // Trade ERC20 to ETH
    function tokenToEthSwapInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline) external returns (uint256  eth_bought);
    function tokenToEthTransferInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline, address recipient) external returns (uint256  eth_bought);
    function tokenToEthSwapOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline) external returns (uint256  tokens_sold);
    function tokenToEthTransferOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline, address recipient) external returns (uint256  tokens_sold);
    // Trade ERC20 to ERC20
    function tokenToTokenSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address token_addr) external returns (uint256  tokens_bought);
    function tokenToTokenTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address token_addr) external returns (uint256  tokens_bought);
    function tokenToTokenSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address token_addr) external returns (uint256  tokens_sold);
    function tokenToTokenTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address token_addr) external returns (uint256  tokens_sold);
    // Trade ERC20 to Custom Pool
    function tokenToExchangeSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address exchange_addr) external returns (uint256  tokens_bought);
    function tokenToExchangeTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address exchange_addr) external returns (uint256  tokens_bought);
    function tokenToExchangeSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address exchange_addr) external returns (uint256  tokens_sold);
    function tokenToExchangeTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address exchange_addr) external returns (uint256  tokens_sold);
    // ERC20 comaptibility for liquidity tokens
    bytes32 public name;
    bytes32 public symbol;
    uint256 public decimals;
    function transfer(address _to, uint256 _value) external returns (bool);
    function transferFrom(address _from, address _to, uint256 value) external returns (bool);
    function approve(address _spender, uint256 _value) external returns (bool);
    function allowance(address _owner, address _spender) external view returns (uint256);
    function balanceOf(address _owner) external view returns (uint256);
    function totalSupply() external view returns (uint256);
    // Never use
    function setup(address token_addr) external;
}

// File: contracts/lib/UniswapFactoryInterface.sol

pragma solidity 0.5.10;


// Solidity Interface
contract UniswapFactoryInterface {
    // Public Variables
    address public exchangeTemplate;
    uint256 public tokenCount;
    // // Create Exchange
    function createExchange(address token) external returns (address exchange);
    // Get Exchange and Token Info
    function getExchange(address token) external view returns (address exchange);
    function getToken(address exchange) external view returns (address token);
    function getTokenWithId(uint256 tokenId) external view returns (address token);
    // Never use
    function initializeFactory(address template) external;
    // function createExchange(address token) external returns (address exchange) {
    //     return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128;
    // }
    // // Get Exchange and Token Info
    // function getExchange(address token) external view returns (address exchange){
    //     return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128;
    // }
    // function getToken(address exchange) external view returns (address token) {
    //     return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128;
    // }
    // function getTokenWithId(uint256 tokenId) external view returns (address token) {
    //     return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128;
    // }
}

// File: contracts/OptionsUtils.sol

pragma solidity 0.5.10;





contract OptionsUtils {
    // defauls are for mainnet
    UniswapFactoryInterface public UNISWAP_FACTORY;

    CompoundOracleInterface public COMPOUND_ORACLE;

    constructor(address _uniswapFactory, address _compoundOracle) public {
        UNISWAP_FACTORY = UniswapFactoryInterface(_uniswapFactory);
        COMPOUND_ORACLE = CompoundOracleInterface(_compoundOracle);
    }

    // TODO: for now gets Uniswap, later update to get other exchanges
    function getExchange(address _token)
        public
        view
        returns (UniswapExchangeInterface)
    {
        if (address(UNISWAP_FACTORY.getExchange(_token)) == address(0)) {
            revert("No payout exchange");
        }

        UniswapExchangeInterface exchange = UniswapExchangeInterface(
            UNISWAP_FACTORY.getExchange(_token)
        );

        return exchange;
    }

    function isETH(IERC20 _ierc20) public pure returns (bool) {
        return _ierc20 == IERC20(0);
    }
}

// File: contracts/OptionsExchange.sol

pragma solidity 0.5.10;






contract OptionsExchange {
    uint256 constant LARGE_BLOCK_SIZE = 1651753129000;
    uint256 constant LARGE_APPROVAL_NUMBER = 10**30;

    UniswapFactoryInterface public UNISWAP_FACTORY;

    constructor(address _uniswapFactory) public {
        UNISWAP_FACTORY = UniswapFactoryInterface(_uniswapFactory);
    }

    /*** Events ***/
    event SellOTokens(
        address seller,
        address payable receiver,
        address oTokenAddress,
        address payoutTokenAddress,
        uint256 oTokensToSell
    );
    event BuyOTokens(
        address buyer,
        address payable receiver,
        address oTokenAddress,
        address paymentTokenAddress,
        uint256 oTokensToBuy,
        uint256 premiumPaid
    );

    /**
    * @notice This function sells oTokens on Uniswap and sends back payoutTokens to the receiver
    * @param receiver The address to send the payout tokens back to
    * @param oTokenAddress The address of the oToken to sell
    * @param payoutTokenAddress The address of the token to receive the premiums in
    * @param oTokensToSell The number of oTokens to sell
    */
    function sellOTokens(
        address payable receiver,
        address oTokenAddress,
        address payoutTokenAddress,
        uint256 oTokensToSell
    ) public {
        // @note: first need to bootstrap the uniswap exchange to get the address.
        IERC20 oToken = IERC20(oTokenAddress);
        IERC20 payoutToken = IERC20(payoutTokenAddress);
        oToken.transferFrom(msg.sender, address(this), oTokensToSell);
        uniswapSellOToken(oToken, payoutToken, oTokensToSell, receiver);

        emit SellOTokens(
            msg.sender,
            receiver,
            oTokenAddress,
            payoutTokenAddress,
            oTokensToSell
        );
    }

    /**
    * @notice This function buys oTokens on Uniswap and using paymentTokens from the receiver
    * @param receiver The address to send the oTokens back to
    * @param oTokenAddress The address of the oToken to buy
    * @param paymentTokenAddress The address of the token to pay the premiums in
    * @param oTokensToBuy The number of oTokens to buy
    */
    function buyOTokens(
        address payable receiver,
        address oTokenAddress,
        address paymentTokenAddress,
        uint256 oTokensToBuy
    ) public payable {
        IERC20 oToken = IERC20(oTokenAddress);
        IERC20 paymentToken = IERC20(paymentTokenAddress);
        uniswapBuyOToken(paymentToken, oToken, oTokensToBuy, receiver);
    }

    /**
    * @notice This function calculates the amount of premiums that the seller
    * will receive if they sold oTokens on Uniswap
    * @param oTokenAddress The address of the oToken to sell
    * @param payoutTokenAddress The address of the token to receive the premiums in
    * @param oTokensToSell The number of oTokens to sell
    */
    function premiumReceived(
        address oTokenAddress,
        address payoutTokenAddress,
        uint256 oTokensToSell
    ) public view returns (uint256) {
        // get the amount of ETH that will be paid out if oTokensToSell is sold.
        UniswapExchangeInterface oTokenExchange = getExchange(oTokenAddress);
        uint256 ethReceived = oTokenExchange.getTokenToEthInputPrice(
            oTokensToSell
        );

        if (!isETH(IERC20(payoutTokenAddress))) {
            // get the amount of payout tokens that will be received if the ethRecieved is sold.
            UniswapExchangeInterface payoutExchange = getExchange(
                payoutTokenAddress
            );
            return payoutExchange.getEthToTokenInputPrice(ethReceived);
        }
        return ethReceived;

    }

    /**
    * @notice This function calculates the premiums to be paid if a buyer wants to
    * buy oTokens on Uniswap
    * @param oTokenAddress The address of the oToken to buy
    * @param paymentTokenAddress The address of the token to pay the premiums in
    * @param oTokensToBuy The number of oTokens to buy
    */
    function premiumToPay(
        address oTokenAddress,
        address paymentTokenAddress,
        uint256 oTokensToBuy
    ) public view returns (uint256) {
        // get the amount of ETH that needs to be paid for oTokensToBuy.
        UniswapExchangeInterface oTokenExchange = getExchange(oTokenAddress);
        uint256 ethToPay = oTokenExchange.getEthToTokenOutputPrice(
            oTokensToBuy
        );

        if (!isETH(IERC20(paymentTokenAddress))) {
            // get the amount of paymentTokens that needs to be paid to get the desired ethToPay.
            UniswapExchangeInterface paymentTokenExchange = getExchange(
                paymentTokenAddress
            );
            return paymentTokenExchange.getTokenToEthOutputPrice(ethToPay);
        }

        return ethToPay;
    }

    function uniswapSellOToken(
        IERC20 oToken,
        IERC20 payoutToken,
        uint256 _amt,
        address payable _transferTo
    ) internal returns (uint256) {
        require(!isETH(oToken), "Can only sell oTokens");
        UniswapExchangeInterface exchange = getExchange(address(oToken));

        if (isETH(payoutToken)) {
            //Token to ETH
            oToken.approve(address(exchange), _amt);
            return
                exchange.tokenToEthTransferInput(
                    _amt,
                    1,
                    LARGE_BLOCK_SIZE,
                    _transferTo
                );
        } else {
            //Token to Token
            oToken.approve(address(exchange), _amt);
            return
                exchange.tokenToTokenTransferInput(
                    _amt,
                    1,
                    1,
                    LARGE_BLOCK_SIZE,
                    _transferTo,
                    address(payoutToken)
                );
        }
    }

    function uniswapBuyOToken(
        IERC20 paymentToken,
        IERC20 oToken,
        uint256 _amt,
        address payable _transferTo
    ) public returns (uint256) {
        require(!isETH(oToken), "Can only buy oTokens");

        if (!isETH(paymentToken)) {
            UniswapExchangeInterface exchange = getExchange(
                address(paymentToken)
            );

            uint256 paymentTokensToTransfer = premiumToPay(
                address(oToken),
                address(paymentToken),
                _amt
            );
            paymentToken.transferFrom(
                msg.sender,
                address(this),
                paymentTokensToTransfer
            );

            // Token to Token
            paymentToken.approve(address(exchange), LARGE_APPROVAL_NUMBER);

            emit BuyOTokens(
                msg.sender,
                _transferTo,
                address(oToken),
                address(paymentToken),
                _amt,
                paymentTokensToTransfer
            );

            return
                exchange.tokenToTokenTransferInput(
                    paymentTokensToTransfer,
                    1,
                    1,
                    LARGE_BLOCK_SIZE,
                    _transferTo,
                    address(oToken)
                );
        } else {
            // ETH to Token
            UniswapExchangeInterface exchange = UniswapExchangeInterface(
                UNISWAP_FACTORY.getExchange(address(oToken))
            );

            uint256 ethToTransfer = exchange.getEthToTokenOutputPrice(_amt);

            emit BuyOTokens(
                msg.sender,
                _transferTo,
                address(oToken),
                address(paymentToken),
                _amt,
                ethToTransfer
            );

            return
                exchange.ethToTokenTransferOutput.value(ethToTransfer)(
                    _amt,
                    LARGE_BLOCK_SIZE,
                    _transferTo
                );
        }
    }

    function getExchange(address _token)
        internal
        view
        returns (UniswapExchangeInterface)
    {
        UniswapExchangeInterface exchange = UniswapExchangeInterface(
            UNISWAP_FACTORY.getExchange(_token)
        );

        if (address(exchange) == address(0)) {
            revert("No payout exchange");
        }

        return exchange;
    }

    function isETH(IERC20 _ierc20) internal pure returns (bool) {
        return _ierc20 == IERC20(0);
    }

    function() external payable {
        // to get ether from uniswap exchanges
    }

}

// File: @openzeppelin/contracts/token/ERC20/ERC20Detailed.sol

pragma solidity ^0.5.0;


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

// File: @openzeppelin/contracts/ownership/Ownable.sol

pragma solidity ^0.5.0;

/**
 * @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 applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        _owner = _msgSender();
        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 _msgSender() == _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;
    }
}

// File: contracts/OptionsContract.sol

pragma solidity 0.5.10;











/**
 * @title Opyn's Options Contract
 * @author Opyn
 */
contract OptionsContract is Ownable, ERC20 {
    using SafeMath for uint256;

    /* represents floting point numbers, where number = value * 10 ** exponent
    i.e 0.1 = 10 * 10 ** -3 */
    struct Number {
        uint256 value;
        int32 exponent;
    }

    // Keeps track of the weighted collateral and weighted debt for each vault.
    struct Vault {
        uint256 collateral;
        uint256 oTokensIssued;
        uint256 underlying;
        bool owned;
    }

    OptionsExchange public optionsExchange;

    mapping(address => Vault) internal vaults;

    address payable[] internal vaultOwners;

    // 10 is 0.01 i.e. 1% incentive.
    Number public liquidationIncentive = Number(10, -3);

    // 100 is egs. 0.1 i.e. 10%.
    Number public transactionFee = Number(0, -3);

    /* 500 is 0.5. Max amount that a Vault can be liquidated by i.e.
    max collateral that can be taken in one function call */
    Number public liquidationFactor = Number(500, -3);

    /* 16 means 1.6. The minimum ratio of a Vault's collateral to insurance promised.
    The ratio is calculated as below:
    vault.collateral / (Vault.oTokensIssued * strikePrice) */
    Number public minCollateralizationRatio = Number(16, -1);

    // The amount of insurance promised per oToken
    Number public strikePrice;

    // The amount of underlying that 1 oToken protects.
    Number public oTokenExchangeRate;

    /* UNIX time.
    Exercise period starts at `(expiry - windowSize)` and ends at `expiry` */
    uint256 internal windowSize;

    /* The total fees accumulated in the contract any time liquidate or exercise is called */
    uint256 internal totalFee;

    // The time of expiry of the options contract
    uint256 public expiry;

    // The precision of the collateral
    int32 public collateralExp = -18;

    // The precision of the underlying
    int32 public underlyingExp = -18;

    // The collateral asset
    IERC20 public collateral;

    // The asset being protected by the insurance
    IERC20 public underlying;

    // The asset in which insurance is denominated in.
    IERC20 public strike;

    // The Oracle used for the contract
    CompoundOracleInterface public COMPOUND_ORACLE;

    // The name of  the contract
    string public name;

    // The symbol of  the contract
    string public symbol;

    // The number of decimals of the contract
    uint8 public decimals;

    /**
    * @param _collateral The collateral asset
    * @param _collExp The precision of the collateral (-18 if ETH)
    * @param _underlying The asset that is being protected
    * @param _underlyingExp The precision of the underlying asset
    * @param _oTokenExchangeExp The precision of the `amount of underlying` that 1 oToken protects
    * @param _strikePrice The amount of strike asset that will be paid out per oToken
    * @param _strikeExp The precision of the strike price.
    * @param _strike The asset in which the insurance is calculated
    * @param _expiry The time at which the insurance expires
    * @param _optionsExchange The contract which interfaces with the exchange + oracle
    * @param _oracleAddress The address of the oracle
    * @param _windowSize UNIX time. Exercise window is from `expiry - _windowSize` to `expiry`.
    */
    constructor(
        IERC20 _collateral,
        int32 _collExp,
        IERC20 _underlying,
        int32 _underlyingExp,
        int32 _oTokenExchangeExp,
        uint256 _strikePrice,
        int32 _strikeExp,
        IERC20 _strike,
        uint256 _expiry,
        OptionsExchange _optionsExchange,
        address _oracleAddress,
        uint256 _windowSize
    ) public {
        require(block.timestamp < _expiry, "Can't deploy an expired contract");
        require(
            _windowSize <= _expiry,
            "Exercise window can't be longer than the contract's lifespan"
        );
        require(
            isWithinExponentRange(_collExp),
            "collateral exponent not within expected range"
        );
        require(
            isWithinExponentRange(_underlyingExp),
            "underlying exponent not within expected range"
        );
        require(
            isWithinExponentRange(_strikeExp),
            "strike price exponent not within expected range"
        );
        require(
            isWithinExponentRange(_oTokenExchangeExp),
            "oToken exchange rate exponent not within expected range"
        );

        collateral = _collateral;
        collateralExp = _collExp;

        underlying = _underlying;
        underlyingExp = _underlyingExp;
        oTokenExchangeRate = Number(1, _oTokenExchangeExp);

        strikePrice = Number(_strikePrice, _strikeExp);
        strike = _strike;

        expiry = _expiry;
        COMPOUND_ORACLE = CompoundOracleInterface(_oracleAddress);
        optionsExchange = _optionsExchange;
        windowSize = _windowSize;
    }

    /*** Events ***/
    event VaultOpened(address payable vaultOwner);
    event ETHCollateralAdded(
        address payable vaultOwner,
        uint256 amount,
        address payer
    );
    event ERC20CollateralAdded(
        address payable vaultOwner,
        uint256 amount,
        address payer
    );
    event IssuedOTokens(
        address issuedTo,
        uint256 oTokensIssued,
        address payable vaultOwner
    );
    event Liquidate(
        uint256 amtCollateralToPay,
        address payable vaultOwner,
        address payable liquidator
    );
    event Exercise(
        uint256 amtUnderlyingToPay,
        uint256 amtCollateralToPay,
        address payable exerciser,
        address payable vaultExercisedFrom
    );
    event RedeemVaultBalance(
        uint256 amtCollateralRedeemed,
        uint256 amtUnderlyingRedeemed,
        address payable vaultOwner
    );
    event BurnOTokens(address payable vaultOwner, uint256 oTokensBurned);
    event RemoveCollateral(uint256 amtRemoved, address payable vaultOwner);
    event UpdateParameters(
        uint256 liquidationIncentive,
        uint256 liquidationFactor,
        uint256 transactionFee,
        uint256 minCollateralizationRatio,
        address owner
    );
    event TransferFee(address payable to, uint256 fees);
    event RemoveUnderlying(
        uint256 amountUnderlying,
        address payable vaultOwner
    );

    /**
     * @dev Throws if called Options contract is expired.
     */
    modifier notExpired() {
        require(!hasExpired(), "Options contract expired");
        _;
    }

    /**
     * @notice This function gets the array of vaultOwners
     */
    function getVaultOwners() public view returns (address payable[] memory) {
        address payable[] memory owners;
        uint256 index = 0;
        for (uint256 i = 0; i < vaultOwners.length; i++) {
            if (hasVault(vaultOwners[i])) {
                owners[index] = vaultOwners[i];
                index++;
            }
        }

        return owners;
    }

    /**
     * @notice Can only be called by owner. Used to update the fees, minminCollateralizationRatio, etc
     * @param _liquidationIncentive The incentive paid to liquidator. 10 is 0.01 i.e. 1% incentive.
     * @param _liquidationFactor Max amount that a Vault can be liquidated by. 500 is 0.5.
     * @param _transactionFee The fees paid to our protocol every time a execution happens. 100 is egs. 0.1 i.e. 10%.
     * @param _minCollateralizationRatio The minimum ratio of a Vault's collateral to insurance promised. 16 means 1.6.
     */
    function updateParameters(
        uint256 _liquidationIncentive,
        uint256 _liquidationFactor,
        uint256 _transactionFee,
        uint256 _minCollateralizationRatio
    ) public onlyOwner {
        require(
            _liquidationIncentive <= 200,
            "Can't have >20% liquidation incentive"
        );
        require(
            _liquidationFactor <= 1000,
            "Can't liquidate more than 100% of the vault"
        );
        require(_transactionFee <= 100, "Can't have transaction fee > 10%");
        require(
            _minCollateralizationRatio >= 10,
            "Can't have minCollateralizationRatio < 1"
        );

        liquidationIncentive.value = _liquidationIncentive;
        liquidationFactor.value = _liquidationFactor;
        transactionFee.value = _transactionFee;
        minCollateralizationRatio.value = _minCollateralizationRatio;

        emit UpdateParameters(
            _liquidationIncentive,
            _liquidationFactor,
            _transactionFee,
            _minCollateralizationRatio,
            owner()
        );
    }

    /**
     * @notice Can only be called by owner. Used to set the name, symbol and decimals of the contract
     * @param _name The name of the contract
     * @param _symbol The symbol of the contract
     */
    function setDetails(string memory _name, string memory _symbol)
        public
        onlyOwner
    {
        name = _name;
        symbol = _symbol;
        decimals = uint8(-1 * oTokenExchangeRate.exponent);
        require(
            decimals >= 0,
            "1 oToken cannot protect less than the smallest unit of the asset"
        );
    }

    /**
     * @notice Can only be called by owner. Used to take out the protocol fees from the contract.
     * @param _address The address to send the fee to.
     */
    function transferFee(address payable _address) public onlyOwner {
        uint256 fees = totalFee;
        totalFee = 0;
        transferCollateral(_address, fees);

        emit TransferFee(_address, fees);
    }

    /**
     * @notice Checks if a `owner` has already created a Vault
     * @param owner The address of the supposed owner
     * @return true or false
     */
    function hasVault(address payable owner) public view returns (bool) {
        return vaults[owner].owned;
    }

    /**
     * @notice Creates a new empty Vault and sets the owner of the vault to be the msg.sender.
     */
    function openVault() public notExpired returns (bool) {
        require(!hasVault(msg.sender), "Vault already created");

        vaults[msg.sender] = Vault(0, 0, 0, true);
        vaultOwners.push(msg.sender);

        emit VaultOpened(msg.sender);
        return true;
    }

    /**
     * @notice If the collateral type is ETH, anyone can call this function any time before
     * expiry to increase the amount of collateral in a Vault. Will fail if ETH is not the
     * collateral asset.
     * Remember that adding ETH collateral even if no oTokens have been created can put the owner at a
     * risk of losing the collateral if an exercise event happens.
     * Ensure that you issue and immediately sell oTokens to allow the owner to earn premiums.
     * (Either call the createAndSell function in the oToken contract or batch the
     * addERC20Collateral, issueOTokens and sell transactions and ensure they happen atomically to protect
     * the end user).
     * @param vaultOwner the index of the Vault to which collateral will be added.
     */
    function addETHCollateral(address payable vaultOwner)
        public
        payable
        notExpired
        returns (uint256)
    {
        require(isETH(collateral), "ETH is not the specified collateral type");
        require(hasVault(vaultOwner), "Vault does not exist");

        emit ETHCollateralAdded(vaultOwner, msg.value, msg.sender);
        return _addCollateral(vaultOwner, msg.value);
    }

    /**
     * @notice If the collateral type is any ERC20, anyone can call this function any time before
     * expiry to increase the amount of collateral in a Vault. Can only transfer in the collateral asset.
     * Will fail if ETH is the collateral asset.
     * The user has to allow the contract to handle their ERC20 tokens on his behalf before these
     * functions are called.
     * Remember that adding ERC20 collateral even if no oTokens have been created can put the owner at a
     * risk of losing the collateral. Ensure that you issue and immediately sell the oTokens!
     * (Either call the createAndSell function in the oToken contract or batch the
     * addERC20Collateral, issueOTokens and sell transactions and ensure they happen atomically to protect
     * the end user).
     * @param vaultOwner the index of the Vault to which collateral will be added.
     * @param amt the amount of collateral to be transferred in.
     */
    function addERC20Collateral(address payable vaultOwner, uint256 amt)
        public
        notExpired
        returns (uint256)
    {
        require(
            collateral.transferFrom(msg.sender, address(this), amt),
            "Could not transfer in collateral tokens"
        );
        require(hasVault(vaultOwner), "Vault does not exist");

        emit ERC20CollateralAdded(vaultOwner, amt, msg.sender);
        return _addCollateral(vaultOwner, amt);
    }

    /**
     * @notice Returns the amount of underlying to be transferred during an exercise call
     */
    function underlyingRequiredToExercise(uint256 oTokensToExercise)
        public
        view
        returns (uint256)
    {
        uint64 underlyingPerOTokenExp = uint64(
            oTokenExchangeRate.exponent - underlyingExp
        );
        return oTokensToExercise.mul(10**underlyingPerOTokenExp);
    }

    /**
     * @notice Returns true if exercise can be called
     */
    function isExerciseWindow() public view returns (bool) {
        return ((block.timestamp >= expiry.sub(windowSize)) &&
            (block.timestamp < expiry));
    }

    /**
     * @notice Returns true if the oToken contract has expired
     */
    function hasExpired() public view returns (bool) {
        return (block.timestamp >= expiry);
    }

    /**
     * @notice Called by anyone holding the oTokens and underlying during the
     * exercise window i.e. from `expiry - windowSize` time to `expiry` time. The caller
     * transfers in their oTokens and corresponding amount of underlying and gets
     * `strikePrice * oTokens` amount of collateral out. The collateral paid out is taken from
     * the each vault owner starting with the first and iterating until the oTokens to exercise
     * are found.
     * NOTE: This uses a for loop and hence could run out of gas if the array passed in is too big!
     * @param oTokensToExercise the number of oTokens being exercised.
     * @param vaultsToExerciseFrom the array of vaults to exercise from.
     */
    function exercise(
        uint256 oTokensToExercise,
        address payable[] memory vaultsToExerciseFrom
    ) public payable {
        for (uint256 i = 0; i < vaultsToExerciseFrom.length; i++) {
            address payable vaultOwner = vaultsToExerciseFrom[i];
            require(
                hasVault(vaultOwner),
                "Cannot exercise from a vault that doesn't exist"
            );
            Vault storage vault = vaults[vaultOwner];
            if (oTokensToExercise == 0) {
                return;
            } else if (vault.oTokensIssued >= oTokensToExercise) {
                _exercise(oTokensToExercise, vaultOwner);
                return;
            } else {
                oTokensToExercise = oTokensToExercise.sub(vault.oTokensIssued);
                _exercise(vault.oTokensIssued, vaultOwner);
            }
        }
        require(
            oTokensToExercise == 0,
            "Specified vaults have insufficient collateral"
        );
    }

    /**
     * @notice This function allows the vault owner to remove their share of underlying after an exercise
     */
    function removeUnderlying() public {
        require(hasVault(msg.sender), "Vault does not exist");
        Vault storage vault = vaults[msg.sender];

        require(vault.underlying > 0, "No underlying balance");

        uint256 underlyingToTransfer = vault.underlying;
        vault.underlying = 0;

        transferUnderlying(msg.sender, underlyingToTransfer);
        emit RemoveUnderlying(underlyingToTransfer, msg.sender);

    }

    /**
     * @notice This function is called to issue the option tokens. Remember that issuing oTokens even if they
     * haven't been sold can put the owner at a risk of not making premiums on the oTokens. Ensure that you
     * issue and immidiately sell the oTokens! (Either call the createAndSell function in the oToken contract
     * of batch the issueOTokens transaction with a sell transaction and ensure it happens atomically).
     * @dev The owner of a Vault should only be able to have a max of
     * repo.collateral * collateralToStrike / (minminCollateralizationRatio * strikePrice) tokens issued.
     * @param oTokensToIssue The number of o tokens to issue
     * @param receiver The address to send the oTokens to
     */
    function issueOTokens(uint256 oTokensToIssue, address receiver)
        public
        notExpired
    {
        //check that we're properly collateralized to mint this number, then call _mint(address account, uint256 amount)
        require(hasVault(msg.sender), "Vault does not exist");

        Vault storage vault = vaults[msg.sender];

        // checks that the vault is sufficiently collateralized
        uint256 newOTokensBalance = vault.oTokensIssued.add(oTokensToIssue);
        require(isSafe(vault.collateral, newOTokensBalance), "unsafe to mint");

        // issue the oTokens
        vault.oTokensIssued = newOTokensBalance;
        _mint(receiver, oTokensToIssue);

        emit IssuedOTokens(receiver, oTokensToIssue, msg.sender);
        return;
    }

    /**
     * @notice Returns the vault for a given address
     * @param vaultOwner the owner of the Vault to return
     */
    function getVault(address payable vaultOwner)
        public
        view
        returns (uint256, uint256, uint256, bool)
    {
        Vault storage vault = vaults[vaultOwner];
        return (
            vault.collateral,
            vault.oTokensIssued,
            vault.underlying,
            vault.owned
        );
    }

    /**
     * @notice Returns true if the given ERC20 is ETH.
     * @param _ierc20 the ERC20 asset.
     */
    function isETH(IERC20 _ierc20) public pure returns (bool) {
        return _ierc20 == IERC20(0);
    }

    /**
     * @notice allows the owner to burn their oTokens to increase the collateralization ratio of
     * their vault.
     * @param amtToBurn number of oTokens to burn
     * @dev only want to call this function before expiry. After expiry, no benefit to calling it.
     */
    function burnOTokens(uint256 amtToBurn) public notExpired {
        require(hasVault(msg.sender), "Vault does not exist");

        Vault storage vault = vaults[msg.sender];

        vault.oTokensIssued = vault.oTokensIssued.sub(amtToBurn);
        _burn(msg.sender, amtToBurn);

        emit BurnOTokens(msg.sender, amtToBurn);
    }

    /**
     * @notice allows the owner to remove excess collateral from the vault before expiry. Removing collateral lowers
     * the collateralization ratio of the vault.
     * @param amtToRemove Amount of collateral to remove in 10^-18.
     */
    function removeCollateral(uint256 amtToRemove) public notExpired {
        require(amtToRemove > 0, "Cannot remove 0 collateral");
        require(hasVault(msg.sender), "Vault does not exist");

        Vault storage vault = vaults[msg.sender];
        require(
            amtToRemove <= getCollateral(msg.sender),
            "Can't remove more collateral than owned"
        );

        // check that vault will remain safe after removing collateral
        uint256 newCollateralBalance = vault.collateral.sub(amtToRemove);

        require(
            isSafe(newCollateralBalance, vault.oTokensIssued),
            "Vault is unsafe"
        );

        // remove the collateral
        vault.collateral = newCollateralBalance;
        transferCollateral(msg.sender, amtToRemove);

        emit RemoveCollateral(amtToRemove, msg.sender);
    }

    /**
     * @notice after expiry, each vault holder can get back their proportional share of collateral
     * from vaults that they own.
     * @dev The owner gets all of their collateral back if no exercise event took their collateral.
     */
    function redeemVaultBalance() public {
        require(hasExpired(), "Can't collect collateral until expiry");
        require(hasVault(msg.sender), "Vault does not exist");

        // pay out owner their share
        Vault storage vault = vaults[msg.sender];

        // To deal with lower precision
        uint256 collateralToTransfer = vault.collateral;
        uint256 underlyingToTransfer = vault.underlying;

        vault.collateral = 0;
        vault.oTokensIssued = 0;
        vault.underlying = 0;

        transferCollateral(msg.sender, collateralToTransfer);
        transferUnderlying(msg.sender, underlyingToTransfer);

        emit RedeemVaultBalance(
            collateralToTransfer,
            underlyingToTransfer,
            msg.sender
        );
    }

    /**
     * This function returns the maximum amount of collateral liquidatable if the given vault is unsafe
     * @param vaultOwner The index of the vault to be liquidated
     */
    function maxOTokensLiquidatable(address payable vaultOwner)
        public
        view
        returns (uint256)
    {
        if (isUnsafe(vaultOwner)) {
            Vault storage vault = vaults[vaultOwner];
            uint256 maxCollateralLiquidatable = vault
                .collateral
                .mul(liquidationFactor.value)
                .div(10**uint256(-liquidationFactor.exponent));

            uint256 one = 10**uint256(-liquidationIncentive.exponent);
            Number memory liqIncentive = Number(
                liquidationIncentive.value.add(one),
                liquidationIncentive.exponent
            );
            return calculateOTokens(maxCollateralLiquidatable, liqIncentive);
        } else {
            return 0;
        }
    }

    /**
     * @notice This function can be called by anyone who notices a vault is undercollateralized.
     * The caller gets a reward for reducing the amount of oTokens in circulation.
     * @dev Liquidator comes with _oTokens. They get _oTokens * strikePrice * (incentive + fee)
     * amount of collateral out. They can liquidate a max of liquidationFactor * vault.collateral out
     * in one function call i.e. partial liquidations.
     * @param vaultOwner The index of the vault to be liquidated
     * @param oTokensToLiquidate The number of oTokens being taken out of circulation
     */
    function liquidate(address payable vaultOwner, uint256 oTokensToLiquidate)
        public
        notExpired
    {
        require(hasVault(vaultOwner), "Vault does not exist");

        Vault storage vault = vaults[vaultOwner];

        // cannot liquidate a safe vault.
        require(isUnsafe(vaultOwner), "Vault is safe");

        // Owner can't liquidate themselves
        require(msg.sender != vaultOwner, "Owner can't liquidate themselves");

        uint256 amtCollateral = calculateCollateralToPay(
            oTokensToLiquidate,
            Number(1, 0)
        );
        uint256 amtIncentive = calculateCollateralToPay(
            oTokensToLiquidate,
            liquidationIncentive
        );
        uint256 amtCollateralToPay = amtCollateral.add(amtIncentive);

        // calculate the maximum amount of collateral that can be liquidated
        uint256 maxCollateralLiquidatable = vault.collateral.mul(
            liquidationFactor.value
        );

        if (liquidationFactor.exponent > 0) {
            maxCollateralLiquidatable = maxCollateralLiquidatable.mul(
                10**uint256(liquidationFactor.exponent)
            );
        } else {
            maxCollateralLiquidatable = maxCollateralLiquidatable.div(
                10**uint256(-1 * liquidationFactor.exponent)
            );
        }

        require(
            amtCollateralToPay <= maxCollateralLiquidatable,
            "Can only liquidate liquidation factor at any given time"
        );

        // deduct the collateral and oTokensIssued
        vault.collateral = vault.collateral.sub(amtCollateralToPay);
        vault.oTokensIssued = vault.oTokensIssued.sub(oTokensToLiquidate);

        // transfer the collateral and burn the _oTokens
        _burn(msg.sender, oTokensToLiquidate);
        transferCollateral(msg.sender, amtCollateralToPay);

        emit Liquidate(amtCollateralToPay, vaultOwner, msg.sender);
    }

    /**
     * @notice checks if a vault is unsafe. If so, it can be liquidated
     * @param vaultOwner The number of the vault to check
     * @return true or false
     */
    function isUnsafe(address payable vaultOwner) public view returns (bool) {
        bool stillUnsafe = !isSafe(
            getCollateral(vaultOwner),
            getOTokensIssued(vaultOwner)
        );
        return stillUnsafe;
    }

    /**
     * @notice This function returns if an -30 <= exponent <= 30
     */
    function isWithinExponentRange(int32 val) internal pure returns (bool) {
        return ((val <= 30) && (val >= -30));
    }

    /**
     * @notice This function calculates and returns the amount of collateral in the vault
    */
    function getCollateral(address payable vaultOwner)
        internal
        view
        returns (uint256)
    {
        Vault storage vault = vaults[vaultOwner];
        return vault.collateral;
    }

    /**
     * @notice This function calculates and returns the amount of puts issued by the Vault
    */
    function getOTokensIssued(address payable vaultOwner)
        internal
        view
        returns (uint256)
    {
        Vault storage vault = vaults[vaultOwner];
        return vault.oTokensIssued;
    }

    /**
     * @notice Called by anyone holding the oTokens and underlying during the
     * exercise window i.e. from `expiry - windowSize` time to `expiry` time. The caller
     * transfers in their oTokens and corresponding amount of underlying and gets
     * `strikePrice * oTokens` amount of collateral out. The collateral paid out is taken from
     * the specified vault holder. At the end of the expiry window, the vault holder can redeem their balance
     * of collateral. The vault owner can withdraw their underlying at any time.
     * The user has to allow the contract to handle their oTokens and underlying on his behalf before these functions are called.
     * @param oTokensToExercise the number of oTokens being exercised.
     * @param vaultToExerciseFrom the address of the vaultOwner to take collateral from.
     * @dev oTokenExchangeRate is the number of underlying tokens that 1 oToken protects.
     */
    function _exercise(
        uint256 oTokensToExercise,
        address payable vaultToExerciseFrom
    ) internal {
        // 1. before exercise window: revert
        require(
            isExerciseWindow(),
            "Can't exercise outside of the exercise window"
        );

        require(hasVault(vaultToExerciseFrom), "Vault does not exist");

        Vault storage vault = vaults[vaultToExerciseFrom];
        require(oTokensToExercise > 0, "Can't exercise 0 oTokens");
        // Check correct amount of oTokens passed in)
        require(
            oTokensToExercise <= vault.oTokensIssued,
            "Can't exercise more oTokens than the owner has"
        );
        // Ensure person calling has enough oTokens
        require(
            balanceOf(msg.sender) >= oTokensToExercise,
            "Not enough oTokens"
        );

        // 1. Check sufficient underlying
        // 1.1 update underlying balances
        uint256 amtUnderlyingToPay = underlyingRequiredToExercise(
            oTokensToExercise
        );
        vault.underlying = vault.underlying.add(amtUnderlyingToPay);

        // 2. Calculate Collateral to pay
        // 2.1 Payout enough collateral to get (strikePrice * oTokens) amount of collateral
        uint256 amtCollateralToPay = calculateCollateralToPay(
            oTokensToExercise,
            Number(1, 0)
        );

        // 2.2 Take a small fee on every exercise
        uint256 amtFee = calculateCollateralToPay(
            oTokensToExercise,
            transactionFee
        );
        totalFee = totalFee.add(amtFee);

        uint256 totalCollateralToPay = amtCollateralToPay.add(amtFee);
        require(
            totalCollateralToPay <= vault.collateral,
            "Vault underwater, can't exercise"
        );

        // 3. Update collateral + oToken balances
        vault.collateral = vault.collateral.sub(totalCollateralToPay);
        vault.oTokensIssued = vault.oTokensIssued.sub(oTokensToExercise);

        // 4. Transfer in underlying, burn oTokens + pay out collateral
        // 4.1 Transfer in underlying
        if (isETH(underlying)) {
            require(msg.value == amtUnderlyingToPay, "Incorrect msg.value");
        } else {
            require(
                underlying.transferFrom(
                    msg.sender,
                    address(this),
                    amtUnderlyingToPay
                ),
                "Could not transfer in tokens"
            );
        }
        // 4.2 burn oTokens
        _burn(msg.sender, oTokensToExercise);

        // 4.3 Pay out collateral
        transferCollateral(msg.sender, amtCollateralToPay);

        emit Exercise(
            amtUnderlyingToPay,
            amtCollateralToPay,
            msg.sender,
            vaultToExerciseFrom
        );

    }

    /**
     * @notice adds `_amt` collateral to `vaultOwner` and returns the new balance of the vault
     * @param vaultOwner the index of the vault
     * @param amt the amount of collateral to add
     */
    function _addCollateral(address payable vaultOwner, uint256 amt)
        internal
        notExpired
        returns (uint256)
    {
        Vault storage vault = vaults[vaultOwner];
        vault.collateral = vault.collateral.add(amt);

        return vault.collateral;
    }

    /**
     * @notice checks if a hypothetical vault is safe with the given collateralAmt and oTokensIssued
     * @param collateralAmt The amount of collateral the hypothetical vault has
     * @param oTokensIssued The amount of oTokens generated by the hypothetical vault
     * @return true or false
     */
    function isSafe(uint256 collateralAmt, uint256 oTokensIssued)
        internal
        view
        returns (bool)
    {
        // get price from Oracle
        uint256 collateralToEthPrice = getPrice(address(collateral));
        uint256 strikeToEthPrice = getPrice(address(strike));

        // check `oTokensIssued * minCollateralizationRatio * strikePrice <= collAmt * collateralToStrikePrice`
        uint256 leftSideVal = oTokensIssued
            .mul(minCollateralizationRatio.value)
            .mul(strikePrice.value);
        int32 leftSideExp = minCollateralizationRatio.exponent +
            strikePrice.exponent;

        uint256 rightSideVal = (collateralAmt.mul(collateralToEthPrice)).div(
            strikeToEthPrice
        );
        int32 rightSideExp = collateralExp;

        uint256 exp = 0;
        bool stillSafe = false;

        if (rightSideExp < leftSideExp) {
            exp = uint256(leftSideExp - rightSideExp);
            stillSafe = leftSideVal.mul(10**exp) <= rightSideVal;
        } else {
            exp = uint256(rightSideExp - leftSideExp);
            stillSafe = leftSideVal <= rightSideVal.mul(10**exp);
        }

        return stillSafe;
    }

    /**
     * This function returns the maximum amount of oTokens that can safely be issued against the specified amount of collateral.
     * @param collateralAmt The amount of collateral against which oTokens will be issued.
     */
    function maxOTokensIssuable(uint256 collateralAmt)
        public
        view
        returns (uint256)
    {
        return calculateOTokens(collateralAmt, minCollateralizationRatio);

    }

    /**
     * @notice This function is used to calculate the amount of tokens that can be issued.
     * @dev The amount of oTokens is determined by:
     * oTokensIssued  <= collateralAmt * collateralToStrikePrice / (proportion * strikePrice)
     * @param collateralAmt The amount of collateral
     * @param proportion The proportion of the collateral to pay out. If 100% of collateral
     * should be paid out, pass in Number(1, 0). The proportion might be less than 100% if
     * you are calculating fees.
     */
    function calculateOTokens(uint256 collateralAmt, Number memory proportion)
        internal
        view
        returns (uint256)
    {
        // get price from Oracle
        uint256 collateralToEthPrice = getPrice(address(collateral));
        uint256 strikeToEthPrice = getPrice(address(strike));

        // oTokensIssued  <= collAmt * collateralToStrikePrice / (proportion * strikePrice)
        uint256 denomVal = proportion.value.mul(strikePrice.value);
        int32 denomExp = proportion.exponent + strikePrice.exponent;

        uint256 numeratorVal = (collateralAmt.mul(collateralToEthPrice)).div(
            strikeToEthPrice
        );
        int32 numeratorExp = collateralExp;

        uint256 exp = 0;
        uint256 numOptions = 0;

        if (numeratorExp < denomExp) {
            exp = uint256(denomExp - numeratorExp);
            numOptions = numeratorVal.div(denomVal.mul(10**exp));
        } else {
            exp = uint256(numeratorExp - denomExp);
            numOptions = numeratorVal.mul(10**exp).div(denomVal);
        }

        return numOptions;
    }

    /**
     * @notice This function calculates the amount of collateral to be paid out.
     * @dev The amount of collateral to paid out is determined by:
     * (proportion * strikePrice * strikeToCollateralPrice * oTokens) amount of collateral.
     * @param _oTokens The number of oTokens.
     * @param proportion The proportion of the collateral to pay out. If 100% of collateral
     * should be paid out, pass in Number(1, 0). The proportion might be less than 100% if
     * you are calculating fees.
     */
    function calculateCollateralToPay(
        uint256 _oTokens,
        Number memory proportion
    ) internal view returns (uint256) {
        // Get price from oracle
        uint256 collateralToEthPrice = getPrice(address(collateral));
        uint256 strikeToEthPrice = getPrice(address(strike));

        // calculate how much should be paid out
        uint256 amtCollateralToPayInEthNum = _oTokens
            .mul(strikePrice.value)
            .mul(proportion.value)
            .mul(strikeToEthPrice);
        int32 amtCollateralToPayExp = strikePrice.exponent +
            proportion.exponent -
            collateralExp;
        uint256 amtCollateralToPay = 0;
        if (amtCollateralToPayExp > 0) {
            uint32 exp = uint32(amtCollateralToPayExp);
            amtCollateralToPay = amtCollateralToPayInEthNum.mul(10**exp).div(
                collateralToEthPrice
            );
        } else {
            uint32 exp = uint32(-1 * amtCollateralToPayExp);
            amtCollateralToPay = (amtCollateralToPayInEthNum.div(10**exp)).div(
                collateralToEthPrice
            );
        }

        return amtCollateralToPay;

    }

    /**
     * @notice This function transfers `amt` collateral to `_addr`
     * @param _addr The address to send the collateral to
     * @param _amt The amount of the collateral to pay out.
     */
    function transferCollateral(address payable _addr, uint256 _amt) internal {
        if (isETH(collateral)) {
            _addr.transfer(_amt);
        } else {
            collateral.transfer(_addr, _amt);
        }
    }

    /**
     * @notice This function transfers `amt` underlying to `_addr`
     * @param _addr The address to send the underlying to
     * @param _amt The amount of the underlying to pay out.
     */
    function transferUnderlying(address payable _addr, uint256 _amt) internal {
        if (isETH(underlying)) {
            _addr.transfer(_amt);
        } else {
            underlying.transfer(_addr, _amt);
        }
    }

    /**
     * @notice This function gets the price ETH (wei) to asset price.
     * @param asset The address of the asset to get the price of
     */
    function getPrice(address asset) internal view returns (uint256) {
        if (asset == address(0)) {
            return (10**18);
        } else {
            return COMPOUND_ORACLE.getPrice(asset);
        }
    }
}

// File: contracts/oToken.sol

pragma solidity 0.5.10;


/**
 * @title Opyn's Options Contract
 * @author Opyn
 */

contract oToken is OptionsContract {
    /**
    * @param _collateral The collateral asset
    * @param _collExp The precision of the collateral (-18 if ETH)
    * @param _underlying The asset that is being protected
    * @param _underlyingExp The precision of the underlying asset
    * @param _oTokenExchangeExp The precision of the `amount of underlying` that 1 oToken protects
    * @param _strikePrice The amount of strike asset that will be paid out
    * @param _strikeExp The precision of the strike asset (-18 if ETH)
    * @param _strike The asset in which the insurance is calculated
    * @param _expiry The time at which the insurance expires
    * @param _optionsExchange The contract which interfaces with the exchange + oracle
    * @param _oracleAddress The address of the oracle
    * @param _windowSize UNIX time. Exercise window is from `expiry - _windowSize` to `expiry`.
    */
    constructor(
        IERC20 _collateral,
        int32 _collExp,
        IERC20 _underlying,
        int32 _underlyingExp,
        int32 _oTokenExchangeExp,
        uint256 _strikePrice,
        int32 _strikeExp,
        IERC20 _strike,
        uint256 _expiry,
        OptionsExchange _optionsExchange,
        address _oracleAddress,
        uint256 _windowSize
    )
        public
        OptionsContract(
            _collateral,
            _collExp,
            _underlying,
            _underlyingExp,
            _oTokenExchangeExp,
            _strikePrice,
            _strikeExp,
            _strike,
            _expiry,
            _optionsExchange,
            _oracleAddress,
            _windowSize
        )
    {}

    /**
     * @notice opens a Vault, adds ETH collateral, and mints new oTokens in one step
     * Remember that creating oTokens can put the owner at a risk of losing the collateral
     * if an exercise event happens.
     * The sell function provides the owner a chance to earn premiums.
     * Ensure that you create and immediately sell oTokens atmoically.
     * @param amtToCreate number of oTokens to create
     * @param receiver address to send the Options to
     */
    function createETHCollateralOption(uint256 amtToCreate, address receiver)
        external
        payable
    {
        openVault();
        addETHCollateralOption(amtToCreate, receiver);
    }

    /**
     * @notice adds ETH collateral, and mints new oTokens in one step to an existing Vault
     * Remember that creating oTokens can put the owner at a risk of losing the collateral
     * if an exercise event happens.
     * The sell function provides the owner a chance to earn premiums.
     * Ensure that you create and immediately sell oTokens atmoically.
     * @param amtToCreate number of oTokens to create
     * @param receiver address to send the Options to
     */
    function addETHCollateralOption(uint256 amtToCreate, address receiver)
        public
        payable
    {
        addETHCollateral(msg.sender);
        issueOTokens(amtToCreate, receiver);
    }

    /**
     * @notice opens a Vault, adds ETH collateral, mints new oTokens and sell in one step
     * @param amtToCreate number of oTokens to create
     * @param receiver address to receive the premiums
     */
    function createAndSellETHCollateralOption(
        uint256 amtToCreate,
        address payable receiver
    ) external payable {
        openVault();
        addETHCollateralOption(amtToCreate, address(this));
        this.approve(address(optionsExchange), amtToCreate);
        optionsExchange.sellOTokens(
            receiver,
            address(this),
            address(0),
            amtToCreate
        );
    }

    /**
     * @notice adds ETH collateral to an existing Vault, and mints new oTokens and sells the oTokens in one step
     * @param amtToCreate number of oTokens to create
     * @param receiver address to send the Options to
     */
    function addAndSellETHCollateralOption(
        uint256 amtToCreate,
        address payable receiver
    ) public payable {
        addETHCollateral(msg.sender);
        issueOTokens(amtToCreate, address(this));
        this.approve(address(optionsExchange), amtToCreate);
        optionsExchange.sellOTokens(
            receiver,
            address(this),
            address(0),
            amtToCreate
        );
    }

    /**
     * @notice opens a Vault, adds ERC20 collateral, and mints new oTokens in one step
     * Remember that creating oTokens can put the owner at a risk of losing the collateral
     * if an exercise event happens.
     * The sell function provides the owner a chance to earn premiums.
     * Ensure that you create and immediately sell oTokens atmoically.
     * @param amtToCreate number of oTokens to create
     * @param amtCollateral amount of collateral added
     * @param receiver address to send the Options to
     */
    function createERC20CollateralOption(
        uint256 amtToCreate,
        uint256 amtCollateral,
        address receiver
    ) external {
        openVault();
        addERC20CollateralOption(amtToCreate, amtCollateral, receiver);
    }

    /**
     * @notice adds ERC20 collateral, and mints new oTokens in one step
     * Remember that creating oTokens can put the owner at a risk of losing the collateral
     * if an exercise event happens.
     * The sell function provides the owner a chance to earn premiums.
     * Ensure that you create and immediately sell oTokens atmoically.
     * @param amtToCreate number of oTokens to create
     * @param amtCollateral amount of collateral added
     * @param receiver address to send the Options to
     */
    function addERC20CollateralOption(
        uint256 amtToCreate,
        uint256 amtCollateral,
        address receiver
    ) public {
        addERC20Collateral(msg.sender, amtCollateral);
        issueOTokens(amtToCreate, receiver);
    }

    /**
     * @notice opens a Vault, adds ERC20 collateral, mints new oTokens and sells the oTokens in one step
     * @param amtToCreate number of oTokens to create
     * @param amtCollateral amount of collateral added
     * @param receiver address to send the Options to
     */
    function createAndSellERC20CollateralOption(
        uint256 amtToCreate,
        uint256 amtCollateral,
        address payable receiver
    ) external {
        openVault();
        addERC20CollateralOption(amtToCreate, amtCollateral, address(this));
        this.approve(address(optionsExchange), amtToCreate);
        optionsExchange.sellOTokens(
            receiver,
            address(this),
            address(0),
            amtToCreate
        );
    }

    /**
     * @notice adds ERC20 collateral, mints new oTokens and sells the oTokens in one step
     * @param amtToCreate number of oTokens to create
     * @param amtCollateral amount of collateral added
     * @param receiver address to send the Options to
     */
    function addAndSellERC20CollateralOption(
        uint256 amtToCreate,
        uint256 amtCollateral,
        address payable receiver
    ) public {
        addERC20Collateral(msg.sender, amtCollateral);
        issueOTokens(amtToCreate, address(this));
        this.approve(address(optionsExchange), amtToCreate);
        optionsExchange.sellOTokens(
            receiver,
            address(this),
            address(0),
            amtToCreate
        );
    }
}

Contract Security Audit

Contract ABI

[{"constant":false,"inputs":[{"name":"vaultOwner","type":"address"},{"name":"amt","type":"uint256"}],"name":"addERC20Collateral","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getVaultOwners","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"hasVault","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isExerciseWindow","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"vaultOwner","type":"address"}],"name":"getVault","outputs":[{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"oTokensToIssue","type":"uint256"},{"name":"receiver","type":"address"}],"name":"issueOTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"},{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amtToCreate","type":"uint256"},{"name":"amtCollateral","type":"uint256"},{"name":"receiver","type":"address"}],"name":"addAndSellERC20CollateralOption","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"amtToRemove","type":"uint256"}],"name":"removeCollateral","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"liquidationFactor","outputs":[{"name":"value","type":"uint256"},{"name":"exponent","type":"int32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amtToCreate","type":"uint256"},{"name":"receiver","type":"address"}],"name":"createAndSellETHCollateralOption","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"optionsExchange","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amtToCreate","type":"uint256"},{"name":"amtCollateral","type":"uint256"},{"name":"receiver","type":"address"}],"name":"createERC20CollateralOption","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"oTokensToExercise","type":"uint256"},{"name":"vaultsToExerciseFrom","type":"address[]"}],"name":"exercise","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"amtToCreate","type":"uint256"},{"name":"amtCollateral","type":"uint256"},{"name":"receiver","type":"address"}],"name":"addERC20CollateralOption","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"collateralAmt","type":"uint256"}],"name":"maxOTokensIssuable","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"underlying","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"oTokensToExercise","type":"uint256"}],"name":"underlyingRequiredToExercise","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"openVault","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"COMPOUND_ORACLE","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"liquidationIncentive","outputs":[{"name":"value","type":"uint256"},{"name":"exponent","type":"int32"}],"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":"hasExpired","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"vaultOwner","type":"address"}],"name":"addETHCollateral","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"transactionFee","outputs":[{"name":"value","type":"uint256"},{"name":"exponent","type":"int32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"strike","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"underlyingExp","outputs":[{"name":"","type":"int32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"collateralExp","outputs":[{"name":"","type":"int32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oTokenExchangeRate","outputs":[{"name":"value","type":"uint256"},{"name":"exponent","type":"int32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"redeemVaultBalance","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"}],"name":"setDetails","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"amtToCreate","type":"uint256"},{"name":"receiver","type":"address"}],"name":"addETHCollateralOption","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"minCollateralizationRatio","outputs":[{"name":"value","type":"uint256"},{"name":"exponent","type":"int32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"vaultOwner","type":"address"},{"name":"oTokensToLiquidate","type":"uint256"}],"name":"liquidate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"strikePrice","outputs":[{"name":"value","type":"uint256"},{"name":"exponent","type":"int32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amtToCreate","type":"uint256"},{"name":"amtCollateral","type":"uint256"},{"name":"receiver","type":"address"}],"name":"createAndSellERC20CollateralOption","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"vaultOwner","type":"address"}],"name":"isUnsafe","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amtToCreate","type":"uint256"},{"name":"receiver","type":"address"}],"name":"addAndSellETHCollateralOption","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"collateral","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"vaultOwner","type":"address"}],"name":"maxOTokensLiquidatable","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"expiry","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"transferFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"amtToBurn","type":"uint256"}],"name":"burnOTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"amtToCreate","type":"uint256"},{"name":"receiver","type":"address"}],"name":"createETHCollateralOption","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_liquidationIncentive","type":"uint256"},{"name":"_liquidationFactor","type":"uint256"},{"name":"_transactionFee","type":"uint256"},{"name":"_minCollateralizationRatio","type":"uint256"}],"name":"updateParameters","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_ierc20","type":"address"}],"name":"isETH","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"removeUnderlying","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_collateral","type":"address"},{"name":"_collExp","type":"int32"},{"name":"_underlying","type":"address"},{"name":"_underlyingExp","type":"int32"},{"name":"_oTokenExchangeExp","type":"int32"},{"name":"_strikePrice","type":"uint256"},{"name":"_strikeExp","type":"int32"},{"name":"_strike","type":"address"},{"name":"_expiry","type":"uint256"},{"name":"_optionsExchange","type":"address"},{"name":"_oracleAddress","type":"address"},{"name":"_windowSize","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"vaultOwner","type":"address"}],"name":"VaultOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"vaultOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"payer","type":"address"}],"name":"ETHCollateralAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"vaultOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"payer","type":"address"}],"name":"ERC20CollateralAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"issuedTo","type":"address"},{"indexed":false,"name":"oTokensIssued","type":"uint256"},{"indexed":false,"name":"vaultOwner","type":"address"}],"name":"IssuedOTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amtCollateralToPay","type":"uint256"},{"indexed":false,"name":"vaultOwner","type":"address"},{"indexed":false,"name":"liquidator","type":"address"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amtUnderlyingToPay","type":"uint256"},{"indexed":false,"name":"amtCollateralToPay","type":"uint256"},{"indexed":false,"name":"exerciser","type":"address"},{"indexed":false,"name":"vaultExercisedFrom","type":"address"}],"name":"Exercise","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amtCollateralRedeemed","type":"uint256"},{"indexed":false,"name":"amtUnderlyingRedeemed","type":"uint256"},{"indexed":false,"name":"vaultOwner","type":"address"}],"name":"RedeemVaultBalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"vaultOwner","type":"address"},{"indexed":false,"name":"oTokensBurned","type":"uint256"}],"name":"BurnOTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amtRemoved","type":"uint256"},{"indexed":false,"name":"vaultOwner","type":"address"}],"name":"RemoveCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"liquidationIncentive","type":"uint256"},{"indexed":false,"name":"liquidationFactor","type":"uint256"},{"indexed":false,"name":"transactionFee","type":"uint256"},{"indexed":false,"name":"minCollateralizationRatio","type":"uint256"},{"indexed":false,"name":"owner","type":"address"}],"name":"UpdateParameters","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"fees","type":"uint256"}],"name":"TransferFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amountUnderlying","type":"uint256"},{"indexed":false,"name":"vaultOwner","type":"address"}],"name":"RemoveUnderlying","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]

600a608081905260021960a081905260078290556008805463ffffffff1990811663fffffffd908117909255600060c081905260e08490526009558354811682179093556101f461010081905261012092909252600b91909155600c805483169091179055610180604052601061014081905260001961016052600d55600e805463ffffffff9083161790556016805490911663ffffffee1763ffffffff60201b191667ffffffee00000000179055348015620000bb57600080fd5b5060405162004873380380620048738339818101604052610180811015620000e257600080fd5b508051602082015160408301516060840151608085015160a086015160c087015160e08801516101008901516101208a01516101408b0151610160909b0151999a9899979896979596949593949293919290918b8b8b8b8b8b8b8b8b8b8b8b620001546001600160e01b03620005ec16565b600080546001600160a01b0319166001600160a01b03928316178082556040519216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a38342106200020b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f43616e2774206465706c6f7920616e206578706972656420636f6e7472616374604482015290519081900360640190fd5b8381111562000266576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603c81526020018062004777603c913960400191505060405180910390fd5b6200027a8b6001600160e01b03620005f016565b620002d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d815260200180620047b3602d913960400191505060405180910390fd5b620002e5896001600160e01b03620005f016565b6200033c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602d81526020018062004846602d913960400191505060405180910390fd5b62000350866001600160e01b03620005f016565b620003a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f81526020018062004817602f913960400191505060405180910390fd5b620003bb886001600160e01b03620005f016565b62000412576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526037815260200180620047e06037913960400191505060405180910390fd5b8b601660086101000a8154816001600160a01b0302191690836001600160a01b031602179055508a601660006101000a81548163ffffffff021916908360030b63ffffffff16021790555089601760006101000a8154816001600160a01b0302191690836001600160a01b0316021790555088601660046101000a81548163ffffffff021916908360030b63ffffffff1602179055506040518060400160405280600181526020018960030b81525060116000820151816000015560208201518160010160006101000a81548163ffffffff021916908360030b63ffffffff16021790555090505060405180604001604052808881526020018760030b815250600f6000820151816000015560208201518160010160006101000a81548163ffffffff021916908360030b63ffffffff16021790555090505084601860006101000a8154816001600160a01b0302191690836001600160a01b031602179055508360158190555081601960006101000a8154816001600160a01b0302191690836001600160a01b0316021790555082600460006101000a8154816001600160a01b0302191690836001600160a01b031602179055508060138190555050505050505050505050505050505050505050505050505062000612565b3390565b6000601e8260030b131580156200060c5750601d198260030b12155b92915050565b61415580620006226000396000f3fe6080604052600436106103975760003560e01c806390e64d13116101dc578063c52987cf11610102578063e184c9be116100a0578063ee1eab4f1161006f578063ee1eab4f14610ed3578063f2fde38b14610f0f578063f70a250814610f42578063faa2041f14610f7557610397565b8063e184c9be14610e35578063ea8c4bcf14610e4a578063eaa376b514610e7d578063ed1f41c314610ea757610397565b8063cfbea789116100dc578063cfbea78914610d86578063d8dfeb4514610db2578063dd62ed3e14610dc7578063dec44c0b14610e0257610397565b8063c52987cf14610cff578063c56749ce14610d14578063cdb4b5c214610d5357610397565b8063b2c2b13f1161017a578063b7b090ee11610149578063b7b090ee14610b4f578063b96661ba14610c85578063ba1be55414610cb1578063bcbaf48714610cc657610397565b8063b2c2b13f14610ae2578063b6e61c0814610b10578063b736554014610b25578063b76fdb6c14610b3a57610397565b80639ed3edf0116101b65780639ed3edf014610a46578063a457c2d714610a5b578063a9059cbb14610a94578063ad8f500814610acd57610397565b806390e64d13146109f657806395d89b4114610a0b5780639ce0725114610a2057610397565b806339509351116102c15780636fd865f91161025f5780638a5e8cc71161022e5780638a5e8cc7146109a25780638c765e94146109b75780638da5cb5b146109cc5780638f32d59b146109e157610397565b80636fd865f91461091b57806370a0823114610945578063715018a61461097857806386f547121461098d57610397565b806358b36dac1161029b57806358b36dac146107f55780635ca7c8a61461089d578063686c1e21146108dc5780636f307dc31461090657610397565b8063395093511461074c5780633bd33f621461078557806352f89fe3146107b657610397565b806318160ddd116103395780633226052d116103085780633226052d146106845780633237c158146106c3578063352ade55146106ed5780633667429f1461072057610397565b806318160ddd146105c65780631a0e21bd146105db57806323b872dd14610616578063313ce5671461065957610397565b8063095ea7b311610375578063095ea7b3146104d65780630d453efb146105235780630d6cd8aa146105565780630eb9af381461056b57610397565b806301b4a3c11461039c578063060ab2ea146103e757806306fdde031461044c575b600080fd5b3480156103a857600080fd5b506103d5600480360360408110156103bf57600080fd5b506001600160a01b038135169060200135610f8a565b60408051918252519081900360200190f35b3480156103f357600080fd5b506103fc61113e565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610438578181015183820152602001610420565b505050509050019250505060405180910390f35b34801561045857600080fd5b506104616111e5565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561049b578181015183820152602001610483565b50505050905090810190601f1680156104c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104e257600080fd5b5061050f600480360360408110156104f957600080fd5b506001600160a01b038135169060200135611273565b604080519115158252519081900360200190f35b34801561052f57600080fd5b5061050f6004803603602081101561054657600080fd5b50356001600160a01b0316611290565b34801561056257600080fd5b5061050f6112b5565b34801561057757600080fd5b5061059e6004803603602081101561058e57600080fd5b50356001600160a01b03166112e3565b6040805194855260208501939093528383019190915215156060830152519081900360800190f35b3480156105d257600080fd5b506103d5611317565b3480156105e757600080fd5b50610614600480360360408110156105fe57600080fd5b50803590602001356001600160a01b031661131d565b005b34801561062257600080fd5b5061050f6004803603606081101561063957600080fd5b506001600160a01b03813581169160208101359091169060400135611486565b34801561066557600080fd5b5061066e611513565b6040805160ff9092168252519081900360200190f35b34801561069057600080fd5b50610614600480360360608110156106a757600080fd5b50803590602081013590604001356001600160a01b031661151c565b3480156106cf57600080fd5b50610614600480360360208110156106e657600080fd5b5035611634565b3480156106f957600080fd5b50610702611824565b60408051928352600391820b90910b60208301528051918290030190f35b6106146004803603604081101561073657600080fd5b50803590602001356001600160a01b0316611830565b34801561075857600080fd5b5061050f6004803603604081101561076f57600080fd5b506001600160a01b038135169060200135611945565b34801561079157600080fd5b5061079a611999565b604080516001600160a01b039092168252519081900360200190f35b3480156107c257600080fd5b50610614600480360360608110156107d957600080fd5b50803590602081013590604001356001600160a01b03166119a8565b6106146004803603604081101561080b57600080fd5b81359190810190604081016020820135600160201b81111561082c57600080fd5b82018360208201111561083e57600080fd5b803590602001918460208302840111600160201b8311171561085f57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506119c1945050505050565b3480156108a957600080fd5b50610614600480360360608110156108c057600080fd5b50803590602081013590604001356001600160a01b0316611ad9565b3480156108e857600080fd5b506103d5600480360360208110156108ff57600080fd5b5035611aee565b34801561091257600080fd5b5061079a611b1c565b34801561092757600080fd5b506103d56004803603602081101561093e57600080fd5b5035611b2b565b34801561095157600080fd5b506103d56004803603602081101561096857600080fd5b50356001600160a01b0316611b6f565b34801561098457600080fd5b50610614611b8a565b34801561099957600080fd5b5061050f611c1b565b3480156109ae57600080fd5b5061079a611d88565b3480156109c357600080fd5b50610702611d97565b3480156109d857600080fd5b5061079a611da3565b3480156109ed57600080fd5b5061050f611db2565b348015610a0257600080fd5b5061050f611dd6565b348015610a1757600080fd5b50610461611ddf565b6103d560048036036020811015610a3657600080fd5b50356001600160a01b0316611e3a565b348015610a5257600080fd5b50610702611f74565b348015610a6757600080fd5b5061050f60048036036040811015610a7e57600080fd5b506001600160a01b038135169060200135611f80565b348015610aa057600080fd5b5061050f60048036036040811015610ab757600080fd5b506001600160a01b038135169060200135611fee565b348015610ad957600080fd5b5061079a612002565b348015610aee57600080fd5b50610af7612011565b60408051600392830b90920b8252519081900360200190f35b348015610b1c57600080fd5b50610af7612021565b348015610b3157600080fd5b5061070261202a565b348015610b4657600080fd5b50610614612036565b348015610b5b57600080fd5b5061061460048036036040811015610b7257600080fd5b810190602081018135600160201b811115610b8c57600080fd5b820183602082011115610b9e57600080fd5b803590602001918460018302840111600160201b83111715610bbf57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610c1157600080fd5b820183602082011115610c2357600080fd5b803590602001918460018302840111600160201b83111715610c4457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612142945050505050565b61061460048036036040811015610c9b57600080fd5b50803590602001356001600160a01b03166121d3565b348015610cbd57600080fd5b506107026121e7565b348015610cd257600080fd5b5061061460048036036040811015610ce957600080fd5b506001600160a01b0381351690602001356121f3565b348015610d0b57600080fd5b506107026124f7565b348015610d2057600080fd5b5061061460048036036060811015610d3757600080fd5b50803590602081013590604001356001600160a01b0316612503565b348015610d5f57600080fd5b5061050f60048036036020811015610d7657600080fd5b50356001600160a01b0316612517565b61061460048036036040811015610d9c57600080fd5b50803590602001356001600160a01b031661253c565b348015610dbe57600080fd5b5061079a612550565b348015610dd357600080fd5b506103d560048036036040811015610dea57600080fd5b506001600160a01b0381358116916020013516612566565b348015610e0e57600080fd5b506103d560048036036020811015610e2557600080fd5b50356001600160a01b0316612591565b348015610e4157600080fd5b506103d561265c565b348015610e5657600080fd5b5061061460048036036020811015610e6d57600080fd5b50356001600160a01b0316612662565b348015610e8957600080fd5b5061061460048036036020811015610ea057600080fd5b5035612704565b61061460048036036040811015610ebd57600080fd5b50803590602001356001600160a01b0316612806565b348015610edf57600080fd5b5061061460048036036080811015610ef657600080fd5b5080359060208101359060408101359060600135612819565b348015610f1b57600080fd5b5061061460048036036020811015610f3257600080fd5b50356001600160a01b03166129f1565b348015610f4e57600080fd5b5061050f60048036036020811015610f6557600080fd5b50356001600160a01b0316612a44565b348015610f8157600080fd5b50610614612a51565b6000610f94611dd6565b15610fd4576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b601654604080516323b872dd60e01b8152336004820152306024820152604481018590529051600160401b9092046001600160a01b0316916323b872dd916064808201926020929091908290030181600087803b15801561103457600080fd5b505af1158015611048573d6000803e3d6000fd5b505050506040513d602081101561105e57600080fd5b505161109b5760405162461bcd60e51b8152600401808060200182810382526027815260200180613e626027913960400191505060405180910390fd5b6110a483611290565b6110e3576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b604080516001600160a01b038516815260208101849052338183015290517f2199418ea9428ed3ff7d460860e1edaf5831452fa4ea0f8d1a60d63c603487829181900360600190a16111358383612b49565b90505b92915050565b6060806000805b6006548110156111dc576111796006828154811061115f57fe5b6000918252602090912001546001600160a01b0316611290565b156111d4576006818154811061118b57fe5b9060005260206000200160009054906101000a90046001600160a01b03168383815181106111b557fe5b6001600160a01b03909216602092830291909101909101526001909101905b600101611145565b50909150505b90565b601a805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561126b5780601f106112405761010080835404028352916020019161126b565b820191906000526020600020905b81548152906001019060200180831161124e57829003601f168201915b505050505081565b6000611287611280612bc8565b8484612bcc565b50600192915050565b6001600160a01b03811660009081526005602052604090206003015460ff165b919050565b60006112ce601354601554612cb890919063ffffffff16565b42101580156112de575060155442105b905090565b6001600160a01b03166000908152600560205260409020805460018201546002830154600390930154919390929160ff1690565b60035490565b611325611dd6565b15611365576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b61136e33611290565b6113ad576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b33600090815260056020526040812060018101549091906113d4908563ffffffff612cfa16565b90506113e4826000015482612d54565b611426576040805162461bcd60e51b815260206004820152600e60248201526d1d5b9cd85999481d1bc81b5a5b9d60921b604482015290519081900360640190fd5b600182018190556114378385612e59565b604080516001600160a01b038516815260208101869052338183015290517f5e5aaabf04e3760968ffb551bdf9708f4dbf95d53ad98539e91a56b125e88f089181900360600190a150505b5050565b6000611493848484612f4b565b6115098461149f612bc8565b61150485604051806060016040528060288152602001613fcd602891396001600160a01b038a166000908152600260205260408120906114dd612bc8565b6001600160a01b03168152602081019190915260400160002054919063ffffffff6130a916565b612bcc565b5060019392505050565b601c5460ff1681565b6115263383610f8a565b50611531833061131d565b600480546040805163095ea7b360e01b81526001600160a01b0390921692820192909252602481018590529051309163095ea7b39160448083019260209291908290030181600087803b15801561158757600080fd5b505af115801561159b573d6000803e3d6000fd5b505050506040513d60208110156115b157600080fd5b50506004805460408051637dafae5960e01b81526001600160a01b03858116948201949094523060248201526000604482018190526064820188905291519390921692637dafae5992608480820193929182900301818387803b15801561161757600080fd5b505af115801561162b573d6000803e3d6000fd5b50505050505050565b61163c611dd6565b1561167c576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b600081116116d1576040805162461bcd60e51b815260206004820152601a60248201527f43616e6e6f742072656d6f7665203020636f6c6c61746572616c000000000000604482015290519081900360640190fd5b6116da33611290565b611719576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b3360008181526005602052604090209061173290613140565b8211156117705760405162461bcd60e51b8152600401808060200182810382526027815260200180613f796027913960400191505060405180910390fd5b8054600090611785908463ffffffff612cb816565b9050611795818360010154612d54565b6117d8576040805162461bcd60e51b815260206004820152600f60248201526e5661756c7420697320756e7361666560881b604482015290519081900360640190fd5b8082556117e5338461315b565b6040805184815233602082015281517f5a945309b3c58e9bb259128c2a530a6579dc75ac1d7d61b3db4c0b8305a16821929181900390910190a1505050565b600b54600c5460030b82565b611838611c1b565b5061184382306121d3565b600480546040805163095ea7b360e01b81526001600160a01b0390921692820192909252602481018490529051309163095ea7b39160448083019260209291908290030181600087803b15801561189957600080fd5b505af11580156118ad573d6000803e3d6000fd5b505050506040513d60208110156118c357600080fd5b50506004805460408051637dafae5960e01b81526001600160a01b03858116948201949094523060248201526000604482018190526064820187905291519390921692637dafae5992608480820193929182900301818387803b15801561192957600080fd5b505af115801561193d573d6000803e3d6000fd5b505050505050565b6000611287611952612bc8565b846115048560026000611963612bc8565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff612cfa16565b6004546001600160a01b031681565b6119b0611c1b565b506119bc838383611ad9565b505050565b60005b8151811015611a9b5760008282815181106119db57fe5b602002602001015190506119ee81611290565b611a295760405162461bcd60e51b815260040180806020018281038252602f815260200180614036602f913960400191505060405180910390fd5b6001600160a01b038116600090815260056020526040902084611a4e57505050611482565b84816001015410611a6b57611a638583613246565b505050611482565b6001810154611a8190869063ffffffff612cb816565b9450611a91816001015483613246565b50506001016119c4565b5081156114825760405162461bcd60e51b815260040180806020018281038252602d815260200180613ef4602d913960400191505060405180910390fd5b611ae33383610f8a565b506119bc838261131d565b60408051808201909152600d548152600e54600390810b810b900b60208201526000906111389083906136a9565b6017546001600160a01b031681565b601654601254600091600160201b9004600390810b91810b91909103900b611b688367ffffffffffffffff808416600a0a1663ffffffff6137a416565b9392505050565b6001600160a01b031660009081526001602052604090205490565b611b92611db2565b611bd1576040805162461bcd60e51b81526020600482018190526024820152600080516020613ff5833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000611c25611dd6565b15611c65576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b611c6e33611290565b15611cb8576040805162461bcd60e51b815260206004820152601560248201527415985d5b1d08185b1c9958591e4818dc99585d1959605a1b604482015290519081900360640190fd5b60408051608081018252600080825260208083018281528385018381526001606086018181523380875260058652888720975188559351878301559151600287015590516003909501805460ff1916951515959095179094556006805494850181559092527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90920180546001600160a01b03191682179055825190815291517f66a872561db77eb92ef3079a44a5af00c68c3a09e0976814a95bd91721f57c2f9281900390910190a150600190565b6019546001600160a01b031681565b60075460085460030b82565b6000546001600160a01b031690565b600080546001600160a01b0316611dc7612bc8565b6001600160a01b031614905090565b60155442101590565b601b805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561126b5780601f106112405761010080835404028352916020019161126b565b6000611e44611dd6565b15611e84576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b601654611ea090600160401b90046001600160a01b0316612a44565b611edb5760405162461bcd60e51b8152600401808060200182810382526028815260200180613dcd6028913960400191505060405180910390fd5b611ee482611290565b611f23576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b604080516001600160a01b0384168152346020820152338183015290517ff24ce6016de57e90501829715846e26ac283a0aabfc160647e0ae8b05e0f433d9181900360600190a16111388234612b49565b600954600a5460030b82565b6000611287611f8d612bc8565b84611504856040518060600160405280602581526020016140fc6025913960026000611fb7612bc8565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff6130a916565b6000611287611ffb612bc8565b8484612f4b565b6018546001600160a01b031681565b601654600160201b900460030b81565b60165460030b81565b60115460125460030b82565b61203e611dd6565b6120795760405162461bcd60e51b8152600401808060200182810382526025815260200180613e3d6025913960400191505060405180910390fd5b61208233611290565b6120c1576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b33600081815260056020526040812080546002820180548484556001840185905593905590929091906120f4908361315b565b6120fe33826137fd565b6040805183815260208101839052338183015290517fe481532a3f7d078365ca0145442ed0a0a3e0443f3c0bae0c29cff131112678389181900360600190a1505050565b61214a611db2565b612189576040805162461bcd60e51b81526020600482018190526024820152600080516020613ff5833981519152604482015290519081900360640190fd5b815161219c90601a906020850190613c85565b5080516121b090601b906020840190613c85565b50601254601c805460ff191660039290920b60000360ff16919091179055611482565b6121dc33611e3a565b50611482828261131d565b600d54600e5460030b82565b6121fb611dd6565b1561223b576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b61224482611290565b612283576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b6001600160a01b03821660009081526005602052604090206122a483612517565b6122e5576040805162461bcd60e51b815260206004820152600d60248201526c5661756c74206973207361666560981b604482015290519081900360640190fd5b336001600160a01b0384161415612343576040805162461bcd60e51b815260206004820181905260248201527f4f776e65722063616e2774206c6971756964617465207468656d73656c766573604482015290519081900360640190fd5b600061236883604051806040016040528060018152602001600060030b8152506138a3565b604080518082019091526007548152600854600390810b810b900b60208201529091506000906123999085906138a3565b905060006123ad838363ffffffff612cfa16565b600b5485549192506000916123c79163ffffffff6137a416565b600c549091506000600391820b90910b131561240257600c546123fb908290600390810b900b600a0a63ffffffff6137a416565b9050612426565b600c54612423908290600390810b600003900b600a0a63ffffffff61398516565b90505b808211156124655760405162461bcd60e51b8152600401808060200182810382526037815260200180613f216037913960400191505060405180910390fd5b8454612477908363ffffffff612cb816565b8555600185015461248e908763ffffffff612cb816565b600186015561249d33876139c7565b6124a7338361315b565b604080518381526001600160a01b0389166020820152338183015290517fcab8e1abb9f8235c6db895cf185336dc9461aecf477b98c1be83687ee549e66a9181900360600190a150505050505050565b600f5460105460030b82565b61250b611c1b565b50611531838330611ad9565b60008061253461252684613140565b61252f85613ac3565b612d54565b159392505050565b61254533611e3a565b50611843823061131d565b601654600160401b90046001600160a01b031681565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b600061259c82612517565b15612654576001600160a01b0382166000908152600560205260408120600c54600b5482549293926125f192600390810b8503900b600a0a916125e5919063ffffffff6137a416565b9063ffffffff61398516565b600854909150600390810b600003900b600a0a61260c613d03565b60408051808201909152600754819061262b908563ffffffff612cfa16565b8152600854600390810b900b602090910152905061264983826136a9565b9450505050506112b0565b5060006112b0565b60155481565b61266a611db2565b6126a9576040805162461bcd60e51b81526020600482018190526024820152600080516020613ff5833981519152604482015290519081900360640190fd5b6014805460009091556126bc828261315b565b604080516001600160a01b03841681526020810183905281517f88b171bb78d3ac5e1caa8e729dddce4e1322e84c80c093ebbe52507b62c77d98929181900390910190a15050565b61270c611dd6565b1561274c576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b61275533611290565b612794576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b33600090815260056020526040902060018101546127b8908363ffffffff612cb816565b60018201556127c733836139c7565b604080513381526020810184905281517fdf8cebdea6ef1fd20576b80bc951377c0e61e2a8169153a1f836673ccce80e62929181900390910190a15050565b61280e611c1b565b5061148282826121d3565b612821611db2565b612860576040805162461bcd60e51b81526020600482018190526024820152600080516020613ff5833981519152604482015290519081900360640190fd5b60c88411156128a05760405162461bcd60e51b8152600401808060200182810382526025815260200180613ecf6025913960400191505060405180910390fd5b6103e88311156128e15760405162461bcd60e51b815260040180806020018281038252602b815260200180613d80602b913960400191505060405180910390fd5b6064821115612937576040805162461bcd60e51b815260206004820181905260248201527f43616e27742068617665207472616e73616374696f6e20666565203e20313025604482015290519081900360640190fd5b600a8110156129775760405162461bcd60e51b8152600401808060200182810382526028815260200180613d586028913960400191505060405180910390fd5b6007849055600b8390556009829055600d8190557f3450d20c21ea671871fed271900cc8ff03badafa9b6fe2ff7f86991950e86b6b848484846129b8611da3565b6040805195865260208601949094528484019290925260608401526001600160a01b03166080830152519081900360a00190a150505050565b6129f9611db2565b612a38576040805162461bcd60e51b81526020600482018190526024820152600080516020613ff5833981519152604482015290519081900360640190fd5b612a4181613ae1565b50565b6001600160a01b03161590565b612a5a33611290565b612a99576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b3360009081526005602052604090206002810154612af6576040805162461bcd60e51b81526020600482015260156024820152744e6f20756e6465726c79696e672062616c616e636560581b604482015290519081900360640190fd5b6002810180546000909155612b0b33826137fd565b6040805182815233602082015281517fea0bff65fa9380b944e9a761f9c6a665ad2d31e74706a52773ddb45c8a57c83d929181900390910190a15050565b6000612b53611dd6565b15612b93576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b6001600160a01b03831660009081526005602052604090208054612bbd908463ffffffff612cfa16565b908190559392505050565b3390565b6001600160a01b038316612c115760405162461bcd60e51b815260040180806020018281038252602481526020018061408a6024913960400191505060405180910390fd5b6001600160a01b038216612c565760405162461bcd60e51b8152600401808060200182810382526022815260200180613e1b6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b600061113583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506130a9565b600082820183811015611135576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600080612d75601660089054906101000a90046001600160a01b0316613b81565b601854909150600090612d90906001600160a01b0316613b81565b600f54600d54919250600091612dbe9190612db290889063ffffffff6137a416565b9063ffffffff6137a416565b601054600e54919250600391820b910b016000612de5846125e58a8863ffffffff6137a416565b601654909150600390810b90600090819085810b9084900b1215612e295782850360030b915083612e2087600a85900a63ffffffff6137a416565b11159050612e4b565b84830360030b9150612e4584600a84900a63ffffffff6137a416565b86111590505b9a9950505050505050505050565b6001600160a01b038216612eb4576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b600354612ec7908263ffffffff612cfa16565b6003556001600160a01b038216600090815260016020526040902054612ef3908263ffffffff612cfa16565b6001600160a01b03831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b038316612f905760405162461bcd60e51b81526004018080602001828103825260258152602001806140656025913960400191505060405180910390fd5b6001600160a01b038216612fd55760405162461bcd60e51b8152600401808060200182810382526023815260200180613d356023913960400191505060405180910390fd5b61301881604051806060016040528060268152602001613ea9602691396001600160a01b038616600090815260016020526040902054919063ffffffff6130a916565b6001600160a01b03808516600090815260016020526040808220939093559084168152205461304d908263ffffffff612cfa16565b6001600160a01b0380841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156131385760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156130fd5781810151838201526020016130e5565b50505050905090810190601f16801561312a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b031660009081526005602052604090205490565b60165461317790600160401b90046001600160a01b0316612a44565b156131b8576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156131b2573d6000803e3d6000fd5b50611482565b6016546040805163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529151600160401b9093049091169163a9059cbb916044808201926020929091908290030181600087803b15801561321657600080fd5b505af115801561322a573d6000803e3d6000fd5b505050506040513d602081101561324057600080fd5b50505050565b61324e6112b5565b6132895760405162461bcd60e51b815260040180806020018281038252602d815260200180613fa0602d913960400191505060405180910390fd5b61329281611290565b6132d1576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b6001600160a01b03811660009081526005602052604090208261333b576040805162461bcd60e51b815260206004820152601860248201527f43616e27742065786572636973652030206f546f6b656e730000000000000000604482015290519081900360640190fd5b806001015483111561337e5760405162461bcd60e51b815260040180806020018281038252602e8152602001806140ae602e913960400191505060405180910390fd5b8261338833611b6f565b10156133d0576040805162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f756768206f546f6b656e7360701b604482015290519081900360640190fd5b60006133db84611b2b565b60028301549091506133f3908263ffffffff612cfa16565b600283015560408051808201909152600181526000602082018190529061341b9086906138a3565b604080518082019091526009548152600a54600390810b810b900b602082015290915060009061344c9087906138a3565b601454909150613462908263ffffffff612cfa16565b6014556000613477838363ffffffff612cfa16565b85549091508111156134d0576040805162461bcd60e51b815260206004820181905260248201527f5661756c7420756e64657277617465722c2063616e2774206578657263697365604482015290519081900360640190fd5b84546134e2908263ffffffff612cb816565b855560018501546134f9908863ffffffff612cb816565b6001860155601754613513906001600160a01b0316612a44565b1561356757833414613562576040805162461bcd60e51b8152602060048201526013602482015272496e636f7272656374206d73672e76616c756560681b604482015290519081900360640190fd5b61363e565b601754604080516323b872dd60e01b81523360048201523060248201526044810187905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b1580156135c157600080fd5b505af11580156135d5573d6000803e3d6000fd5b505050506040513d60208110156135eb57600080fd5b505161363e576040805162461bcd60e51b815260206004820152601c60248201527f436f756c64206e6f74207472616e7366657220696e20746f6b656e7300000000604482015290519081900360640190fd5b61364833886139c7565b613652338461315b565b604080518581526020810185905233818301526001600160a01b038816606082015290517ffa7bab37479e50a9b24a9412b879d400de9bcaa1e3a2b343e90bb370d85bbaa79181900360800190a150505050505050565b6000806136ca601660089054906101000a90046001600160a01b0316613b81565b6018549091506000906136e5906001600160a01b0316613b81565b600f5485519192506000916136ff9163ffffffff6137a416565b601054602087015191925060030b016000613724846125e58a8863ffffffff6137a416565b601654909150600390810b90600090819085810b9084900b12156137755782850360030b915061376e61376187600a85900a63ffffffff6137a416565b859063ffffffff61398516565b9050612e4b565b84830360030b9150613795866125e586600a86900a63ffffffff6137a416565b9b9a5050505050505050505050565b6000826137b357506000611138565b828202828482816137c057fe5b04146111355760405162461bcd60e51b8152600401808060200182810382526021815260200180613f586021913960400191505060405180910390fd5b601754613812906001600160a01b0316612a44565b1561384d576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156131b2573d6000803e3d6000fd5b6017546040805163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529151919092169163a9059cbb9160448083019260209291908290030181600087803b15801561321657600080fd5b6000806138c4601660089054906101000a90046001600160a01b0316613b81565b6018549091506000906138df906001600160a01b0316613b81565b9050600061390782612db28760000151612db2600f600001548b6137a490919063ffffffff16565b6016546020870151601054929350600391820b92820b01919091039060009082900b811215613955578161394d866125e58663ffffffff808616600a0a8116906137a416565b91505061397a565b6000829003613976866125e58663ffffffff808616600a0a81169061398516565b9150505b979650505050505050565b600061113583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613c20565b6001600160a01b038216613a0c5760405162461bcd60e51b81526004018080602001828103825260218152602001806140156021913960400191505060405180910390fd5b613a4f81604051806060016040528060228152602001613dab602291396001600160a01b038516600090815260016020526040902054919063ffffffff6130a916565b6001600160a01b038316600090815260016020526040902055600354613a7b908263ffffffff612cb816565b6003556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b6001600160a01b031660009081526005602052604090206001015490565b6001600160a01b038116613b265760405162461bcd60e51b8152600401808060200182810382526026815260200180613df56026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160a01b038216613ba05750670de0b6b3a76400006112b0565b601954604080516341976e0960e01b81526001600160a01b038581166004830152915191909216916341976e09916024808301926020929190829003018186803b158015613bed57600080fd5b505afa158015613c01573d6000803e3d6000fd5b505050506040513d6020811015613c1757600080fd5b505190506112b0565b60008183613c6f5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156130fd5781810151838201526020016130e5565b506000838581613c7b57fe5b0495945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613cc657805160ff1916838001178555613cf3565b82800160010185558215613cf3579182015b82811115613cf3578251825591602001919060010190613cd8565b50613cff929150613d1a565b5090565b604080518082019091526000808252602082015290565b6111e291905b80821115613cff5760008155600101613d2056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737343616e27742068617665206d696e436f6c6c61746572616c697a6174696f6e526174696f203c203143616e2774206c6971756964617465206d6f7265207468616e2031303025206f6620746865207661756c7445524332303a206275726e20616d6f756e7420657863656564732062616c616e6365455448206973206e6f74207468652073706563696669656420636f6c6c61746572616c20747970654f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737343616e277420636f6c6c65637420636f6c6c61746572616c20756e74696c20657870697279436f756c64206e6f74207472616e7366657220696e20636f6c6c61746572616c20746f6b656e735661756c7420646f6573206e6f7420657869737400000000000000000000000045524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636543616e27742068617665203e323025206c69717569646174696f6e20696e63656e74697665537065636966696564207661756c7473206861766520696e73756666696369656e7420636f6c6c61746572616c43616e206f6e6c79206c6971756964617465206c69717569646174696f6e20666163746f7220617420616e7920676976656e2074696d65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7743616e27742072656d6f7665206d6f726520636f6c6c61746572616c207468616e206f776e656443616e2774206578657263697365206f757473696465206f66207468652065786572636973652077696e646f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e63654f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657245524332303a206275726e2066726f6d20746865207a65726f206164647265737343616e6e6f742065786572636973652066726f6d2061207661756c74207468617420646f65736e277420657869737445524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737343616e2774206578657263697365206d6f7265206f546f6b656e73207468616e20746865206f776e6572206861734f7074696f6e7320636f6e74726163742065787069726564000000000000000045524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a7230582078d274c261df68e9d5018737bd71b890ed72cabfe0e584eb1d201ad752666c9564736f6c634300050a003245786572636973652077696e646f772063616e2774206265206c6f6e676572207468616e2074686520636f6e74726163742773206c6966657370616e636f6c6c61746572616c206578706f6e656e74206e6f742077697468696e2065787065637465642072616e67656f546f6b656e2065786368616e67652072617465206578706f6e656e74206e6f742077697468696e2065787065637465642072616e6765737472696b65207072696365206578706f6e656e74206e6f742077697468696e2065787065637465642072616e6765756e6465726c79696e67206578706f6e656e74206e6f742077697468696e2065787065637465642072616e67650000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee0000000000000000000000005d3a536e4d6dbd6114cc1ead35777bab948e3643fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000602322000000000000000000000000005778f2824a114f6115dc74d432685d33362160170000000000000000000000007054e08461e3ecb7718b63540addb3c3a17464150000000000000000000000000000000000000000000000000000000060232200

Deployed Bytecode

0x6080604052600436106103975760003560e01c806390e64d13116101dc578063c52987cf11610102578063e184c9be116100a0578063ee1eab4f1161006f578063ee1eab4f14610ed3578063f2fde38b14610f0f578063f70a250814610f42578063faa2041f14610f7557610397565b8063e184c9be14610e35578063ea8c4bcf14610e4a578063eaa376b514610e7d578063ed1f41c314610ea757610397565b8063cfbea789116100dc578063cfbea78914610d86578063d8dfeb4514610db2578063dd62ed3e14610dc7578063dec44c0b14610e0257610397565b8063c52987cf14610cff578063c56749ce14610d14578063cdb4b5c214610d5357610397565b8063b2c2b13f1161017a578063b7b090ee11610149578063b7b090ee14610b4f578063b96661ba14610c85578063ba1be55414610cb1578063bcbaf48714610cc657610397565b8063b2c2b13f14610ae2578063b6e61c0814610b10578063b736554014610b25578063b76fdb6c14610b3a57610397565b80639ed3edf0116101b65780639ed3edf014610a46578063a457c2d714610a5b578063a9059cbb14610a94578063ad8f500814610acd57610397565b806390e64d13146109f657806395d89b4114610a0b5780639ce0725114610a2057610397565b806339509351116102c15780636fd865f91161025f5780638a5e8cc71161022e5780638a5e8cc7146109a25780638c765e94146109b75780638da5cb5b146109cc5780638f32d59b146109e157610397565b80636fd865f91461091b57806370a0823114610945578063715018a61461097857806386f547121461098d57610397565b806358b36dac1161029b57806358b36dac146107f55780635ca7c8a61461089d578063686c1e21146108dc5780636f307dc31461090657610397565b8063395093511461074c5780633bd33f621461078557806352f89fe3146107b657610397565b806318160ddd116103395780633226052d116103085780633226052d146106845780633237c158146106c3578063352ade55146106ed5780633667429f1461072057610397565b806318160ddd146105c65780631a0e21bd146105db57806323b872dd14610616578063313ce5671461065957610397565b8063095ea7b311610375578063095ea7b3146104d65780630d453efb146105235780630d6cd8aa146105565780630eb9af381461056b57610397565b806301b4a3c11461039c578063060ab2ea146103e757806306fdde031461044c575b600080fd5b3480156103a857600080fd5b506103d5600480360360408110156103bf57600080fd5b506001600160a01b038135169060200135610f8a565b60408051918252519081900360200190f35b3480156103f357600080fd5b506103fc61113e565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610438578181015183820152602001610420565b505050509050019250505060405180910390f35b34801561045857600080fd5b506104616111e5565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561049b578181015183820152602001610483565b50505050905090810190601f1680156104c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104e257600080fd5b5061050f600480360360408110156104f957600080fd5b506001600160a01b038135169060200135611273565b604080519115158252519081900360200190f35b34801561052f57600080fd5b5061050f6004803603602081101561054657600080fd5b50356001600160a01b0316611290565b34801561056257600080fd5b5061050f6112b5565b34801561057757600080fd5b5061059e6004803603602081101561058e57600080fd5b50356001600160a01b03166112e3565b6040805194855260208501939093528383019190915215156060830152519081900360800190f35b3480156105d257600080fd5b506103d5611317565b3480156105e757600080fd5b50610614600480360360408110156105fe57600080fd5b50803590602001356001600160a01b031661131d565b005b34801561062257600080fd5b5061050f6004803603606081101561063957600080fd5b506001600160a01b03813581169160208101359091169060400135611486565b34801561066557600080fd5b5061066e611513565b6040805160ff9092168252519081900360200190f35b34801561069057600080fd5b50610614600480360360608110156106a757600080fd5b50803590602081013590604001356001600160a01b031661151c565b3480156106cf57600080fd5b50610614600480360360208110156106e657600080fd5b5035611634565b3480156106f957600080fd5b50610702611824565b60408051928352600391820b90910b60208301528051918290030190f35b6106146004803603604081101561073657600080fd5b50803590602001356001600160a01b0316611830565b34801561075857600080fd5b5061050f6004803603604081101561076f57600080fd5b506001600160a01b038135169060200135611945565b34801561079157600080fd5b5061079a611999565b604080516001600160a01b039092168252519081900360200190f35b3480156107c257600080fd5b50610614600480360360608110156107d957600080fd5b50803590602081013590604001356001600160a01b03166119a8565b6106146004803603604081101561080b57600080fd5b81359190810190604081016020820135600160201b81111561082c57600080fd5b82018360208201111561083e57600080fd5b803590602001918460208302840111600160201b8311171561085f57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506119c1945050505050565b3480156108a957600080fd5b50610614600480360360608110156108c057600080fd5b50803590602081013590604001356001600160a01b0316611ad9565b3480156108e857600080fd5b506103d5600480360360208110156108ff57600080fd5b5035611aee565b34801561091257600080fd5b5061079a611b1c565b34801561092757600080fd5b506103d56004803603602081101561093e57600080fd5b5035611b2b565b34801561095157600080fd5b506103d56004803603602081101561096857600080fd5b50356001600160a01b0316611b6f565b34801561098457600080fd5b50610614611b8a565b34801561099957600080fd5b5061050f611c1b565b3480156109ae57600080fd5b5061079a611d88565b3480156109c357600080fd5b50610702611d97565b3480156109d857600080fd5b5061079a611da3565b3480156109ed57600080fd5b5061050f611db2565b348015610a0257600080fd5b5061050f611dd6565b348015610a1757600080fd5b50610461611ddf565b6103d560048036036020811015610a3657600080fd5b50356001600160a01b0316611e3a565b348015610a5257600080fd5b50610702611f74565b348015610a6757600080fd5b5061050f60048036036040811015610a7e57600080fd5b506001600160a01b038135169060200135611f80565b348015610aa057600080fd5b5061050f60048036036040811015610ab757600080fd5b506001600160a01b038135169060200135611fee565b348015610ad957600080fd5b5061079a612002565b348015610aee57600080fd5b50610af7612011565b60408051600392830b90920b8252519081900360200190f35b348015610b1c57600080fd5b50610af7612021565b348015610b3157600080fd5b5061070261202a565b348015610b4657600080fd5b50610614612036565b348015610b5b57600080fd5b5061061460048036036040811015610b7257600080fd5b810190602081018135600160201b811115610b8c57600080fd5b820183602082011115610b9e57600080fd5b803590602001918460018302840111600160201b83111715610bbf57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610c1157600080fd5b820183602082011115610c2357600080fd5b803590602001918460018302840111600160201b83111715610c4457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612142945050505050565b61061460048036036040811015610c9b57600080fd5b50803590602001356001600160a01b03166121d3565b348015610cbd57600080fd5b506107026121e7565b348015610cd257600080fd5b5061061460048036036040811015610ce957600080fd5b506001600160a01b0381351690602001356121f3565b348015610d0b57600080fd5b506107026124f7565b348015610d2057600080fd5b5061061460048036036060811015610d3757600080fd5b50803590602081013590604001356001600160a01b0316612503565b348015610d5f57600080fd5b5061050f60048036036020811015610d7657600080fd5b50356001600160a01b0316612517565b61061460048036036040811015610d9c57600080fd5b50803590602001356001600160a01b031661253c565b348015610dbe57600080fd5b5061079a612550565b348015610dd357600080fd5b506103d560048036036040811015610dea57600080fd5b506001600160a01b0381358116916020013516612566565b348015610e0e57600080fd5b506103d560048036036020811015610e2557600080fd5b50356001600160a01b0316612591565b348015610e4157600080fd5b506103d561265c565b348015610e5657600080fd5b5061061460048036036020811015610e6d57600080fd5b50356001600160a01b0316612662565b348015610e8957600080fd5b5061061460048036036020811015610ea057600080fd5b5035612704565b61061460048036036040811015610ebd57600080fd5b50803590602001356001600160a01b0316612806565b348015610edf57600080fd5b5061061460048036036080811015610ef657600080fd5b5080359060208101359060408101359060600135612819565b348015610f1b57600080fd5b5061061460048036036020811015610f3257600080fd5b50356001600160a01b03166129f1565b348015610f4e57600080fd5b5061050f60048036036020811015610f6557600080fd5b50356001600160a01b0316612a44565b348015610f8157600080fd5b50610614612a51565b6000610f94611dd6565b15610fd4576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b601654604080516323b872dd60e01b8152336004820152306024820152604481018590529051600160401b9092046001600160a01b0316916323b872dd916064808201926020929091908290030181600087803b15801561103457600080fd5b505af1158015611048573d6000803e3d6000fd5b505050506040513d602081101561105e57600080fd5b505161109b5760405162461bcd60e51b8152600401808060200182810382526027815260200180613e626027913960400191505060405180910390fd5b6110a483611290565b6110e3576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b604080516001600160a01b038516815260208101849052338183015290517f2199418ea9428ed3ff7d460860e1edaf5831452fa4ea0f8d1a60d63c603487829181900360600190a16111358383612b49565b90505b92915050565b6060806000805b6006548110156111dc576111796006828154811061115f57fe5b6000918252602090912001546001600160a01b0316611290565b156111d4576006818154811061118b57fe5b9060005260206000200160009054906101000a90046001600160a01b03168383815181106111b557fe5b6001600160a01b03909216602092830291909101909101526001909101905b600101611145565b50909150505b90565b601a805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561126b5780601f106112405761010080835404028352916020019161126b565b820191906000526020600020905b81548152906001019060200180831161124e57829003601f168201915b505050505081565b6000611287611280612bc8565b8484612bcc565b50600192915050565b6001600160a01b03811660009081526005602052604090206003015460ff165b919050565b60006112ce601354601554612cb890919063ffffffff16565b42101580156112de575060155442105b905090565b6001600160a01b03166000908152600560205260409020805460018201546002830154600390930154919390929160ff1690565b60035490565b611325611dd6565b15611365576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b61136e33611290565b6113ad576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b33600090815260056020526040812060018101549091906113d4908563ffffffff612cfa16565b90506113e4826000015482612d54565b611426576040805162461bcd60e51b815260206004820152600e60248201526d1d5b9cd85999481d1bc81b5a5b9d60921b604482015290519081900360640190fd5b600182018190556114378385612e59565b604080516001600160a01b038516815260208101869052338183015290517f5e5aaabf04e3760968ffb551bdf9708f4dbf95d53ad98539e91a56b125e88f089181900360600190a150505b5050565b6000611493848484612f4b565b6115098461149f612bc8565b61150485604051806060016040528060288152602001613fcd602891396001600160a01b038a166000908152600260205260408120906114dd612bc8565b6001600160a01b03168152602081019190915260400160002054919063ffffffff6130a916565b612bcc565b5060019392505050565b601c5460ff1681565b6115263383610f8a565b50611531833061131d565b600480546040805163095ea7b360e01b81526001600160a01b0390921692820192909252602481018590529051309163095ea7b39160448083019260209291908290030181600087803b15801561158757600080fd5b505af115801561159b573d6000803e3d6000fd5b505050506040513d60208110156115b157600080fd5b50506004805460408051637dafae5960e01b81526001600160a01b03858116948201949094523060248201526000604482018190526064820188905291519390921692637dafae5992608480820193929182900301818387803b15801561161757600080fd5b505af115801561162b573d6000803e3d6000fd5b50505050505050565b61163c611dd6565b1561167c576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b600081116116d1576040805162461bcd60e51b815260206004820152601a60248201527f43616e6e6f742072656d6f7665203020636f6c6c61746572616c000000000000604482015290519081900360640190fd5b6116da33611290565b611719576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b3360008181526005602052604090209061173290613140565b8211156117705760405162461bcd60e51b8152600401808060200182810382526027815260200180613f796027913960400191505060405180910390fd5b8054600090611785908463ffffffff612cb816565b9050611795818360010154612d54565b6117d8576040805162461bcd60e51b815260206004820152600f60248201526e5661756c7420697320756e7361666560881b604482015290519081900360640190fd5b8082556117e5338461315b565b6040805184815233602082015281517f5a945309b3c58e9bb259128c2a530a6579dc75ac1d7d61b3db4c0b8305a16821929181900390910190a1505050565b600b54600c5460030b82565b611838611c1b565b5061184382306121d3565b600480546040805163095ea7b360e01b81526001600160a01b0390921692820192909252602481018490529051309163095ea7b39160448083019260209291908290030181600087803b15801561189957600080fd5b505af11580156118ad573d6000803e3d6000fd5b505050506040513d60208110156118c357600080fd5b50506004805460408051637dafae5960e01b81526001600160a01b03858116948201949094523060248201526000604482018190526064820187905291519390921692637dafae5992608480820193929182900301818387803b15801561192957600080fd5b505af115801561193d573d6000803e3d6000fd5b505050505050565b6000611287611952612bc8565b846115048560026000611963612bc8565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff612cfa16565b6004546001600160a01b031681565b6119b0611c1b565b506119bc838383611ad9565b505050565b60005b8151811015611a9b5760008282815181106119db57fe5b602002602001015190506119ee81611290565b611a295760405162461bcd60e51b815260040180806020018281038252602f815260200180614036602f913960400191505060405180910390fd5b6001600160a01b038116600090815260056020526040902084611a4e57505050611482565b84816001015410611a6b57611a638583613246565b505050611482565b6001810154611a8190869063ffffffff612cb816565b9450611a91816001015483613246565b50506001016119c4565b5081156114825760405162461bcd60e51b815260040180806020018281038252602d815260200180613ef4602d913960400191505060405180910390fd5b611ae33383610f8a565b506119bc838261131d565b60408051808201909152600d548152600e54600390810b810b900b60208201526000906111389083906136a9565b6017546001600160a01b031681565b601654601254600091600160201b9004600390810b91810b91909103900b611b688367ffffffffffffffff808416600a0a1663ffffffff6137a416565b9392505050565b6001600160a01b031660009081526001602052604090205490565b611b92611db2565b611bd1576040805162461bcd60e51b81526020600482018190526024820152600080516020613ff5833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000611c25611dd6565b15611c65576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b611c6e33611290565b15611cb8576040805162461bcd60e51b815260206004820152601560248201527415985d5b1d08185b1c9958591e4818dc99585d1959605a1b604482015290519081900360640190fd5b60408051608081018252600080825260208083018281528385018381526001606086018181523380875260058652888720975188559351878301559151600287015590516003909501805460ff1916951515959095179094556006805494850181559092527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90920180546001600160a01b03191682179055825190815291517f66a872561db77eb92ef3079a44a5af00c68c3a09e0976814a95bd91721f57c2f9281900390910190a150600190565b6019546001600160a01b031681565b60075460085460030b82565b6000546001600160a01b031690565b600080546001600160a01b0316611dc7612bc8565b6001600160a01b031614905090565b60155442101590565b601b805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561126b5780601f106112405761010080835404028352916020019161126b565b6000611e44611dd6565b15611e84576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b601654611ea090600160401b90046001600160a01b0316612a44565b611edb5760405162461bcd60e51b8152600401808060200182810382526028815260200180613dcd6028913960400191505060405180910390fd5b611ee482611290565b611f23576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b604080516001600160a01b0384168152346020820152338183015290517ff24ce6016de57e90501829715846e26ac283a0aabfc160647e0ae8b05e0f433d9181900360600190a16111388234612b49565b600954600a5460030b82565b6000611287611f8d612bc8565b84611504856040518060600160405280602581526020016140fc6025913960026000611fb7612bc8565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff6130a916565b6000611287611ffb612bc8565b8484612f4b565b6018546001600160a01b031681565b601654600160201b900460030b81565b60165460030b81565b60115460125460030b82565b61203e611dd6565b6120795760405162461bcd60e51b8152600401808060200182810382526025815260200180613e3d6025913960400191505060405180910390fd5b61208233611290565b6120c1576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b33600081815260056020526040812080546002820180548484556001840185905593905590929091906120f4908361315b565b6120fe33826137fd565b6040805183815260208101839052338183015290517fe481532a3f7d078365ca0145442ed0a0a3e0443f3c0bae0c29cff131112678389181900360600190a1505050565b61214a611db2565b612189576040805162461bcd60e51b81526020600482018190526024820152600080516020613ff5833981519152604482015290519081900360640190fd5b815161219c90601a906020850190613c85565b5080516121b090601b906020840190613c85565b50601254601c805460ff191660039290920b60000360ff16919091179055611482565b6121dc33611e3a565b50611482828261131d565b600d54600e5460030b82565b6121fb611dd6565b1561223b576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b61224482611290565b612283576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b6001600160a01b03821660009081526005602052604090206122a483612517565b6122e5576040805162461bcd60e51b815260206004820152600d60248201526c5661756c74206973207361666560981b604482015290519081900360640190fd5b336001600160a01b0384161415612343576040805162461bcd60e51b815260206004820181905260248201527f4f776e65722063616e2774206c6971756964617465207468656d73656c766573604482015290519081900360640190fd5b600061236883604051806040016040528060018152602001600060030b8152506138a3565b604080518082019091526007548152600854600390810b810b900b60208201529091506000906123999085906138a3565b905060006123ad838363ffffffff612cfa16565b600b5485549192506000916123c79163ffffffff6137a416565b600c549091506000600391820b90910b131561240257600c546123fb908290600390810b900b600a0a63ffffffff6137a416565b9050612426565b600c54612423908290600390810b600003900b600a0a63ffffffff61398516565b90505b808211156124655760405162461bcd60e51b8152600401808060200182810382526037815260200180613f216037913960400191505060405180910390fd5b8454612477908363ffffffff612cb816565b8555600185015461248e908763ffffffff612cb816565b600186015561249d33876139c7565b6124a7338361315b565b604080518381526001600160a01b0389166020820152338183015290517fcab8e1abb9f8235c6db895cf185336dc9461aecf477b98c1be83687ee549e66a9181900360600190a150505050505050565b600f5460105460030b82565b61250b611c1b565b50611531838330611ad9565b60008061253461252684613140565b61252f85613ac3565b612d54565b159392505050565b61254533611e3a565b50611843823061131d565b601654600160401b90046001600160a01b031681565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b600061259c82612517565b15612654576001600160a01b0382166000908152600560205260408120600c54600b5482549293926125f192600390810b8503900b600a0a916125e5919063ffffffff6137a416565b9063ffffffff61398516565b600854909150600390810b600003900b600a0a61260c613d03565b60408051808201909152600754819061262b908563ffffffff612cfa16565b8152600854600390810b900b602090910152905061264983826136a9565b9450505050506112b0565b5060006112b0565b60155481565b61266a611db2565b6126a9576040805162461bcd60e51b81526020600482018190526024820152600080516020613ff5833981519152604482015290519081900360640190fd5b6014805460009091556126bc828261315b565b604080516001600160a01b03841681526020810183905281517f88b171bb78d3ac5e1caa8e729dddce4e1322e84c80c093ebbe52507b62c77d98929181900390910190a15050565b61270c611dd6565b1561274c576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b61275533611290565b612794576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b33600090815260056020526040902060018101546127b8908363ffffffff612cb816565b60018201556127c733836139c7565b604080513381526020810184905281517fdf8cebdea6ef1fd20576b80bc951377c0e61e2a8169153a1f836673ccce80e62929181900390910190a15050565b61280e611c1b565b5061148282826121d3565b612821611db2565b612860576040805162461bcd60e51b81526020600482018190526024820152600080516020613ff5833981519152604482015290519081900360640190fd5b60c88411156128a05760405162461bcd60e51b8152600401808060200182810382526025815260200180613ecf6025913960400191505060405180910390fd5b6103e88311156128e15760405162461bcd60e51b815260040180806020018281038252602b815260200180613d80602b913960400191505060405180910390fd5b6064821115612937576040805162461bcd60e51b815260206004820181905260248201527f43616e27742068617665207472616e73616374696f6e20666565203e20313025604482015290519081900360640190fd5b600a8110156129775760405162461bcd60e51b8152600401808060200182810382526028815260200180613d586028913960400191505060405180910390fd5b6007849055600b8390556009829055600d8190557f3450d20c21ea671871fed271900cc8ff03badafa9b6fe2ff7f86991950e86b6b848484846129b8611da3565b6040805195865260208601949094528484019290925260608401526001600160a01b03166080830152519081900360a00190a150505050565b6129f9611db2565b612a38576040805162461bcd60e51b81526020600482018190526024820152600080516020613ff5833981519152604482015290519081900360640190fd5b612a4181613ae1565b50565b6001600160a01b03161590565b612a5a33611290565b612a99576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b3360009081526005602052604090206002810154612af6576040805162461bcd60e51b81526020600482015260156024820152744e6f20756e6465726c79696e672062616c616e636560581b604482015290519081900360640190fd5b6002810180546000909155612b0b33826137fd565b6040805182815233602082015281517fea0bff65fa9380b944e9a761f9c6a665ad2d31e74706a52773ddb45c8a57c83d929181900390910190a15050565b6000612b53611dd6565b15612b93576040805162461bcd60e51b815260206004820152601860248201526000805160206140dc833981519152604482015290519081900360640190fd5b6001600160a01b03831660009081526005602052604090208054612bbd908463ffffffff612cfa16565b908190559392505050565b3390565b6001600160a01b038316612c115760405162461bcd60e51b815260040180806020018281038252602481526020018061408a6024913960400191505060405180910390fd5b6001600160a01b038216612c565760405162461bcd60e51b8152600401808060200182810382526022815260200180613e1b6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b600061113583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506130a9565b600082820183811015611135576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600080612d75601660089054906101000a90046001600160a01b0316613b81565b601854909150600090612d90906001600160a01b0316613b81565b600f54600d54919250600091612dbe9190612db290889063ffffffff6137a416565b9063ffffffff6137a416565b601054600e54919250600391820b910b016000612de5846125e58a8863ffffffff6137a416565b601654909150600390810b90600090819085810b9084900b1215612e295782850360030b915083612e2087600a85900a63ffffffff6137a416565b11159050612e4b565b84830360030b9150612e4584600a84900a63ffffffff6137a416565b86111590505b9a9950505050505050505050565b6001600160a01b038216612eb4576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b600354612ec7908263ffffffff612cfa16565b6003556001600160a01b038216600090815260016020526040902054612ef3908263ffffffff612cfa16565b6001600160a01b03831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b038316612f905760405162461bcd60e51b81526004018080602001828103825260258152602001806140656025913960400191505060405180910390fd5b6001600160a01b038216612fd55760405162461bcd60e51b8152600401808060200182810382526023815260200180613d356023913960400191505060405180910390fd5b61301881604051806060016040528060268152602001613ea9602691396001600160a01b038616600090815260016020526040902054919063ffffffff6130a916565b6001600160a01b03808516600090815260016020526040808220939093559084168152205461304d908263ffffffff612cfa16565b6001600160a01b0380841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156131385760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156130fd5781810151838201526020016130e5565b50505050905090810190601f16801561312a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b031660009081526005602052604090205490565b60165461317790600160401b90046001600160a01b0316612a44565b156131b8576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156131b2573d6000803e3d6000fd5b50611482565b6016546040805163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529151600160401b9093049091169163a9059cbb916044808201926020929091908290030181600087803b15801561321657600080fd5b505af115801561322a573d6000803e3d6000fd5b505050506040513d602081101561324057600080fd5b50505050565b61324e6112b5565b6132895760405162461bcd60e51b815260040180806020018281038252602d815260200180613fa0602d913960400191505060405180910390fd5b61329281611290565b6132d1576040805162461bcd60e51b81526020600482015260146024820152600080516020613e89833981519152604482015290519081900360640190fd5b6001600160a01b03811660009081526005602052604090208261333b576040805162461bcd60e51b815260206004820152601860248201527f43616e27742065786572636973652030206f546f6b656e730000000000000000604482015290519081900360640190fd5b806001015483111561337e5760405162461bcd60e51b815260040180806020018281038252602e8152602001806140ae602e913960400191505060405180910390fd5b8261338833611b6f565b10156133d0576040805162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f756768206f546f6b656e7360701b604482015290519081900360640190fd5b60006133db84611b2b565b60028301549091506133f3908263ffffffff612cfa16565b600283015560408051808201909152600181526000602082018190529061341b9086906138a3565b604080518082019091526009548152600a54600390810b810b900b602082015290915060009061344c9087906138a3565b601454909150613462908263ffffffff612cfa16565b6014556000613477838363ffffffff612cfa16565b85549091508111156134d0576040805162461bcd60e51b815260206004820181905260248201527f5661756c7420756e64657277617465722c2063616e2774206578657263697365604482015290519081900360640190fd5b84546134e2908263ffffffff612cb816565b855560018501546134f9908863ffffffff612cb816565b6001860155601754613513906001600160a01b0316612a44565b1561356757833414613562576040805162461bcd60e51b8152602060048201526013602482015272496e636f7272656374206d73672e76616c756560681b604482015290519081900360640190fd5b61363e565b601754604080516323b872dd60e01b81523360048201523060248201526044810187905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b1580156135c157600080fd5b505af11580156135d5573d6000803e3d6000fd5b505050506040513d60208110156135eb57600080fd5b505161363e576040805162461bcd60e51b815260206004820152601c60248201527f436f756c64206e6f74207472616e7366657220696e20746f6b656e7300000000604482015290519081900360640190fd5b61364833886139c7565b613652338461315b565b604080518581526020810185905233818301526001600160a01b038816606082015290517ffa7bab37479e50a9b24a9412b879d400de9bcaa1e3a2b343e90bb370d85bbaa79181900360800190a150505050505050565b6000806136ca601660089054906101000a90046001600160a01b0316613b81565b6018549091506000906136e5906001600160a01b0316613b81565b600f5485519192506000916136ff9163ffffffff6137a416565b601054602087015191925060030b016000613724846125e58a8863ffffffff6137a416565b601654909150600390810b90600090819085810b9084900b12156137755782850360030b915061376e61376187600a85900a63ffffffff6137a416565b859063ffffffff61398516565b9050612e4b565b84830360030b9150613795866125e586600a86900a63ffffffff6137a416565b9b9a5050505050505050505050565b6000826137b357506000611138565b828202828482816137c057fe5b04146111355760405162461bcd60e51b8152600401808060200182810382526021815260200180613f586021913960400191505060405180910390fd5b601754613812906001600160a01b0316612a44565b1561384d576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156131b2573d6000803e3d6000fd5b6017546040805163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529151919092169163a9059cbb9160448083019260209291908290030181600087803b15801561321657600080fd5b6000806138c4601660089054906101000a90046001600160a01b0316613b81565b6018549091506000906138df906001600160a01b0316613b81565b9050600061390782612db28760000151612db2600f600001548b6137a490919063ffffffff16565b6016546020870151601054929350600391820b92820b01919091039060009082900b811215613955578161394d866125e58663ffffffff808616600a0a8116906137a416565b91505061397a565b6000829003613976866125e58663ffffffff808616600a0a81169061398516565b9150505b979650505050505050565b600061113583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613c20565b6001600160a01b038216613a0c5760405162461bcd60e51b81526004018080602001828103825260218152602001806140156021913960400191505060405180910390fd5b613a4f81604051806060016040528060228152602001613dab602291396001600160a01b038516600090815260016020526040902054919063ffffffff6130a916565b6001600160a01b038316600090815260016020526040902055600354613a7b908263ffffffff612cb816565b6003556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b6001600160a01b031660009081526005602052604090206001015490565b6001600160a01b038116613b265760405162461bcd60e51b8152600401808060200182810382526026815260200180613df56026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160a01b038216613ba05750670de0b6b3a76400006112b0565b601954604080516341976e0960e01b81526001600160a01b038581166004830152915191909216916341976e09916024808301926020929190829003018186803b158015613bed57600080fd5b505afa158015613c01573d6000803e3d6000fd5b505050506040513d6020811015613c1757600080fd5b505190506112b0565b60008183613c6f5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156130fd5781810151838201526020016130e5565b506000838581613c7b57fe5b0495945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613cc657805160ff1916838001178555613cf3565b82800160010185558215613cf3579182015b82811115613cf3578251825591602001919060010190613cd8565b50613cff929150613d1a565b5090565b604080518082019091526000808252602082015290565b6111e291905b80821115613cff5760008155600101613d2056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737343616e27742068617665206d696e436f6c6c61746572616c697a6174696f6e526174696f203c203143616e2774206c6971756964617465206d6f7265207468616e2031303025206f6620746865207661756c7445524332303a206275726e20616d6f756e7420657863656564732062616c616e6365455448206973206e6f74207468652073706563696669656420636f6c6c61746572616c20747970654f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737343616e277420636f6c6c65637420636f6c6c61746572616c20756e74696c20657870697279436f756c64206e6f74207472616e7366657220696e20636f6c6c61746572616c20746f6b656e735661756c7420646f6573206e6f7420657869737400000000000000000000000045524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636543616e27742068617665203e323025206c69717569646174696f6e20696e63656e74697665537065636966696564207661756c7473206861766520696e73756666696369656e7420636f6c6c61746572616c43616e206f6e6c79206c6971756964617465206c69717569646174696f6e20666163746f7220617420616e7920676976656e2074696d65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7743616e27742072656d6f7665206d6f726520636f6c6c61746572616c207468616e206f776e656443616e2774206578657263697365206f757473696465206f66207468652065786572636973652077696e646f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e63654f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657245524332303a206275726e2066726f6d20746865207a65726f206164647265737343616e6e6f742065786572636973652066726f6d2061207661756c74207468617420646f65736e277420657869737445524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737343616e2774206578657263697365206d6f7265206f546f6b656e73207468616e20746865206f776e6572206861734f7074696f6e7320636f6e74726163742065787069726564000000000000000045524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a7230582078d274c261df68e9d5018737bd71b890ed72cabfe0e584eb1d201ad752666c9564736f6c634300050a0032

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

0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee0000000000000000000000005d3a536e4d6dbd6114cc1ead35777bab948e3643fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000002fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000602322000000000000000000000000005778f2824a114f6115dc74d432685d33362160170000000000000000000000007054e08461e3ecb7718b63540addb3c3a17464150000000000000000000000000000000000000000000000000000000060232200

-----Decoded View---------------
Arg [0] : _collateral (address): 0x0000000000000000000000000000000000000000
Arg [1] : _collExp (int32): -18
Arg [2] : _underlying (address): 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643
Arg [3] : _underlyingExp (int32): -8
Arg [4] : _oTokenExchangeExp (int32): -8
Arg [5] : _strikePrice (uint256): 2
Arg [6] : _strikeExp (int32): -10
Arg [7] : _strike (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [8] : _expiry (uint256): 1612915200
Arg [9] : _optionsExchange (address): 0x5778f2824a114F6115dc74d432685d3336216017
Arg [10] : _oracleAddress (address): 0x7054e08461e3eCb7718B63540adDB3c3A1746415
Arg [11] : _windowSize (uint256): 1612915200

-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee
Arg [2] : 0000000000000000000000005d3a536e4d6dbd6114cc1ead35777bab948e3643
Arg [3] : fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8
Arg [4] : fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [6] : fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6
Arg [7] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [8] : 0000000000000000000000000000000000000000000000000000000060232200
Arg [9] : 0000000000000000000000005778f2824a114f6115dc74d432685d3336216017
Arg [10] : 0000000000000000000000007054e08461e3ecb7718b63540addb3c3a1746415
Arg [11] : 0000000000000000000000000000000000000000000000000000000060232200


Deployed Bytecode Sourcemap

76403:7558:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51596:480;;8:9:-1;5:2;;;30:1;27;20:12;5:2;51596:480:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;51596:480:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;45645:383;;8:9:-1;5:2;;;30:1;27;20:12;5:2;45645:383:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;45645:383:0;;;;;;;;;;;;;;;;;41188:18;;8:9:-1;5:2;;;30:1;27;20:12;5:2;41188:18:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;41188:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12136:152;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12136:152:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;12136:152:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;48878:113;;8:9:-1;5:2;;;30:1;27;20:12;5:2;48878:113:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;48878:113:0;-1:-1:-1;;;;;48878:113:0;;:::i;52594:169::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52594:169:0;;;:::i;56975:342::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;56975:342:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;56975:342:0;-1:-1:-1;;;;;56975:342:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11157:91;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11157:91:0;;;:::i;56048:788::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;56048:788:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;56048:788:0;;;;;;-1:-1:-1;;;;;56048:788:0;;:::i;:::-;;12760:304;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12760:304:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;12760:304:0;;;;;;;;;;;;;;;;;:::i;41327:21::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;41327:21:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;83478:480;;8:9:-1;5:2;;;30:1;27;20:12;5:2;83478:480:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;83478:480:0;;;;;;;;;;;-1:-1:-1;;;;;83478:480:0;;:::i;58445:870::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;58445:870:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;58445:870:0;;:::i;39825:49::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;39825:49:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;79712:435;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;79712:435:0;;;;;;-1:-1:-1;;;;;79712:435:0;;:::i;13473:210::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;13473:210:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;13473:210:0;;;;;;;;:::i;39364:38::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;39364:38:0;;;:::i;:::-;;;;-1:-1:-1;;;;;39364:38:0;;;;;;;;;;;;;;81388:245;;8:9:-1;5:2;;;30:1;27;20:12;5:2;81388:245:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;81388:245:0;;;;;;;;;;;-1:-1:-1;;;;;81388:245:0;;:::i;53692:1013::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;53692:1013:0;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;53692:1013:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;53692:1013:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;53692:1013:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;53692:1013:0;;-1:-1:-1;53692:1013:0;;-1:-1:-1;;;;;53692:1013:0:i;82172:247::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;82172:247:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;82172:247:0;;;;;;;;;;;-1:-1:-1;;;;;82172:247:0;;:::i;71420:199::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;71420:199:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;71420:199:0;;:::i;40940:24::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40940:24:0;;;:::i;52193:320::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52193:320:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;52193:320:0;;:::i;11311:110::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11311:110:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;11311:110:0;-1:-1:-1;;;;;11311:110:0;;:::i;37970:140::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37970:140:0;;;:::i;49113:284::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;49113:284:0;;;:::i;41099:46::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;41099:46:0;;;:::i;39546:51::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;39546:51:0;;;:::i;37159:79::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37159:79:0;;;:::i;37525:94::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37525:94:0;;;:::i;52853:102::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52853:102:0;;;:::i;41251:20::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;41251:20:0;;;:::i;50201:418::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;50201:418:0;-1:-1:-1;;;;;50201:418:0;;:::i;39640:44::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;39640:44:0;;;:::i;14186:261::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;14186:261:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;14186:261:0;;;;;;;;:::i;11634:158::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11634:158:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;11634:158:0;;;;;;;;:::i;41029:20::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;41029:20:0;;;:::i;40786:32::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40786:32:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;40705;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40705:32:0;;;:::i;40280:::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40280:32:0;;;:::i;59577:800::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59577:800:0;;;:::i;47942:361::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;47942:361:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;47942:361:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;47942:361:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;47942:361:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;47942:361:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;47942:361:0;;;;;;;;-1:-1:-1;47942:361:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;47942:361:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;47942:361:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;47942:361:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;47942:361:0;;-1:-1:-1;47942:361:0;;-1:-1:-1;;;;;47942:361:0:i;79282:202::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;79282:202:0;;;;;;-1:-1:-1;;;;;79282:202:0;;:::i;40072:56::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40072:56:0;;;:::i;61981:1984::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;61981:1984:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;61981:1984:0;;;;;;;;:::i;40189:25::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40189:25:0;;;:::i;82717:478::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;82717:478:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;82717:478:0;;;;;;;;;;;-1:-1:-1;;;;;82717:478:0;;:::i;64153:241::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;64153:241:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;64153:241:0;-1:-1:-1;;;;;64153:241:0;;:::i;80397:437::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;80397:437:0;;;;;;-1:-1:-1;;;;;80397:437:0;;:::i;40856:24::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40856:24:0;;;:::i;11855:134::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11855:134:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;11855:134:0;;;;;;;;;;:::i;60574:790::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;60574:790:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;60574:790:0;-1:-1:-1;;;;;60574:790:0;;:::i;40635:21::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40635:21:0;;;:::i;48484:219::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;48484:219:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;48484:219:0;-1:-1:-1;;;;;48484:219:0;;:::i;57839:343::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;57839:343:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;57839:343:0;;:::i;78580:200::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;78580:200:0;;;;;;-1:-1:-1;;;;;78580:200:0;;:::i;46591:1126::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;46591:1126:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;46591:1126:0;;;;;;;;;;;;;;;;;:::i;38265:109::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38265:109:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;38265:109:0;-1:-1:-1;;;;;38265:109:0;;:::i;57439:104::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;57439:104:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;57439:104:0;-1:-1:-1;;;;;57439:104:0;;:::i;54838:449::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54838:449:0;;;:::i;51596:480::-;51719:7;45498:12;:10;:12::i;:::-;45497:13;45489:50;;;;;-1:-1:-1;;;45489:50:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;45489:50:0;;;;;;;;;;;;;;;51766:10;;:55;;;-1:-1:-1;;;51766:55:0;;51790:10;51766:55;;;;51810:4;51766:55;;;;;;;;;;;;-1:-1:-1;;;51766:10:0;;;-1:-1:-1;;;;;51766:10:0;;:23;;:55;;;;;;;;;;;;;;;-1:-1:-1;51766:10:0;:55;;;5:2:-1;;;;30:1;27;20:12;5:2;51766:55:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;51766:55:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;51766:55:0;51744:144;;;;-1:-1:-1;;;51744:144:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51907:20;51916:10;51907:8;:20::i;:::-;51899:53;;;;;-1:-1:-1;;;51899:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;51899:53:0;;;;;;;;;;;;;;;51970:49;;;-1:-1:-1;;;;;51970:49:0;;;;;;;;;;52008:10;51970:49;;;;;;;;;;;;;;;52037:31;52052:10;52064:3;52037:14;:31::i;:::-;52030:38;;45550:1;51596:480;;;;:::o;45645:383::-;45692:24;;45771:13;;45799:196;45823:11;:18;45819:22;;45799:196;;;45867:24;45876:11;45888:1;45876:14;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;45876:14:0;45867:8;:24::i;:::-;45863:121;;;45928:11;45940:1;45928:14;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;45928:14:0;45912:6;45919:5;45912:13;;;;;;;;-1:-1:-1;;;;;45912:30:0;;;:13;;;;;;;;;;;:30;45961:7;;;;;45863:121;45843:3;;45799:196;;;-1:-1:-1;46014:6:0;;-1:-1:-1;;45645:383:0;;:::o;41188:18::-;;;;;;;;;;;;;;;-1:-1:-1;;41188:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;12136:152::-;12202:4;12219:39;12228:12;:10;:12::i;:::-;12242:7;12251:6;12219:8;:39::i;:::-;-1:-1:-1;12276:4:0;12136:152;;;;:::o;48878:113::-;-1:-1:-1;;;;;48964:13:0;;48940:4;48964:13;;;:6;:13;;;;;:19;;;;;48878:113;;;;:::o;52594:169::-;52643:4;52688:22;52699:10;;52688:6;;:10;;:22;;;;:::i;:::-;52669:15;:41;;52668:86;;;;;52747:6;;52729:15;:24;52668:86;52660:95;;52594:169;:::o;56975:342::-;-1:-1:-1;;;;;57140:18:0;57069:7;57140:18;;;:6;:18;;;;;57191:16;;57222:19;;;;57256:16;;;;57287:11;;;;;57191:16;;57222:19;;57256:16;57287:11;;;56975:342::o;11157:91::-;11228:12;;11157:91;:::o;56048:788::-;45498:12;:10;:12::i;:::-;45497:13;45489:50;;;;;-1:-1:-1;;;45489:50:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;45489:50:0;;;;;;;;;;;;;;;56294:20;56303:10;56294:8;:20::i;:::-;56286:53;;;;;-1:-1:-1;;;56286:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;56286:53:0;;;;;;;;;;;;;;;56381:10;56352:19;56374:18;;;:6;:18;;;;;56498:19;;;;56374:18;;56352:19;56498:39;;56522:14;56498:39;:23;:39;:::i;:::-;56470:67;;56556:43;56563:5;:16;;;56581:17;56556:6;:43::i;:::-;56548:70;;;;;-1:-1:-1;;;56548:70:0;;;;;;;;;;;;-1:-1:-1;;;56548:70:0;;;;;;;;;;;;;;;56661:19;;;:39;;;56711:31;56717:8;56727:14;56711:5;:31::i;:::-;56760:51;;;-1:-1:-1;;;;;56760:51:0;;;;;;;;;;56800:10;56760:51;;;;;;;;;;;;;;;56822:7;;45550:1;56048:788;;:::o;12760:304::-;12849:4;12866:36;12876:6;12884:9;12895:6;12866:9;:36::i;:::-;12913:121;12922:6;12930:12;:10;:12::i;:::-;12944:89;12982:6;12944:89;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;12944:19:0;;;;;;:11;:19;;;;;;12964:12;:10;:12::i;:::-;-1:-1:-1;;;;;12944:33:0;;;;;;;;;;;;-1:-1:-1;12944:33:0;;;:89;;:37;:89;:::i;:::-;12913:8;:121::i;:::-;-1:-1:-1;13052:4:0;12760:304;;;;;:::o;41327:21::-;;;;;;:::o;83478:480::-;83641:45;83660:10;83672:13;83641:18;:45::i;:::-;;83697:40;83710:11;83731:4;83697:12;:40::i;:::-;83769:15;;;83748:51;;;-1:-1:-1;;;83748:51:0;;-1:-1:-1;;;;;83769:15:0;;;83748:51;;;;;;;;;;;;;;;:4;;:12;;:51;;;;;;;;;;;;;;-1:-1:-1;83748:4:0;:51;;;5:2:-1;;;;30:1;27;20:12;5:2;83748:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;83748:51:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;83810:15:0;;;:140;;;-1:-1:-1;;;83810:140:0;;-1:-1:-1;;;;;83810:140:0;;;;;;;;;;83883:4;83810:140;;;;:15;:140;;;;;;;;;;;;;;:15;;;;;:27;;:140;;;;;:15;:140;;;;;;:15;;:140;;;5:2:-1;;;;30:1;27;20:12;5:2;83810:140:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;83810:140:0;;;;83478:480;;;:::o;58445:870::-;45498:12;:10;:12::i;:::-;45497:13;45489:50;;;;;-1:-1:-1;;;45489:50:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;45489:50:0;;;;;;;;;;;;;;;58543:1;58529:11;:15;58521:54;;;;;-1:-1:-1;;;58521:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;58594:20;58603:10;58594:8;:20::i;:::-;58586:53;;;;;-1:-1:-1;;;58586:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;58586:53:0;;;;;;;;;;;;;;;58681:10;58652:19;58674:18;;;:6;:18;;;;;;58740:25;;:13;:25::i;:::-;58725:11;:40;;58703:129;;;;-1:-1:-1;;;58703:129:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58948:16;;58917:28;;58948:33;;58969:11;58948:33;:20;:33;:::i;:::-;58917:64;;59016:49;59023:20;59045:5;:19;;;59016:6;:49::i;:::-;58994:114;;;;;-1:-1:-1;;;58994:114:0;;;;;;;;;;;;-1:-1:-1;;;58994:114:0;;;;;;;;;;;;;;;59155:39;;;59205:43;59224:10;59236:11;59205:18;:43::i;:::-;59266:41;;;;;;59296:10;59266:41;;;;;;;;;;;;;;;;;45550:1;;58445:870;:::o;39825:49::-;;;;;;;;:::o;79712:435::-;79854:11;:9;:11::i;:::-;;79876:50;79899:11;79920:4;79876:22;:50::i;:::-;79958:15;;;79937:51;;;-1:-1:-1;;;79937:51:0;;-1:-1:-1;;;;;79958:15:0;;;79937:51;;;;;;;;;;;;;;;:4;;:12;;:51;;;;;;;;;;;;;;-1:-1:-1;79937:4:0;:51;;;5:2:-1;;;;30:1;27;20:12;5:2;79937:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79937:51:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;79999:15:0;;;:140;;;-1:-1:-1;;;79999:140:0;;-1:-1:-1;;;;;79999:140:0;;;;;;;;;;80072:4;79999:140;;;;:15;:140;;;;;;;;;;;;;;:15;;;;;:27;;:140;;;;;:15;:140;;;;;;:15;;:140;;;5:2:-1;;;;30:1;27;20:12;5:2;79999:140:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79999:140:0;;;;79712:435;;:::o;13473:210::-;13553:4;13570:83;13579:12;:10;:12::i;:::-;13593:7;13602:50;13641:10;13602:11;:25;13614:12;:10;:12::i;:::-;-1:-1:-1;;;;;13602:25:0;;;;;;;;;;;;;;;;;-1:-1:-1;13602:25:0;;;:34;;;;;;;;;;;:50;:38;:50;:::i;39364:38::-;;;-1:-1:-1;;;;;39364:38:0;;:::o;81388:245::-;81541:11;:9;:11::i;:::-;;81563:62;81588:11;81601:13;81616:8;81563:24;:62::i;:::-;81388:245;;;:::o;53692:1013::-;53840:9;53835:735;53859:20;:27;53855:1;:31;53835:735;;;53908:26;53937:20;53958:1;53937:23;;;;;;;;;;;;;;53908:52;;54001:20;54010:10;54001:8;:20::i;:::-;53975:129;;;;-1:-1:-1;;;53975:129:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;54141:18:0;;54119:19;54141:18;;;:6;:18;;;;;54178:22;54174:385;;54221:7;;;;;54174:385;54276:17;54253:5;:19;;;:40;54249:310;;54314:40;54324:17;54343:10;54314:9;:40::i;:::-;54373:7;;;;;54249:310;54462:19;;;;54440:42;;:17;;:42;:21;:42;:::i;:::-;54420:62;;54501:42;54511:5;:19;;;54532:10;54501:9;:42::i;:::-;-1:-1:-1;;53888:3:0;;53835:735;;;-1:-1:-1;54602:22:0;;54580:117;;;;-1:-1:-1;;;54580:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;82172:247;82320:45;82339:10;82351:13;82320:18;:45::i;:::-;;82376:35;82389:11;82402:8;82376:12;:35::i;71420:199::-;71551:58;;;;;;;;;71583:25;71551:58;;;;;;;;;;;;;;;;;71519:7;;71551:58;;71568:13;;71551:16;:58::i;40940:24::-;;;-1:-1:-1;;;;;40940:24:0;;:::o;52193:320::-;52414:13;;52384:27;;52306:7;;-1:-1:-1;;;52414:13:0;;;;;;52384:27;;;:43;;;;52363:75;;52456:49;:17;52478:26;;;;:2;:26;52456:49;;:21;:49;:::i;:::-;52449:56;52193:320;-1:-1:-1;;;52193:320:0:o;11311:110::-;-1:-1:-1;;;;;11395:18:0;11368:7;11395:18;;;:9;:18;;;;;;;11311:110::o;37970:140::-;37371:9;:7;:9::i;:::-;37363:54;;;;;-1:-1:-1;;;37363:54:0;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;37363:54:0;;;;;;;;;;;;;;;38069:1;38053:6;;38032:40;;-1:-1:-1;;;;;38053:6:0;;;;38032:40;;38069:1;;38032:40;38100:1;38083:19;;-1:-1:-1;;;;;;38083:19:0;;;37970:140::o;49113:284::-;49161:4;45498:12;:10;:12::i;:::-;45497:13;45489:50;;;;;-1:-1:-1;;;45489:50:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;45489:50:0;;;;;;;;;;;;;;;49187:20;49196:10;49187:8;:20::i;:::-;49186:21;49178:55;;;;;-1:-1:-1;;;49178:55:0;;;;;;;;;;;;-1:-1:-1;;;49178:55:0;;;;;;;;;;;;;;;49267:20;;;;;;;;-1:-1:-1;49267:20:0;;;;;;;;;;;;;;;;49282:4;49267:20;;;;;;49253:10;49246:18;;;:6;:18;;;;;:41;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;49246:41:0;;;;;;;;;;;49298:11;27:10:-1;;23:18;;;45:23;;49298:28:0;;;;;;;;;-1:-1:-1;;;;;;49298:28:0;;;;;49344:23;;;;;;;;;;;;;;;;;-1:-1:-1;49385:4:0;49113:284;:::o;41099:46::-;;;-1:-1:-1;;;;;41099:46:0;;:::o;39546:51::-;;;;;;;;:::o;37159:79::-;37197:7;37224:6;-1:-1:-1;;;;;37224:6:0;37159:79;:::o;37525:94::-;37565:4;37605:6;;-1:-1:-1;;;;;37605:6:0;37589:12;:10;:12::i;:::-;-1:-1:-1;;;;;37589:22:0;;37582:29;;37525:94;:::o;52853:102::-;52940:6;;52921:15;:25;;52853:102;:::o;41251:20::-;;;;;;;;;;;;;;;-1:-1:-1;;41251:20:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50201:418;50326:7;45498:12;:10;:12::i;:::-;45497:13;45489:50;;;;;-1:-1:-1;;;45489:50:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;45489:50:0;;;;;;;;;;;;;;;50365:10;;50359:17;;-1:-1:-1;;;50365:10:0;;-1:-1:-1;;;;;50365:10:0;50359:5;:17::i;:::-;50351:70;;;;-1:-1:-1;;;50351:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50440:20;50449:10;50440:8;:20::i;:::-;50432:53;;;;;-1:-1:-1;;;50432:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;50432:53:0;;;;;;;;;;;;;;;50503;;;-1:-1:-1;;;;;50503:53:0;;;;50534:9;50503:53;;;;50545:10;50503:53;;;;;;;;;;;;;;;50574:37;50589:10;50601:9;50574:14;:37::i;39640:44::-;;;;;;;;:::o;14186:261::-;14271:4;14288:129;14297:12;:10;:12::i;:::-;14311:7;14320:96;14359:15;14320:96;;;;;;;;;;;;;;;;;:11;:25;14332:12;:10;:12::i;:::-;-1:-1:-1;;;;;14320:25:0;;;;;;;;;;;;;;;;;-1:-1:-1;14320:25:0;;;:34;;;;;;;;;;;:96;;:38;:96;:::i;11634:158::-;11703:4;11720:42;11730:12;:10;:12::i;:::-;11744:9;11755:6;11720:9;:42::i;41029:20::-;;;-1:-1:-1;;;;;41029:20:0;;:::o;40786:32::-;;;-1:-1:-1;;;40786:32:0;;;;;:::o;40705:::-;;;;;;:::o;40280:::-;;;;;;;;:::o;59577:800::-;59633:12;:10;:12::i;:::-;59625:62;;;;-1:-1:-1;;;59625:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;59706:20;59715:10;59706:8;:20::i;:::-;59698:53;;;;;-1:-1:-1;;;59698:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;59698:53:0;;;;;;;;;;;;;;;59831:10;59802:19;59824:18;;;:6;:18;;;;;59927:16;;59985;;;;;60014:20;;;-1:-1:-1;60045:19:0;;:23;;;60079:20;;;59824:18;;59927:16;;59985;60112:52;;59927:16;60112:18;:52::i;:::-;60175;60194:10;60206:20;60175:18;:52::i;:::-;60245:124;;;;;;;;;;;;60348:10;60245:124;;;;;;;;;;;;;;;59577:800;;;:::o;47942:361::-;37371:9;:7;:9::i;:::-;37363:54;;;;;-1:-1:-1;;;37363:54:0;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;37363:54:0;;;;;;;;;;;;;;;48057:12;;;;:4;;:12;;;;;:::i;:::-;-1:-1:-1;48080:16:0;;;;:6;;:16;;;;;:::i;:::-;-1:-1:-1;48129:27:0;;48107:8;:50;;-1:-1:-1;;48107:50:0;48129:27;;;;;;48124:32;48107:50;;;;;;;;48168:127;;79282:202;79402:28;79419:10;79402:16;:28::i;:::-;;79441:35;79454:11;79467:8;79441:12;:35::i;40072:56::-;;;;;;;;:::o;61981:1984::-;45498:12;:10;:12::i;:::-;45497:13;45489:50;;;;;-1:-1:-1;;;45489:50:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;45489:50:0;;;;;;;;;;;;;;;62116:20;62125:10;62116:8;:20::i;:::-;62108:53;;;;;-1:-1:-1;;;62108:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;62108:53:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;62196:18:0;;62174:19;62196:18;;;:6;:18;;;;;62278:20;62203:10;62278:8;:20::i;:::-;62270:46;;;;;-1:-1:-1;;;62270:46:0;;;;;;;;;;;;-1:-1:-1;;;62270:46:0;;;;;;;;;;;;;;;62382:10;-1:-1:-1;;;;;62382:24:0;;;;62374:69;;;;;-1:-1:-1;;;62374:69:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62456:21;62480:95;62519:18;62552:12;;;;;;;;62559:1;62552:12;;;;62562:1;62552:12;;;;;62480:24;:95::i;:::-;62609:103;;;;;;;;;62681:20;62609:103;;;;;;;;;;;;;;;;;62456:119;;-1:-1:-1;62586:20:0;;62609:103;;62648:18;;62609:24;:103::i;:::-;62586:126;-1:-1:-1;62723:26:0;62752:31;:13;62586:126;62752:31;:17;:31;:::i;:::-;62945:17;:23;62910:16;;62723:60;;-1:-1:-1;62874:33:0;;62910:69;;;:20;:69;:::i;:::-;62996:26;;62874:105;;-1:-1:-1;63025:1:0;62996:26;;;;:30;;;;62992:361;;;63131:26;;63071:102;;:25;;63131:26;;;;63123:35;;63119:2;:39;63071:102;:29;:102;:::i;:::-;63043:130;;62992:361;;;63299:26;;63234:107;;:25;;63299:26;;;;;63294:31;63286:40;;63282:2;:44;63234:107;:29;:107;:::i;:::-;63206:135;;62992:361;63409:25;63387:18;:47;;63365:152;;;;-1:-1:-1;;;63365:152:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63601:16;;:40;;63622:18;63601:40;:20;:40;:::i;:::-;63582:59;;63674:19;;;;:43;;63698:18;63674:43;:23;:43;:::i;:::-;63652:19;;;:65;63788:37;63794:10;63806:18;63788:5;:37::i;:::-;63836:50;63855:10;63867:18;63836;:50::i;:::-;63904:53;;;;;;-1:-1:-1;;;;;63904:53:0;;;;;;63946:10;63904:53;;;;;;;;;;;;;;;45550:1;;;;;61981:1984;;:::o;40189:25::-;;;;;;;;:::o;82717:478::-;82885:11;:9;:11::i;:::-;;82907:67;82932:11;82945:13;82968:4;82907:24;:67::i;64153:241::-;64220:4;64237:16;64257:100;64278:25;64292:10;64278:13;:25::i;:::-;64318:28;64335:10;64318:16;:28::i;:::-;64257:6;:100::i;:::-;64256:101;;64153:241;-1:-1:-1;;;64153:241:0:o;80397:437::-;80534:28;80551:10;80534:16;:28::i;:::-;;80573:40;80586:11;80607:4;80573:12;:40::i;40856:24::-;;;-1:-1:-1;;;40856:24:0;;-1:-1:-1;;;;;40856:24:0;;:::o;11855:134::-;-1:-1:-1;;;;;11954:18:0;;;11927:7;11954:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;11855:134::o;60574:790::-;60682:7;60711:20;60720:10;60711:8;:20::i;:::-;60707:650;;;-1:-1:-1;;;;;60770:18:0;;60748:19;60770:18;;;:6;:18;;;;;60956:26;;:17;60896:23;60839:34;;60770:18;;60748:19;60839:145;;60956:26;;;;60955:27;;60947:36;;60943:2;:40;;60839:81;;:34;:81;:56;:81;:::i;:::-;:103;:145;:103;:145;:::i;:::-;61028:29;;60803:181;;-1:-1:-1;61028:29:0;;;;61001:11;61027:30;61019:39;;61015:2;:43;61073:26;;:::i;:::-;61102:123;;;;;;;;;61127:20;:26;61102:123;;61127:35;;61158:3;61127:35;:30;:35;:::i;:::-;61102:123;;61181:29;;;;;;61102:123;;;;;;;61073:152;-1:-1:-1;61247:57:0;61264:25;61073:152;61247:16;:57::i;:::-;61240:64;;;;;;;;60707:650;-1:-1:-1;61344:1:0;61337:8;;40635:21;;;;:::o;48484:219::-;37371:9;:7;:9::i;:::-;37363:54;;;;;-1:-1:-1;;;37363:54:0;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;37363:54:0;;;;;;;;;;;;;;;48574:8;;;48559:12;48593;;;48616:34;48635:8;48574;48616:18;:34::i;:::-;48668:27;;;-1:-1:-1;;;;;48668:27:0;;;;;;;;;;;;;;;;;;;;;;;37428:1;48484:219;:::o;57839:343::-;45498:12;:10;:12::i;:::-;45497:13;45489:50;;;;;-1:-1:-1;;;45489:50:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;45489:50:0;;;;;;;;;;;;;;;57916:20;57925:10;57916:8;:20::i;:::-;57908:53;;;;;-1:-1:-1;;;57908:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;57908:53:0;;;;;;;;;;;;;;;58003:10;57974:19;57996:18;;;:6;:18;;;;;58049:19;;;;:34;;58073:9;58049:34;:23;:34;:::i;:::-;58027:19;;;:56;58094:28;58100:10;58112:9;58094:5;:28::i;:::-;58140:34;;;58152:10;58140:34;;;;;;;;;;;;;;;;;;;;;45550:1;57839:343;:::o;78580:200::-;78705:11;:9;:11::i;:::-;;78727:45;78750:11;78763:8;78727:22;:45::i;46591:1126::-;37371:9;:7;:9::i;:::-;37363:54;;;;;-1:-1:-1;;;37363:54:0;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;37363:54:0;;;;;;;;;;;;;;;46855:3;46830:21;:28;;46808:115;;;;-1:-1:-1;;;46808:115:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46978:4;46956:18;:26;;46934:119;;;;-1:-1:-1;;;46934:119:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47091:3;47072:15;:22;;47064:67;;;;;-1:-1:-1;;;47064:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47194:2;47164:26;:32;;47142:122;;;;-1:-1:-1;;;47142:122:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47277:20;:50;;;47338:17;:44;;;47393:14;:38;;;47442:25;:60;;;47520:189;47306:21;47364:18;47416:15;47476:26;47691:7;:5;:7::i;:::-;47520:189;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;47520:189:0;;;;;;;;;;;;;;46591:1126;;;;:::o;38265:109::-;37371:9;:7;:9::i;:::-;37363:54;;;;;-1:-1:-1;;;37363:54:0;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;37363:54:0;;;;;;;;;;;;;;;38338:28;38357:8;38338:18;:28::i;:::-;38265:109;:::o;57439:104::-;-1:-1:-1;;;;;57515:20:0;;;57439:104::o;54838:449::-;54892:20;54901:10;54892:8;:20::i;:::-;54884:53;;;;;-1:-1:-1;;;54884:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;54884:53:0;;;;;;;;;;;;;;;54977:10;54948:19;54970:18;;;:6;:18;;;;;55009:16;;;;55001:54;;;;;-1:-1:-1;;;55001:54:0;;;;;;;;;;;;-1:-1:-1;;;55001:54:0;;;;;;;;;;;;;;;55099:16;;;;;55068:28;55126:20;;;55159:52;55178:10;55099:16;55159:18;:52::i;:::-;55227:50;;;;;;55266:10;55227:50;;;;;;;;;;;;;;;;;54838:449;;:::o;69334:285::-;69455:7;45498:12;:10;:12::i;:::-;45497:13;45489:50;;;;;-1:-1:-1;;;45489:50:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;45489:50:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;69502:18:0;;69480:19;69502:18;;;:6;:18;;;;;69550:16;;:25;;69571:3;69550:25;:20;:25;:::i;:::-;69531:44;;;;;69334:285;-1:-1:-1;;;69334:285:0:o;858:98::-;938:10;858:98;:::o;17118:338::-;-1:-1:-1;;;;;17212:19:0;;17204:68;;;;-1:-1:-1;;;17204:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;17291:21:0;;17283:68;;;;-1:-1:-1;;;17283:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;17364:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;17416:32;;;;;;;;;;;;;;;;;17118:338;;;:::o;5445:136::-;5503:7;5530:43;5534:1;5537;5530:43;;;;;;;;;;;;;;;;;:3;:43::i;4989:181::-;5047:7;5079:5;;;5103:6;;;;5095:46;;;;;-1:-1:-1;;;5095:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;69945:1227;70057:4;70113:28;70144:29;70161:10;;;;;;;;;-1:-1:-1;;;;;70161:10:0;70144:8;:29::i;:::-;70228:6;;70113:60;;-1:-1:-1;70184:24:0;;70211:25;;-1:-1:-1;;;;;70228:6:0;70211:8;:25::i;:::-;70467:11;:17;70416:25;:31;70184:52;;-1:-1:-1;70362:19:0;;70384:101;;70467:17;70384:64;;:13;;:64;:31;:64;:::i;:::-;:82;:101;:82;:101;:::i;:::-;70566:20;;70516:34;;70362:123;;-1:-1:-1;70566:20:0;70516:34;;;70566:20;;70516:70;70496:17;70622:87;70682:16;70623:39;:13;70641:20;70623:39;:17;:39;:::i;70622:87::-;70741:13;;70599:110;;-1:-1:-1;70741:13:0;;;;;70720:18;;;;70832:26;;;;;;;;70828:308;;;70889:26;;;70881:35;;;-1:-1:-1;70971:12:0;70943:24;:11;70959:2;:7;;;70943:24;:15;:24;:::i;:::-;:40;;70931:52;;70828:308;;;71030:26;;;71022:35;;;-1:-1:-1;71099:25:0;:12;71116:2;:7;;;71099:25;:16;:25;:::i;:::-;71084:11;:40;;71072:52;;70828:308;71155:9;69945:1227;-1:-1:-1;;;;;;;;;;69945:1227:0:o;15689:308::-;-1:-1:-1;;;;;15765:21:0;;15757:65;;;;;-1:-1:-1;;;15757:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;15850:12;;:24;;15867:6;15850:24;:16;:24;:::i;:::-;15835:12;:39;-1:-1:-1;;;;;15906:18:0;;;;;;:9;:18;;;;;;:30;;15929:6;15906:30;:22;:30;:::i;:::-;-1:-1:-1;;;;;15885:18:0;;;;;;:9;:18;;;;;;;;:51;;;;15952:37;;;;;;;15885:18;;;;15952:37;;;;;;;;;;15689:308;;:::o;14937:471::-;-1:-1:-1;;;;;15035:20:0;;15027:70;;;;-1:-1:-1;;;15027:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;15116:23:0;;15108:71;;;;-1:-1:-1;;;15108:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15212;15234:6;15212:71;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;15212:17:0;;;;;;:9;:17;;;;;;;:71;;:21;:71;:::i;:::-;-1:-1:-1;;;;;15192:17:0;;;;;;;:9;:17;;;;;;:91;;;;15317:20;;;;;;;:32;;15342:6;15317:32;:24;:32;:::i;:::-;-1:-1:-1;;;;;15294:20:0;;;;;;;:9;:20;;;;;;;;;:55;;;;15365:35;;;;;;;15294:20;;15365:35;;;;;;;;;;;;;14937:471;;;:::o;5918:192::-;6004:7;6040:12;6032:6;;;;6024:29;;;;-1:-1:-1;;;6024:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;6024:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;6076:5:0;;;5918:192::o;64728:208::-;-1:-1:-1;;;;;64876:18:0;64829:7;64876:18;;;:6;:18;;;;;64912:16;;64728:208::o;75218:227::-;75313:10;;75307:17;;-1:-1:-1;;;75313:10:0;;-1:-1:-1;;;;;75313:10:0;75307:5;:17::i;:::-;75303:135;;;75341:20;;-1:-1:-1;;;;;75341:14:0;;;:20;;;;;75356:4;;75341:20;;;;75356:4;75341:14;:20;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;75341:20:0;75303:135;;;75394:10;;:32;;;-1:-1:-1;;;75394:32:0;;-1:-1:-1;;;;;75394:32:0;;;;;;;;;;;;;;;-1:-1:-1;;;75394:10:0;;;;;;;:19;;:32;;;;;;;;;;;;;;;-1:-1:-1;75394:10:0;:32;;;5:2:-1;;;;30:1;27;20:12;5:2;75394:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;75394:32:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;75218:227:0;;:::o;66218:2894::-;66414:18;:16;:18::i;:::-;66392:113;;;;-1:-1:-1;;;66392:113:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66526:29;66535:19;66526:8;:29::i;:::-;66518:62;;;;;-1:-1:-1;;;66518:62:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;66518:62:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;66615:27:0;;66593:19;66615:27;;;:6;:27;;;;;66661:21;66653:58;;;;;-1:-1:-1;;;66653:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;66820:5;:19;;;66799:17;:40;;66777:136;;;;-1:-1:-1;;;66777:136:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67024:17;66999:21;67009:10;66999:9;:21::i;:::-;:42;;66977:110;;;;;-1:-1:-1;;;66977:110:0;;;;;;;;;;;;-1:-1:-1;;;66977:110:0;;;;;;;;;;;;;;;67186:26;67215:71;67258:17;67215:28;:71::i;:::-;67316:16;;;;67186:100;;-1:-1:-1;67316:40:0;;67186:100;67316:40;:20;:40;:::i;:::-;67297:16;;;:59;67605:12;;;;;;;;;67612:1;67605:12;;67505:26;67605:12;;;;;;67505:26;67534:94;;67573:17;;67534:24;:94::i;:::-;67709:96;;;;;;;;;67780:14;67709:96;;;;;;;;;;;;;;;;;67505:123;;-1:-1:-1;67692:14:0;;67709:96;;67748:17;;67709:24;:96::i;:::-;67827:8;;67692:113;;-1:-1:-1;67827:20:0;;67692:113;67827:20;:12;:20;:::i;:::-;67816:8;:31;67860:28;67891:30;:18;67914:6;67891:30;:22;:30;:::i;:::-;67978:16;;67860:61;;-1:-1:-1;67954:40:0;;;67932:122;;;;;-1:-1:-1;;;67932:122:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68137:16;;:42;;68158:20;68137:42;:20;:42;:::i;:::-;68118:61;;68212:19;;;;:42;;68236:17;68212:42;:23;:42;:::i;:::-;68190:19;;;:64;68389:10;;68383:17;;-1:-1:-1;;;;;68389:10:0;68383:5;:17::i;:::-;68379:388;;;68438:18;68425:9;:31;68417:63;;;;;-1:-1:-1;;;68417:63:0;;;;;;;;;;;;-1:-1:-1;;;68417:63:0;;;;;;;;;;;;;;;68379:388;;;68539:10;;:152;;;-1:-1:-1;;;68539:152:0;;68585:10;68539:152;;;;68626:4;68539:152;;;;;;;;;;;;-1:-1:-1;;;;;68539:10:0;;;;:23;;:152;;;;;;;;;;;;;;;:10;;:152;;;5:2:-1;;;;30:1;27;20:12;5:2;68539:152:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;68539:152:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;68539:152:0;68513:242;;;;;-1:-1:-1;;;68513:242:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;68806:36;68812:10;68824:17;68806:5;:36::i;:::-;68890:50;68909:10;68921:18;68890;:50::i;:::-;68958:144;;;;;;;;;;;;69047:10;68958:144;;;;-1:-1:-1;;;;;68958:144:0;;;;;;;;;;;;;;;;;66218:2894;;;;;;;:::o;72158:1119::-;72283:7;72342:28;72373:29;72390:10;;;;;;;;;-1:-1:-1;;;;;72390:10:0;72373:8;:29::i;:::-;72457:6;;72342:60;;-1:-1:-1;72413:24:0;;72440:25;;-1:-1:-1;;;;;72457:6:0;72440:8;:25::i;:::-;72611:11;:17;72590:16;;72413:52;;-1:-1:-1;72571:16:0;;72590:39;;;:20;:39;:::i;:::-;72679:20;;72657:19;;;;72571:58;;-1:-1:-1;72679:20:0;;72657:42;72640:14;72735:87;72795:16;72736:39;:13;72754:20;72736:39;:17;:39;:::i;72735:87::-;72854:13;;72712:110;;-1:-1:-1;72854:13:0;;;;;72833:18;;;;72945:23;;;;;;;;72941:299;;;72999:23;;;72991:32;;;-1:-1:-1;73051:39:0;73068:21;:8;73081:2;:7;;;73068:21;:12;:21;:::i;:::-;73051:12;;:39;:16;:39;:::i;:::-;73038:52;;72941:299;;;73137:23;;;73129:32;;;-1:-1:-1;73189:39:0;73219:8;73189:25;:12;73206:2;:7;;;73189:25;:16;:25;:::i;:39::-;73176:52;72158:1119;-1:-1:-1;;;;;;;;;;;72158:1119:0:o;6361:471::-;6419:7;6664:6;6660:47;;-1:-1:-1;6694:1:0;6687:8;;6660:47;6731:5;;;6735:1;6731;:5;:1;6755:5;;;;;:10;6747:56;;;;-1:-1:-1;;;6747:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;75659:227;75754:10;;75748:17;;-1:-1:-1;;;;;75754:10:0;75748:5;:17::i;:::-;75744:135;;;75782:20;;-1:-1:-1;;;;;75782:14:0;;;:20;;;;;75797:4;;75782:20;;;;75797:4;75782:14;:20;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;75744:135:0;75835:10;;:32;;;-1:-1:-1;;;75835:32:0;;-1:-1:-1;;;;;75835:32:0;;;;;;;;;;;;;;;:10;;;;;:19;;:32;;;;;;;;;;;;;;:10;;:32;;;5:2:-1;;;;30:1;27;20:12;73812:1192:0;73938:7;73992:28;74023:29;74040:10;;;;;;;;;-1:-1:-1;;;;;74040:10:0;74023:8;:29::i;:::-;74107:6;;73992:60;;-1:-1:-1;74063:24:0;;74090:25;;-1:-1:-1;;;;;74107:6:0;74090:8;:25::i;:::-;74063:52;;74178:34;74215:117;74315:16;74215:81;74279:10;:16;;;74215:45;74242:11;:17;;;74215:8;:26;;:45;;;;:::i;:117::-;74444:13;;74409:19;;;;74373:20;;74178:154;;-1:-1:-1;74444:13:0;;;;74373:20;;;:55;:84;;;;;74343:27;;74513:25;;;;-1:-1:-1;74509:448:0;;;74575:21;74633:97;74695:20;74633:39;:26;74664:7;;;;:2;:7;74633:39;;;:30;:39;:::i;:97::-;74612:118;;74509:448;;;;74763:10;74783:26;;;74846:99;74910:20;74847:39;:26;74878:7;;;;:2;:7;74847:39;;;:30;:39;:::i;74846:99::-;74825:120;;74509:448;;74976:18;73812:1192;-1:-1:-1;;;;;;;73812:1192:0:o;7300:132::-;7358:7;7385:39;7389:1;7392;7385:39;;;;;;;;;;;;;;;;;:3;:39::i;16330:348::-;-1:-1:-1;;;;;16406:21:0;;16398:67;;;;-1:-1:-1;;;16398:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;16499:68;16522:6;16499:68;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;16499:18:0;;;;;;:9;:18;;;;;;;:68;;:22;:68;:::i;:::-;-1:-1:-1;;;;;16478:18:0;;;;;;:9;:18;;;;;:89;16593:12;;:24;;16610:6;16593:24;:16;:24;:::i;:::-;16578:12;:39;16633:37;;;;;;;;16659:1;;-1:-1:-1;;;;;16633:37:0;;;;;;;;;;;;16330:348;;:::o;65053:214::-;-1:-1:-1;;;;;65204:18:0;65157:7;65204:18;;;:6;:18;;;;;65240:19;;;;65053:214::o;38480:229::-;-1:-1:-1;;;;;38554:22:0;;38546:73;;;;-1:-1:-1;;;38546:73:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38656:6;;;38635:38;;-1:-1:-1;;;;;38635:38:0;;;;38656:6;;;38635:38;;;38684:6;:17;;-1:-1:-1;;;;;;38684:17:0;-1:-1:-1;;;;;38684:17:0;;;;;;;;;;38480:229::o;76049:221::-;76105:7;-1:-1:-1;;;;;76129:19:0;;76125:138;;-1:-1:-1;76173:6:0;76165:15;;76125:138;76220:15;;:31;;;-1:-1:-1;;;76220:31:0;;-1:-1:-1;;;;;76220:31:0;;;;;;;;;:15;;;;;:24;;:31;;;;;;;;;;;;;;:15;:31;;;5:2:-1;;;;30:1;27;20:12;5:2;76220:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;76220:31:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;76220:31:0;;-1:-1:-1;76213:38:0;;7962:345;8048:7;8150:12;8143:5;8135:28;;;;-1:-1:-1;;;8135:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;8135:28:0;;8174:9;8190:1;8186;:5;;;;;;;7962:345;-1:-1:-1;;;;;7962:345:0:o;76403:7558::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;76403:7558:0;;;-1:-1:-1;76403:7558:0;:::i;:::-;;;:::o;:::-;;;;;;;;;;-1:-1:-1;76403:7558:0;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;

Swarm Source

bzzr://78d274c261df68e9d5018737bd71b890ed72cabfe0e584eb1d201ad752666c95
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.