ETH Price: $3,416.56 (+3.15%)

Token

Vision Token (VISION)
 

Overview

Max Total Supply

1,777,112.0042730103448889 VISION

Holders

1,320 ( -0.076%)

Market

Price

$0.19 @ 0.000056 ETH

Onchain Market Cap

$342,934.36

Circulating Supply Market Cap

$0.00

Other Info

Token Contract (WITH 18 Decimals)

Balance
100.000000000000002097 VISION

Value
$19.30 ( ~0.00564894982220507 Eth) [0.0056%]
0x7740d3c5de14e7aeE58462690BBbcB9366c2C924
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

APY.vision is an all-in-one dashboard to manage your DeFi Liquidity Pools and track your profit and losses in real-time. The APY.vision membership token is used to unlock Professional features.

Market

Volume (24H):$0.00
Market Capitalization:$0.00
Circulating Supply:0.00 VISION
Market Data Source: Coinmarketcap

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
VisionToken

Compiler Version
v0.5.17+commit.d19bba13

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

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

pragma solidity 0.5.17;


/**
 * Source: https://raw.githubusercontent.com/simple-restricted-token/reference-implementation/master/contracts/token/ERC1404/ERC1404.sol
 * With ERC-20 APIs removed (will be implemented as a separate contract).
 * And adding authorizeTransfer.
 */
interface IWhitelist {
  /**
   * @notice Detects if a transfer will be reverted and if so returns an appropriate reference code
   * @param from Sending address
   * @param to Receiving address
   * @param value Amount of tokens being transferred
   * @return Code by which to reference message for rejection reasoning
   * @dev Overwrite with your custom transfer restriction logic
   */
  function detectTransferRestriction(
    address from,
    address to,
    uint value
  ) external view returns (uint8);

  /**
   * @notice Returns a human-readable message for a given restriction code
   * @param restrictionCode Identifier for looking up a message
   * @return Text showing the restriction's reasoning
   * @dev Overwrite with your custom message and restrictionCode handling
   */
  function messageForTransferRestriction(uint8 restrictionCode)
    external
    pure
    returns (string memory);

  /**
   * @notice Called by the DAT contract before a transfer occurs.
   * @dev This call will revert when the transfer is not authorized.
   * This is a mutable call to allow additional data to be recorded,
   * such as when the user aquired their tokens.
   */
  function authorizeTransfer(
    address _from,
    address _to,
    uint _value,
    bool _isSell
  ) external;

  function activateWallet(
    address _wallet
  ) external;

  function deactivateWallet(
    address _wallet
  ) external;

  function walletActivated(
    address _wallet
  ) external returns(bool);
}

interface IERC20Detailed {
  /**
   * @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() external view returns (uint8);

  function name() external view returns (string memory);

  function symbol() external view returns (string memory);

}

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

/**
 * @title Reduces the size of terms before multiplication, to avoid an overflow, and then
 * restores the proper size after division.
 * @notice This effectively allows us to overflow values in the numerator and/or denominator
 * of a fraction, so long as the end result does not overflow as well.
 * @dev Results may be off by 1 + 0.000001% for 2x1 calls and 2 + 0.00001% for 2x2 calls.
 * Do not use if your contract expects very small result values to be accurate.
 */
library BigDiv {
  using SafeMath for uint;

  /// @notice The max possible value
  uint private constant MAX_UINT = 2**256 - 1;

  /// @notice When multiplying 2 terms <= this value the result won't overflow
  uint private constant MAX_BEFORE_SQUARE = 2**128 - 1;

  /// @notice The max error target is off by 1 plus up to 0.000001% error
  /// for bigDiv2x1 and that `* 2` for bigDiv2x2
  uint private constant MAX_ERROR = 100000000;

  /// @notice A larger error threshold to use when multiple rounding errors may apply
  uint private constant MAX_ERROR_BEFORE_DIV = MAX_ERROR * 2;

  /**
   * @notice Returns the approx result of `a * b / d` so long as the result is <= MAX_UINT
   * @param _numA the first numerator term
   * @param _numB the second numerator term
   * @param _den the denominator
   * @return the approx result with up to off by 1 + MAX_ERROR, rounding down if needed
   */
  function bigDiv2x1(
    uint _numA,
    uint _numB,
    uint _den
  ) internal pure returns (uint) {
    if (_numA == 0 || _numB == 0) {
      // would div by 0 or underflow if we don't special case 0
      return 0;
    }

    uint value;

    if (MAX_UINT / _numA >= _numB) {
      // a*b does not overflow, return exact math
      value = _numA * _numB;
      value /= _den;
      return value;
    }

    // Sort numerators
    uint numMax = _numB;
    uint numMin = _numA;
    if (_numA > _numB) {
      numMax = _numA;
      numMin = _numB;
    }

    value = numMax / _den;
    if (value > MAX_ERROR) {
      // _den is small enough to be MAX_ERROR or better w/o a factor
      value = value.mul(numMin);
      return value;
    }

    // formula = ((a / f) * b) / (d / f)
    // factor >= a / sqrt(MAX) * (b / sqrt(MAX))
    uint factor = numMin - 1;
    factor /= MAX_BEFORE_SQUARE;
    factor += 1;
    uint temp = numMax - 1;
    temp /= MAX_BEFORE_SQUARE;
    temp += 1;
    if (MAX_UINT / factor >= temp) {
      factor *= temp;
      value = numMax / factor;
      if (value > MAX_ERROR_BEFORE_DIV) {
        value = value.mul(numMin);
        temp = _den - 1;
        temp /= factor;
        temp = temp.add(1);
        value /= temp;
        return value;
      }
    }

    // formula: (a / (d / f)) * (b / f)
    // factor: b / sqrt(MAX)
    factor = numMin - 1;
    factor /= MAX_BEFORE_SQUARE;
    factor += 1;
    value = numMin / factor;
    temp = _den - 1;
    temp /= factor;
    temp += 1;
    temp = numMax / temp;
    value = value.mul(temp);
    return value;
  }

  /**
   * @notice Returns the approx result of `a * b / d` so long as the result is <= MAX_UINT
   * @param _numA the first numerator term
   * @param _numB the second numerator term
   * @param _den the denominator
   * @return the approx result with up to off by 1 + MAX_ERROR, rounding down if needed
   * @dev roundUp is implemented by first rounding down and then adding the max error to the result
   */
  function bigDiv2x1RoundUp(
    uint _numA,
    uint _numB,
    uint _den
  ) internal pure returns (uint) {
    // first get the rounded down result
    uint value = bigDiv2x1(_numA, _numB, _den);

    if (value == 0) {
      // when the value rounds down to 0, assume up to an off by 1 error
      return 1;
    }

    // round down has a max error of MAX_ERROR, add that to the result
    // for a round up error of <= MAX_ERROR
    uint temp = value - 1;
    temp /= MAX_ERROR;
    temp += 1;
    if (MAX_UINT - value < temp) {
      // value + error would overflow, return MAX
      return MAX_UINT;
    }

    value += temp;

    return value;
  }

  /**
   * @notice Returns the approx result of `a * b / (c * d)` so long as the result is <= MAX_UINT
   * @param _numA the first numerator term
   * @param _numB the second numerator term
   * @param _denA the first denominator term
   * @param _denB the second denominator term
   * @return the approx result with up to off by 2 + MAX_ERROR*10 error, rounding down if needed
   * @dev this uses bigDiv2x1 and adds additional rounding error so the max error of this
   * formula is larger
   */
  function bigDiv2x2(
    uint _numA,
    uint _numB,
    uint _denA,
    uint _denB
  ) internal pure returns (uint) {
    if (MAX_UINT / _denA >= _denB) {
      // denA*denB does not overflow, use bigDiv2x1 instead
      return bigDiv2x1(_numA, _numB, _denA * _denB);
    }

    if (_numA == 0 || _numB == 0) {
      // would div by 0 or underflow if we don't special case 0
      return 0;
    }

    // Sort denominators
    uint denMax = _denB;
    uint denMin = _denA;
    if (_denA > _denB) {
      denMax = _denA;
      denMin = _denB;
    }

    uint value;

    if (MAX_UINT / _numA >= _numB) {
      // a*b does not overflow, use `a / d / c`
      value = _numA * _numB;
      value /= denMin;
      value /= denMax;
      return value;
    }

    // `ab / cd` where both `ab` and `cd` would overflow

    // Sort numerators
    uint numMax = _numB;
    uint numMin = _numA;
    if (_numA > _numB) {
      numMax = _numA;
      numMin = _numB;
    }

    // formula = (a/d) * b / c
    uint temp = numMax / denMin;
    if (temp > MAX_ERROR_BEFORE_DIV) {
      return bigDiv2x1(temp, numMin, denMax);
    }

    // formula: ((a/f) * b) / d then either * f / c or / c * f
    // factor >= a / sqrt(MAX) * (b / sqrt(MAX))
    uint factor = numMin - 1;
    factor /= MAX_BEFORE_SQUARE;
    factor += 1;
    temp = numMax - 1;
    temp /= MAX_BEFORE_SQUARE;
    temp += 1;
    if (MAX_UINT / factor >= temp) {
      factor *= temp;

      value = numMax / factor;
      if (value > MAX_ERROR_BEFORE_DIV) {
        value = value.mul(numMin);
        value /= denMin;
        if (value > 0 && MAX_UINT / value >= factor) {
          value *= factor;
          value /= denMax;
          return value;
        }
      }
    }

    // formula: (a/f) * b / ((c*d)/f)
    // factor >= c / sqrt(MAX) * (d / sqrt(MAX))
    factor = denMin;
    factor /= MAX_BEFORE_SQUARE;
    temp = denMax;
    // + 1 here prevents overflow of factor*temp
    temp /= MAX_BEFORE_SQUARE + 1;
    factor *= temp;
    return bigDiv2x1(numMax / factor, numMin, MAX_UINT);
  }
}

/**
 * @title Calculates the square root of a given value.
 * @dev Results may be off by 1.
 */
library Sqrt {
  /// @notice The max possible value
  uint private constant MAX_UINT = 2**256 - 1;

  // Source: https://github.com/ethereum/dapp-bin/pull/50
  function sqrt(uint x) internal pure returns (uint y) {
    if (x == 0) {
      return 0;
    } else if (x <= 3) {
      return 1;
    } else if (x == MAX_UINT) {
      // Without this we fail on x + 1 below
      return 2**128 - 1;
    }

    uint z = (x + 1) / 2;
    y = x;
    while (z < y) {
      y = z;
      z = (x / z + z) / 2;
    }
  }
}

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

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following 
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * _Available since v2.4.0._
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     *
     * _Available since v2.4.0._
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-call-value
        (bool success, ) = recipient.call.value(amount)("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

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

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

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

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

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

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

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

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

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

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

/**
 * @title Initializable
 *
 * @dev Helper contract to support initializer functions. To use it, replace
 * the constructor with a function that has the `initializer` modifier.
 * WARNING: Unlike constructors, initializer functions must be manually
 * invoked. This applies both to deploying an Initializable contract, as well
 * as extending an Initializable contract via inheritance.
 * WARNING: When used with inheritance, manual care must be taken to not invoke
 * a parent initializer twice, or ensure that all initializers are idempotent,
 * because this is not dealt with automatically as with constructors.
 */
contract Initializable {

  /**
   * @dev Indicates that the contract has been initialized.
   */
  bool private initialized;

  /**
   * @dev Indicates that the contract is in the process of being initialized.
   */
  bool private initializing;

  /**
   * @dev Modifier to use in the initializer function of a contract.
   */
  modifier initializer() {
    require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");

    bool isTopLevelCall = !initializing;
    if (isTopLevelCall) {
      initializing = true;
      initialized = true;
    }

    _;

    if (isTopLevelCall) {
      initializing = false;
    }
  }

  /// @dev Returns true if and only if the function is running in the constructor
  function isConstructor() private view returns (bool) {
    // extcodesize checks the size of the code stored in an address, and
    // address returns the current address. Since the code is still not
    // deployed when running a constructor, any checks on its code size will
    // yield zero, making it an effective way to detect if a contract is
    // under construction or not.
    address self = address(this);
    uint256 cs;
    assembly { cs := extcodesize(self) }
    return cs == 0;
  }

  // Reserved storage space to allow for layout changes in the future.
  uint256[50] private ______gap;
}

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

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

    uint256[50] private ______gap;
}

/**
 * @title Roles
 * @dev Library for managing addresses assigned to a Role.
 */
library Roles {
    struct Role {
        mapping (address => bool) bearer;
    }

    /**
     * @dev Give an account access to this role.
     */
    function add(Role storage role, address account) internal {
        require(!has(role, account), "Roles: account already has role");
        role.bearer[account] = true;
    }

    /**
     * @dev Remove an account's access to this role.
     */
    function remove(Role storage role, address account) internal {
        require(has(role, account), "Roles: account does not have role");
        role.bearer[account] = false;
    }

    /**
     * @dev Check if an account has this role.
     * @return bool
     */
    function has(Role storage role, address account) internal view returns (bool) {
        require(account != address(0), "Roles: account is the zero address");
        return role.bearer[account];
    }
}

contract MinterRole is Initializable, Context {
    using Roles for Roles.Role;

    event MinterAdded(address indexed account);
    event MinterRemoved(address indexed account);

    Roles.Role private _minters;

    function initialize(address sender) public initializer {
        if (!isMinter(sender)) {
            _addMinter(sender);
        }
    }

    modifier onlyMinter() {
        require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
        _;
    }

    function isMinter(address account) public view returns (bool) {
        return _minters.has(account);
    }

    function addMinter(address account) public onlyMinter {
        _addMinter(account);
    }

    function renounceMinter() public {
        _removeMinter(_msgSender());
    }

    function _addMinter(address account) internal {
        _minters.add(account);
        emit MinterAdded(account);
    }

    function _removeMinter(address account) internal {
        _minters.remove(account);
        emit MinterRemoved(account);
    }

    uint256[50] private ______gap;
}

/**
 * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},
 * which have permission to mint (create) new tokens as they see fit.
 *
 * At construction, the deployer of the contract is the only minter.
 */
contract ERC20Mintable is Initializable, ERC20, MinterRole {
    function initialize(address sender) public initializer {
        MinterRole.initialize(sender);
    }

    /**
     * @dev See {ERC20-_mint}.
     *
     * Requirements:
     *
     * - the caller must have the {MinterRole}.
     */
    function mint(address account, uint256 amount) public onlyMinter returns (bool) {
        _mint(account, amount);
        return true;
    }

    uint256[50] private ______gap;
}

/**
 * @dev Extension of {ERC20Mintable} that adds a cap to the supply of tokens.
 */
contract ERC20Capped is Initializable, ERC20Mintable {
    uint256 private _cap;

    /**
     * @dev Sets the value of the `cap`. This value is immutable, it can only be
     * set once during construction.
     */
    function initialize(uint256 cap, address sender) public initializer {
        ERC20Mintable.initialize(sender);

        require(cap > 0, "ERC20Capped: cap is 0");
        _cap = cap;
    }

    /**
     * @dev Returns the cap on the token's total supply.
     */
    function cap() public view returns (uint256) {
        return _cap;
    }

    /**
     * @dev See {ERC20Mintable-mint}.
     *
     * Requirements:
     *
     * - `value` must not cause the total supply to go over the cap.
     */
    function _mint(address account, uint256 value) internal {
        require(totalSupply().add(value) <= _cap, "ERC20Capped: cap exceeded");
        super._mint(account, value);
    }

    uint256[50] private ______gap;
}

contract PauserRole is Initializable, Context {
    using Roles for Roles.Role;

    event PauserAdded(address indexed account);
    event PauserRemoved(address indexed account);

    Roles.Role private _pausers;

    function initialize(address sender) public initializer {
        if (!isPauser(sender)) {
            _addPauser(sender);
        }
    }

    modifier onlyPauser() {
        require(isPauser(_msgSender()), "PauserRole: caller does not have the Pauser role");
        _;
    }

    function isPauser(address account) public view returns (bool) {
        return _pausers.has(account);
    }

    function addPauser(address account) public onlyPauser {
        _addPauser(account);
    }

    function renouncePauser() public {
        _removePauser(_msgSender());
    }

    function _addPauser(address account) internal {
        _pausers.add(account);
        emit PauserAdded(account);
    }

    function _removePauser(address account) internal {
        _pausers.remove(account);
        emit PauserRemoved(account);
    }

    uint256[50] private ______gap;
}

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
contract Pausable is Initializable, Context, PauserRole {
    /**
     * @dev Emitted when the pause is triggered by a pauser (`account`).
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by a pauser (`account`).
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state. Assigns the Pauser role
     * to the deployer.
     */
    function initialize(address sender) public initializer {
        PauserRole.initialize(sender);

        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     */
    modifier whenNotPaused() {
        require(!_paused, "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     */
    modifier whenPaused() {
        require(_paused, "Pausable: not paused");
        _;
    }

    /**
     * @dev Called by a pauser to pause, triggers stopped state.
     */
    function pause() public onlyPauser whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Called by a pauser to unpause, returns to normal state.
     */
    function unpause() public onlyPauser whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }

    uint256[50] private ______gap;
}

/**
 * @title Pausable token
 * @dev ERC20 with pausable transfers and allowances.
 *
 * Useful if you want to stop trades until the end of a crowdsale, or have
 * an emergency switch for freezing all token transfers in the event of a large
 * bug.
 */
contract ERC20Pausable is Initializable, ERC20, Pausable {
    function initialize(address sender) public initializer {
        Pausable.initialize(sender);
    }

    function transfer(address to, uint256 value) public whenNotPaused returns (bool) {
        return super.transfer(to, value);
    }

    function transferFrom(address from, address to, uint256 value) public whenNotPaused returns (bool) {
        return super.transferFrom(from, to, value);
    }

    function approve(address spender, uint256 value) public whenNotPaused returns (bool) {
        return super.approve(spender, value);
    }

    function increaseAllowance(address spender, uint256 addedValue) public whenNotPaused returns (bool) {
        return super.increaseAllowance(spender, addedValue);
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) public whenNotPaused returns (bool) {
        return super.decreaseAllowance(spender, subtractedValue);
    }

    uint256[50] private ______gap;
}

/**
 * @title Continuous Offering abstract contract
 * @notice A shared base for various offerings from Fairmint.
 */
contract ContinuousOffering is ERC20Pausable, ERC20Capped, IERC20Detailed
{
  using SafeMath for uint;
  using Sqrt for uint;
  using SafeERC20 for IERC20;

  /**
   * Events
   */

  event Buy(
    address indexed _from,
    address indexed _to,
    uint _currencyValue,
    uint _fairValue
  );
  event Sell(
    address indexed _from,
    address indexed _to,
    uint _currencyValue,
    uint _fairValue
  );
  event Burn(
    address indexed _from,
    uint _fairValue
  );
  event StateChange(
    uint _previousState,
    uint _newState
  );

  /**
   * Constants
   */

  /// @notice The default state
  uint internal constant STATE_INIT = 0;

  /// @notice The state after initGoal has been reached
  uint internal constant STATE_RUN = 1;

  /// @notice The state after closed by the `beneficiary` account from STATE_RUN
  uint internal constant STATE_CLOSE = 2;

  /// @notice The state after closed by the `beneficiary` account from STATE_INIT
  uint internal constant STATE_CANCEL = 3;

  /// @notice When multiplying 2 terms, the max value is 2^128-1
  uint internal constant MAX_BEFORE_SQUARE = 2**128 - 1;

  /// @notice The denominator component for values specified in basis points.
  uint internal constant BASIS_POINTS_DEN = 10000;

  /// @notice The max `totalSupply() + burnedSupply`
  /// @dev This limit ensures that the DAT's formulas do not overflow (<MAX_BEFORE_SQUARE/2)
  uint internal constant MAX_SUPPLY = 10 ** 38;

  /**
   * Data specific to our token business logic
   */

  /// @notice The contract for transfer authorizations, if any.
  IWhitelist public whitelist;

  /// @notice The total number of burned FAIR tokens, excluding tokens burned from a `Sell` action in the DAT.
  uint public burnedSupply;

  /**
   * Data for DAT business logic
   */

  /// @dev unused slot which remains to ensure compatible upgrades
  bool private __autoBurn;

  /// @notice The address of the beneficiary organization which receives the investments.
  /// Points to the wallet of the organization.
  address payable public beneficiary;

  /// @notice The buy slope of the bonding curve.
  /// Does not affect the financial model, only the granularity of FAIR.
  /// @dev This is the numerator component of the fractional value.
  uint public buySlopeNum;

  /// @notice The buy slope of the bonding curve.
  /// Does not affect the financial model, only the granularity of FAIR.
  /// @dev This is the denominator component of the fractional value.
  uint public buySlopeDen;

  /// @notice The address from which the updatable variables can be updated
  address public control;

  /// @notice The address of the token used as reserve in the bonding curve
  /// (e.g. the DAI contract). Use ETH if 0.
  IERC20 public currency;

  /// @notice The address where fees are sent.
  address payable public feeCollector;

  /// @notice The percent fee collected each time new FAIR are issued expressed in basis points.
  uint public feeBasisPoints;

  /// @notice The initial fundraising goal (expressed in FAIR) to start the c-org.
  /// `0` means that there is no initial fundraising and the c-org immediately moves to run state.
  uint public initGoal;

  /// @notice A map with all investors in init state using address as a key and amount as value.
  /// @dev This structure's purpose is to make sure that only investors can withdraw their money if init_goal is not reached.
  mapping(address => uint) public initInvestors;

  /// @notice The initial number of FAIR created at initialization for the beneficiary.
  /// Technically however, this variable is not a constant as we must always have
  ///`init_reserve>=total_supply+burnt_supply` which means that `init_reserve` will be automatically
  /// decreased to equal `total_supply+burnt_supply` in case `init_reserve>total_supply+burnt_supply`
  /// after an investor sells his FAIRs.
  /// @dev Organizations may move these tokens into vesting contract(s)
  uint public initReserve;

  /// @notice The investment reserve of the c-org. Defines the percentage of the value invested that is
  /// automatically funneled and held into the buyback_reserve expressed in basis points.
  /// Internal since this is n/a to all derivative contracts.
  uint internal __investmentReserveBasisPoints;

  /// @dev unused slot which remains to ensure compatible upgrades
  uint private __openUntilAtLeast;

  /// @notice The minimum amount of `currency` investment accepted.
  uint public minInvestment;

  /// @dev The revenue commitment of the organization. Defines the percentage of the value paid through the contract
  /// that is automatically funneled and held into the buyback_reserve expressed in basis points.
  /// Internal since this is n/a to all derivative contracts.
  uint internal __revenueCommitmentBasisPoints;

  /// @notice The current state of the contract.
  /// @dev See the constants above for possible state values.
  uint public state;

  /// @dev If this value changes we need to reconstruct the DOMAIN_SEPARATOR
  string public constant version = "3";
  // --- EIP712 niceties ---
  // Original source: https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f#code
  mapping (address => uint) public nonces;
  bytes32 public DOMAIN_SEPARATOR;
  // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
  bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

  // The success fee (expressed in currency) that will be earned by setupFeeRecipient as soon as initGoal
  // is reached. We must have setup_fee <= buy_slope*init_goal^(2)/2
  uint public setupFee;

  // The recipient of the setup_fee once init_goal is reached
  address payable public setupFeeRecipient;

  /// @notice The minimum time before which the c-org contract cannot be closed once the contract has
  /// reached the `run` state.
  /// @dev When updated, the new value of `minimum_duration` cannot be earlier than the previous value.
  uint public minDuration;

  /// @dev Initialized at `0` and updated when the contract switches from `init` state to `run` state
  /// or when the initial trial period ends.
  uint public __startedOn;

  /// @notice The max possible value
  uint internal constant MAX_UINT = 2**256 - 1;

  // keccak256("PermitBuy(address from,address to,uint256 currencyValue,uint256 minTokensBought,uint256 nonce,uint256 deadline)");
  bytes32 public constant PERMIT_BUY_TYPEHASH = 0xaf42a244b3020d6a2253d9f291b4d3e82240da42b22129a8113a58aa7a3ddb6a;

  // keccak256("PermitSell(address from,address to,uint256 quantityToSell,uint256 minCurrencyReturned,uint256 nonce,uint256 deadline)");
  bytes32 public constant PERMIT_SELL_TYPEHASH = 0x5dfdc7fb4c68a4c249de5e08597626b84fbbe7bfef4ed3500f58003e722cc548;

  modifier authorizeTransfer(
    address _from,
    address _to,
    uint _value,
    bool _isSell
  )
  {
    if(address(whitelist) != address(0))
    {
      //automatically activate wallet _from
      //does not activate if,
      //1. _from is zero address,
      //2. it is burn
      if(!whitelist.walletActivated(_from) && _from != address(0) && !(_to == address(0) && !_isSell)){
        whitelist.activateWallet(_from);
      }
      //automatically activate wallet _to
      //does not activate if,
      //1. _to is zero address,
      if(!whitelist.walletActivated(_to) && _to != address(0)){
        whitelist.activateWallet(_to);
      }
      // This is not set for the minting of initialReserve
      whitelist.authorizeTransfer(_from, _to, _value, _isSell);
    }
    _;
    if(address(whitelist) != address(0)){
      //automatically deactivates _from if _from's balance is zero
      if(balanceOf(_from) == 0 && _from != address(0) && !(_to==address(0) && !_isSell)){
        //deactivate wallets without balance
        whitelist.deactivateWallet(_from);
      }
    }
  }

  /**
   * Buyback reserve
   */

  /// @notice The total amount of currency value currently locked in the contract and available to sellers.
  function buybackReserve() public view returns (uint)
  {
    uint reserve = address(this).balance;
    if(address(currency) != address(0))
    {
      reserve = currency.balanceOf(address(this));
    }

    if(reserve > MAX_BEFORE_SQUARE)
    {
      /// Math: If the reserve becomes excessive, cap the value to prevent overflowing in other formulas
      return MAX_BEFORE_SQUARE;
    }

    return reserve;
  }

  /**
   * Functions required by the ERC-20 token standard
   */

  /// @dev Moves tokens from one account to another if authorized.
  function _transfer(
    address _from,
    address _to,
    uint _amount
  ) internal
    authorizeTransfer(_from, _to, _amount, false)
  {
    require(state != STATE_INIT || _from == beneficiary, "ONLY_BENEFICIARY_DURING_INIT");
    super._transfer(_from, _to, _amount);
  }

  /// @dev Removes tokens from the circulating supply.
  function _burn(
    address _from,
    uint _amount,
    bool _isSell
  ) internal
    authorizeTransfer(_from, address(0), _amount, _isSell)
  {
    super._burn(_from, _amount);

    if(!_isSell)
    {
      // This is a burn
      require(state == STATE_RUN, "INVALID_STATE");
      // SafeMath not required as we cap how high this value may get during mint
      burnedSupply += _amount;
      emit Burn(_from, _amount);
    }
  }

  /// @notice Called to mint tokens on `buy`.
  function _mint(
    address _to,
    uint _quantity
  ) internal
    authorizeTransfer(address(0), _to, _quantity, false)
  {
    super._mint(_to, _quantity);

    // Math: If this value got too large, the DAT may overflow on sell
    require(totalSupply().add(burnedSupply) <= MAX_SUPPLY, "EXCESSIVE_SUPPLY");
  }

  /**
   * Transaction Helpers
   */

  /// @notice Confirms the transfer of `_quantityToInvest` currency to the contract.
  function _collectInvestment(
    address payable _from,
    uint _quantityToInvest,
    uint _msgValue,
    bool _refundRemainder
  ) internal
  {
    if(address(currency) == address(0))
    {
      // currency is ETH
      if(_refundRemainder)
      {
        // Math: if _msgValue was not sufficient then revert
        uint refund = _msgValue.sub(_quantityToInvest);
        if(refund > 0)
        {
          Address.sendValue(msg.sender, refund);
        }
      }
      else
      {
        require(_quantityToInvest == _msgValue, "INCORRECT_MSG_VALUE");
      }
    }
    else
    {
      // currency is ERC20
      require(_msgValue == 0, "DO_NOT_SEND_ETH");

      currency.safeTransferFrom(_from, address(this), _quantityToInvest);
    }
  }

  /// @dev Send `_amount` currency from the contract to the `_to` account.
  function _transferCurrency(
    address payable _to,
    uint _amount
  ) internal
  {
    if(_amount > 0)
    {
      if(address(currency) == address(0))
      {
        Address.sendValue(_to, _amount);
      }
      else
      {
        currency.safeTransfer(_to, _amount);
      }
    }
  }

  /**
   * Config / Control
   */

  /// @notice Called once after deploy to set the initial configuration.
  /// None of the values provided here may change once initially set.
  /// @dev using the init pattern in order to support zos upgrades
  function _initialize(
    uint _initReserve,
    address _currencyAddress,
    uint _initGoal,
    uint _buySlopeNum,
    uint _buySlopeDen,
    uint _setupFee,
    address payable _setupFeeRecipient
  ) internal
  {
    // The ERC-20 implementation will confirm initialize is only run once
    ERC20Capped.initialize((5000000 * (10 ** 18)), msg.sender);
    // Also update the pausable setting
    _addPauser(msg.sender);

    require(_buySlopeNum > 0, "INVALID_SLOPE_NUM");
    require(_buySlopeDen > 0, "INVALID_SLOPE_DEN");
    require(_buySlopeNum < MAX_BEFORE_SQUARE, "EXCESSIVE_SLOPE_NUM");
    require(_buySlopeDen < MAX_BEFORE_SQUARE, "EXCESSIVE_SLOPE_DEN");
    buySlopeNum = _buySlopeNum;
    buySlopeDen = _buySlopeDen;

    // Setup Fee
    require(_setupFee == 0 || _setupFeeRecipient != address(0), "MISSING_SETUP_FEE_RECIPIENT");
    require(_setupFeeRecipient == address(0) || _setupFee != 0, "MISSING_SETUP_FEE");
    // setup_fee <= (n/d)*(g^2)/2
    uint initGoalInCurrency = _initGoal * _initGoal;
    initGoalInCurrency = initGoalInCurrency.mul(_buySlopeNum);
    initGoalInCurrency /= 2 * _buySlopeDen;
    require(_setupFee <= initGoalInCurrency, "EXCESSIVE_SETUP_FEE");
    setupFee = _setupFee;
    setupFeeRecipient = _setupFeeRecipient;

    // Set default values (which may be updated using `updateConfig`)
    uint decimals = 18;
    if(_currencyAddress != address(0))
    {
      decimals = IERC20Detailed(_currencyAddress).decimals();
    }
    minInvestment = 100 * (10 ** decimals);
    beneficiary = msg.sender;
    control = msg.sender;
    feeCollector = msg.sender;

    // Save currency
    currency = IERC20(_currencyAddress);

    // Mint the initial reserve
    if(_initReserve > 0)
    {
      initReserve = _initReserve;
      _mint(beneficiary, initReserve);
    }

    initializeDomainSeparator();
  }

  /// @notice Used to initialize the domain separator used in meta-transactions
  /// @dev This is separate from `initialize` to allow upgraded contracts to update the version
  /// There is no harm in calling this multiple times / no permissions required
  function initializeDomainSeparator() public
  {
    uint id;
    // solium-disable-next-line
    assembly
    {
      id := chainid()
    }
    DOMAIN_SEPARATOR = keccak256(
      abi.encode(
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
        keccak256(bytes(name())),
        keccak256(bytes(version)),
        id,
        address(this)
      )
    );
  }

  function _updateConfig(
    address _whitelistAddress,
    address payable _beneficiary,
    address _control,
    address payable _feeCollector,
    uint _feeBasisPoints,
    uint _minInvestment,
    uint _minDuration
  ) internal
  {
    // This require(also confirms that initialize has been called.
    require(msg.sender == control, "CONTROL_ONLY");

    // address(0) is okay
    whitelist = IWhitelist(_whitelistAddress);

    require(_control != address(0), "INVALID_ADDRESS");
    control = _control;

    require(_feeCollector != address(0), "INVALID_ADDRESS");
    feeCollector = _feeCollector;

    require(_feeBasisPoints <= BASIS_POINTS_DEN, "INVALID_FEE");
    feeBasisPoints = _feeBasisPoints;

    require(_minInvestment > 0, "INVALID_MIN_INVESTMENT");
    minInvestment = _minInvestment;

    require(_minDuration >= minDuration, "MIN_DURATION_MAY_NOT_BE_REDUCED");
    minDuration = _minDuration;

    if(beneficiary != _beneficiary)
    {
      require(_beneficiary != address(0), "INVALID_ADDRESS");
      uint tokens = balanceOf(beneficiary);
      initInvestors[_beneficiary] = initInvestors[_beneficiary].add(initInvestors[beneficiary]);
      initInvestors[beneficiary] = 0;
      if(tokens > 0)
      {
        _transfer(beneficiary, _beneficiary, tokens);
      }
      beneficiary = _beneficiary;
    }
  }

  /**
   * Functions for our business logic
   */

  /// @notice Burn the amount of tokens from the address msg.sender if authorized.
  /// @dev Note that this is not the same as a `sell` via the DAT.
  function burn(
    uint _amount
  ) public
  {
    _burn(msg.sender, _amount, false);
  }

  /// @notice Burn the amount of tokens from the given address if approved.
  function burnFrom(
    address _from,
    uint _amount
  ) public
  {
    _approve(_from, msg.sender, allowance(_from, msg.sender).sub(_amount, "ERC20: burn amount exceeds allowance"));
    _burn(_from, _amount, false);
  }

  // Buy

  /// @dev Distributes _value currency between the buybackReserve, beneficiary, and feeCollector.
  function _distributeInvestment(uint _value) internal;

  /// @notice Calculate how many FAIR tokens you would buy with the given amount of currency if `buy` was called now.
  /// @param _currencyValue How much currency to spend in order to buy FAIR.
  function estimateBuyValue(
    uint _currencyValue
  ) public view
    returns (uint)
  {
    if(_currencyValue < minInvestment)
    {
      return 0;
    }

    /// Calculate the tokenValue for this investment
    uint tokenValue;
    if(state == STATE_INIT)
    {
      uint currencyValue = _currencyValue;
      uint _totalSupply = totalSupply();
      // (buy_slope*init_goal)*(init_goal+init_reserve-total_supply)
      // n/d: buy_slope (MAX_BEFORE_SQUARE / MAX_BEFORE_SQUARE)
      // g: init_goal (MAX_BEFORE_SQUARE)
      // t: total_supply (MAX_BEFORE_SQUARE)
      // r: init_reserve (MAX_BEFORE_SQUARE)
      // source: ((n/d)*g)*(g+r-t)
      // impl: (g n (g + r - t))/(d)
      uint max = BigDiv.bigDiv2x1(
        initGoal * buySlopeNum,
        initGoal + initReserve - _totalSupply,
        buySlopeDen
      );
      if(currencyValue > max)
      {
        currencyValue = max;
      }
      // Math: worst case
      // MAX * MAX_BEFORE_SQUARE
      // / MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE
      tokenValue = BigDiv.bigDiv2x1(
        currencyValue,
        buySlopeDen,
        initGoal * buySlopeNum
      );

      if(currencyValue != _currencyValue)
      {
        currencyValue = _currencyValue - max;
        // ((2*next_amount/buy_slope)+init_goal^2)^(1/2)-init_goal
        // a: next_amount | currencyValue
        // n/d: buy_slope (MAX_BEFORE_SQUARE / MAX_BEFORE_SQUARE)
        // g: init_goal (MAX_BEFORE_SQUARE/2)
        // r: init_reserve (MAX_BEFORE_SQUARE/2)
        // sqrt(((2*a/(n/d))+g^2)-g
        // sqrt((2 d a + n g^2)/n) - g

        // currencyValue == 2 d a
        uint temp = 2 * buySlopeDen;
        currencyValue = temp.mul(currencyValue);

        // temp == g^2
        temp = initGoal;
        temp *= temp;

        // temp == n g^2
        temp = temp.mul(buySlopeNum);

        // temp == (2 d a) + n g^2
        temp = currencyValue.add(temp);

        // temp == (2 d a + n g^2)/n
        temp /= buySlopeNum;

        // temp == sqrt((2 d a + n g^2)/n)
        temp = temp.sqrt();

        // temp == sqrt((2 d a + n g^2)/n) - g
        temp -= initGoal;

        tokenValue = tokenValue.add(temp);
      }
    }
    else if(state == STATE_RUN)
    {
      // initReserve is reduced on sell as necessary to ensure that this line will not overflow
      uint supply = totalSupply() + burnedSupply - initReserve;
      // Math: worst case
      // MAX * 2 * MAX_BEFORE_SQUARE
      // / MAX_BEFORE_SQUARE
      tokenValue = BigDiv.bigDiv2x1(
        _currencyValue,
        2 * buySlopeDen,
        buySlopeNum
      );

      // Math: worst case MAX + (MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE)
      tokenValue = tokenValue.add(supply * supply);
      tokenValue = tokenValue.sqrt();

      // Math: small chance of underflow due to possible rounding in sqrt
      tokenValue = tokenValue.sub(supply);
    }
    else
    {
      // invalid state
      return 0;
    }

    return tokenValue;
  }

  function _buy(
    address payable _from,
    address _to,
    uint _currencyValue,
    uint _minTokensBought
  ) internal
  {
    require(_to != address(0), "INVALID_ADDRESS");
    require(_minTokensBought > 0, "MUST_BUY_AT_LEAST_1");

    // Calculate the tokenValue for this investment
    uint tokenValue = estimateBuyValue(_currencyValue);
    require(tokenValue >= _minTokensBought, "PRICE_SLIPPAGE");

    emit Buy(_from, _to, _currencyValue, tokenValue);

    _collectInvestment(_from, _currencyValue, msg.value, false);

    // Update state, initInvestors, and distribute the investment when appropriate
    if(state == STATE_INIT)
    {
      // Math worst case: MAX_BEFORE_SQUARE
      initInvestors[_to] += tokenValue;
      // Math worst case:
      // MAX_BEFORE_SQUARE + MAX_BEFORE_SQUARE
      if(totalSupply() + tokenValue - initReserve >= initGoal)
      {
        emit StateChange(state, STATE_RUN);
        state = STATE_RUN;
        if(__startedOn == 0) {
          __startedOn = block.timestamp;
        }

        // Math worst case:
        // MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE/2
        // / MAX_BEFORE_SQUARE
        uint beneficiaryContribution = BigDiv.bigDiv2x1(
          initInvestors[beneficiary],
          buySlopeNum * initGoal,
          buySlopeDen
        );

        if(setupFee > 0)
        {
          _transferCurrency(setupFeeRecipient, setupFee);
          if(beneficiaryContribution > setupFee)
          {
            beneficiaryContribution -= setupFee;
          }
          else
          {
            beneficiaryContribution = 0;
          }
        }

        _distributeInvestment(buybackReserve().sub(beneficiaryContribution));
      }
    }
    else // implied: if(state == STATE_RUN)
    {
      if(_to != beneficiary)
      {
        _distributeInvestment(_currencyValue);
      }
    }

    _mint(_to, tokenValue);
  }

  /// @notice Purchase FAIR tokens with the given amount of currency.
  /// @param _to The account to receive the FAIR tokens from this purchase.
  /// @param _currencyValue How much currency to spend in order to buy FAIR.
  /// @param _minTokensBought Buy at least this many FAIR tokens or the transaction reverts.
  /// @dev _minTokensBought is necessary as the price will change if some elses transaction mines after
  /// yours was submitted.
  function buy(
    address _to,
    uint _currencyValue,
    uint _minTokensBought
  ) public payable
  {
    _buy(msg.sender, _to, _currencyValue, _minTokensBought);
  }

  /// @notice Allow users to sign a message authorizing a buy
  function permitBuy(
    address payable _from,
    address _to,
    uint _currencyValue,
    uint _minTokensBought,
    uint _deadline,
    uint8 _v,
    bytes32 _r,
    bytes32 _s
  ) external
  {
    require(_deadline >= block.timestamp, "EXPIRED");
    bytes32 digest = keccak256(abi.encode(PERMIT_BUY_TYPEHASH, _from, _to, _currencyValue, _minTokensBought, nonces[_from]++, _deadline));
    digest = keccak256(
      abi.encodePacked(
        "\x19\x01",
        DOMAIN_SEPARATOR,
        digest
      )
    );
    address recoveredAddress = ecrecover(digest, _v, _r, _s);
    require(recoveredAddress != address(0) && recoveredAddress == _from, "INVALID_SIGNATURE");
    _buy(_from, _to, _currencyValue, _minTokensBought);
  }

  /// Sell

  function estimateSellValue(
    uint _quantityToSell
  ) public view
    returns(uint)
  {
    uint reserve = buybackReserve();

    // Calculate currencyValue for this sale
    uint currencyValue;
    if(state == STATE_RUN)
    {
      uint supply = totalSupply() + burnedSupply;

      // buyback_reserve = r
      // total_supply = t
      // burnt_supply = b
      // amount = a
      // source: (t+b)*a*(2*r)/((t+b)^2)-(((2*r)/((t+b)^2)*a^2)/2)+((2*r)/((t+b)^2)*a*b^2)/(2*(t))
      // imp: (a b^2 r)/(t (b + t)^2) + (2 a r)/(b + t) - (a^2 r)/(b + t)^2

      // Math: burnedSupply is capped in FAIR such that the square will never overflow
      // Math worst case:
      // MAX * MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE/2 * MAX_BEFORE_SQUARE/2
      // / MAX_BEFORE_SQUARE/2 * MAX_BEFORE_SQUARE/2 * MAX_BEFORE_SQUARE/2
      currencyValue = BigDiv.bigDiv2x2(
        _quantityToSell.mul(reserve),
        burnedSupply * burnedSupply,
        totalSupply(), supply * supply
      );
      // Math: worst case currencyValue is MAX_BEFORE_SQUARE (max reserve, 1 supply)

      // Math worst case:
      // MAX * 2 * MAX_BEFORE_SQUARE
      uint temp = _quantityToSell.mul(2 * reserve);
      temp /= supply;
      // Math: worst-case temp is MAX_BEFORE_SQUARE (max reserve, 1 supply)

      // Math: considering the worst-case for currencyValue and temp, this can never overflow
      currencyValue += temp;

      // Math: worst case
      // MAX * MAX * MAX_BEFORE_SQUARE
      // / MAX_BEFORE_SQUARE/2 * MAX_BEFORE_SQUARE/2
      temp = BigDiv.bigDiv2x1RoundUp(
        _quantityToSell.mul(_quantityToSell),
        reserve,
        supply * supply
      );
      if(currencyValue > temp)
      {
        currencyValue -= temp;
      }
      else
      {
        currencyValue = 0;
      }
    }
    else if(state == STATE_CLOSE)
    {
      // Math worst case
      // MAX * MAX_BEFORE_SQUARE
      currencyValue = _quantityToSell.mul(reserve);
      currencyValue /= totalSupply();
    }
    else
    {
      // STATE_INIT or STATE_CANCEL
      // Math worst case:
      // MAX * MAX_BEFORE_SQUARE
      currencyValue = _quantityToSell.mul(reserve);
      // Math: FAIR blocks initReserve from being burned unless we reach the RUN state which prevents an underflow
      currencyValue /= totalSupply() - initReserve;
    }

    return currencyValue;
  }

  function _sell(
    address _from,
    address payable _to,
    uint _quantityToSell,
    uint _minCurrencyReturned
  ) internal
  {
    require(_from != beneficiary || state >= STATE_CLOSE, "BENEFICIARY_ONLY_SELL_IN_CLOSE_OR_CANCEL");
    require(_minCurrencyReturned > 0, "MUST_SELL_AT_LEAST_1");

    uint currencyValue = estimateSellValue(_quantityToSell);
    require(currencyValue >= _minCurrencyReturned, "PRICE_SLIPPAGE");

    if(state == STATE_INIT || state == STATE_CANCEL)
    {
      initInvestors[_from] = initInvestors[_from].sub(_quantityToSell);
    }

    _burn(_from, _quantityToSell, true);
    uint supply = totalSupply() + burnedSupply;
    if(supply < initReserve)
    {
      initReserve = supply;
    }

    _transferCurrency(_to, currencyValue);
    emit Sell(_from, _to, currencyValue, _quantityToSell);
  }

  /// @notice Sell FAIR tokens for at least the given amount of currency.
  /// @param _to The account to receive the currency from this sale.
  /// @param _quantityToSell How many FAIR tokens to sell for currency value.
  /// @param _minCurrencyReturned Get at least this many currency tokens or the transaction reverts.
  /// @dev _minCurrencyReturned is necessary as the price will change if some elses transaction mines after
  /// yours was submitted.
  function sell(
    address payable _to,
    uint _quantityToSell,
    uint _minCurrencyReturned
  ) public
  {
    _sell(msg.sender, _to, _quantityToSell, _minCurrencyReturned);
  }

  /// @notice Allow users to sign a message authorizing a sell
  function permitSell(
    address _from,
    address payable _to,
    uint _quantityToSell,
    uint _minCurrencyReturned,
    uint _deadline,
    uint8 _v,
    bytes32 _r,
    bytes32 _s
  ) external
  {
    require(_deadline >= block.timestamp, "EXPIRED");
    bytes32 digest = keccak256(abi.encode(PERMIT_SELL_TYPEHASH, _from, _to, _quantityToSell, _minCurrencyReturned, nonces[_from]++, _deadline));
    digest = keccak256(
      abi.encodePacked(
        "\x19\x01",
        DOMAIN_SEPARATOR,
        digest
      )
    );
    address recoveredAddress = ecrecover(digest, _v, _r, _s);
    require(recoveredAddress != address(0) && recoveredAddress == _from, "INVALID_SIGNATURE");
    _sell(_from, _to, _quantityToSell, _minCurrencyReturned);
  }

  /// Close

  /// @notice Called by the beneficiary account to STATE_CLOSE or STATE_CANCEL the c-org,
  /// preventing any more tokens from being minted.
  /// @dev Requires an `exitFee` to be paid.  If the currency is ETH, include a little more than
  /// what appears to be required and any remainder will be returned to your account.  This is
  /// because another user may have a transaction mined which changes the exitFee required.
  /// For other `currency` types, the beneficiary account will be billed the exact amount required.
  function _close() internal
  {
    require(msg.sender == beneficiary, "BENEFICIARY_ONLY");

    if(state == STATE_INIT)
    {
      // Allow the org to cancel anytime if the initGoal was not reached.
      emit StateChange(state, STATE_CANCEL);
      state = STATE_CANCEL;
    }
    else if(state == STATE_RUN)
    {
      // Collect the exitFee and close the c-org.
      require(MAX_UINT - minDuration > __startedOn, "MAY_NOT_CLOSE");
      require(minDuration + __startedOn <= block.timestamp, "TOO_EARLY");

      emit StateChange(state, STATE_CLOSE);
      state = STATE_CLOSE;
    }
    else
    {
      revert("INVALID_STATE");
    }
  }

  // --- Approve by signature ---
  // EIP-2612
  // Original source: https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol
  function permit(
    address owner,
    address spender,
    uint value,
    uint deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) external
  {
    require(deadline >= block.timestamp, "EXPIRED");
    bytes32 digest = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline));
    digest = keccak256(
      abi.encodePacked(
        "\x19\x01",
        DOMAIN_SEPARATOR,
        digest
      )
    );
    address recoveredAddress = ecrecover(digest, v, r, s);
    require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNATURE");
    _approve(owner, spender, value);
  }

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

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

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

  uint256[50] private __gap;
}

/**
 * @title Decentralized Autonomous Trust
 * This contract is the reference implementation provided by Fairmint for a
 * Decentralized Autonomous Trust as described in the continuous
 * organization whitepaper (https://github.com/c-org/whitepaper) and
 * specified here: https://github.com/fairmint/c-org/wiki. Use at your own
 * risk. If you have question or if you're looking for a ready-to-use
 * solution using this contract, you might be interested in Fairmint's
 * offering. Do not hesitate to get in touch with us: https://fairmint.co
 */
contract VisionToken is ContinuousOffering {
  event Close(uint _exitFee);
  event Pay(address indexed _from, uint _currencyValue);
  event UpdateConfig(
    address _whitelistAddress,
    address indexed _beneficiary,
    address indexed _control,
    address indexed _feeCollector,
    uint _revenueCommitmentBasisPoints,
    uint _feeBasisPoints,
    uint _minInvestment,
    uint _minDuration
  );

  /// @notice The revenue commitment of the organization. Defines the percentage of the value paid through the contract
  /// that is automatically funneled and held into the buyback_reserve expressed in basis points.
  /// Internal since this is n/a to all derivative contracts.
  function revenueCommitmentBasisPoints() public view returns (uint) {
    return __revenueCommitmentBasisPoints;
  }

  /// @notice The investment reserve of the c-org. Defines the percentage of the value invested that is
  /// automatically funneled and held into the buyback_reserve expressed in basis points.
  /// Internal since this is n/a to all derivative contracts.
  function investmentReserveBasisPoints() public view returns (uint) {
    return __investmentReserveBasisPoints;
  }

  /// @notice Initialized at `0` and updated when the contract switches from `init` state to `run` state
  /// with the current timestamp.
  function runStartedOn() public view returns (uint) {
    return __startedOn;
  }

  function initialize(
    uint _initReserve,
    address _currencyAddress,
    uint _initGoal,
    uint _buySlopeNum,
    uint _buySlopeDen,
    uint _investmentReserveBasisPoints,
    uint _setupFee,
    address payable _setupFeeRecipient
  ) public
  {
    // _initialize will enforce this is only called once
    super._initialize(
      _initReserve,
      _currencyAddress,
      _initGoal,
      _buySlopeNum,
      _buySlopeDen,
      _setupFee,
      _setupFeeRecipient
    );

    // Set initGoal, which in turn defines the initial state
    if(_initGoal == 0)
    {
      emit StateChange(state, STATE_RUN);
      state = STATE_RUN;
      __startedOn = block.timestamp;
    }
    else
    {
      // Math: If this value got too large, the DAT would overflow on sell
      require(_initGoal < MAX_SUPPLY, "EXCESSIVE_GOAL");
      initGoal = _initGoal;
    }

    // 100% or less
    require(_investmentReserveBasisPoints <= BASIS_POINTS_DEN, "INVALID_RESERVE");
    __investmentReserveBasisPoints = _investmentReserveBasisPoints;
  }



  /// Close


  function estimateExitFee(uint _msgValue) public view returns (uint) {
    uint exitFee;

    if (state == STATE_RUN) {
      uint reserve = buybackReserve();
      reserve = reserve.sub(_msgValue);

      // Source: t*(t+b)*(n/d)-r
      // Implementation: (b n t)/d + (n t^2)/d - r

      uint _totalSupply = totalSupply();

      // Math worst case:
      // MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE/2 * MAX_BEFORE_SQUARE
      exitFee = BigDiv.bigDiv2x1(
        _totalSupply,
        burnedSupply * buySlopeNum,
        buySlopeDen
      );
      // Math worst case:
      // MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE
      exitFee += BigDiv.bigDiv2x1(
        _totalSupply,
        buySlopeNum * _totalSupply,
        buySlopeDen
      );
      // Math: this if condition avoids a potential overflow
      if (exitFee <= reserve) {
        exitFee = 0;
      } else {
        exitFee -= reserve;
      }
    }

    return exitFee;
  }

  /// @notice Called by the beneficiary account to STATE_CLOSE or STATE_CANCEL the c-org,
  /// preventing any more tokens from being minted.
  /// @dev Requires an `exitFee` to be paid.  If the currency is ETH, include a little more than
  /// what appears to be required and any remainder will be returned to your account.  This is
  /// because another user may have a transaction mined which changes the exitFee required.
  /// For other `currency` types, the beneficiary account will be billed the exact amount required.
  function close() public payable {
    uint exitFee = 0;

    if (state == STATE_RUN) {
      exitFee = estimateExitFee(msg.value);
      _collectInvestment(msg.sender, exitFee, msg.value, true);
    }

    super._close();
    emit Close(exitFee);
  }

  /// Pay

  /// @dev Pay the organization on-chain.
  /// @param _currencyValue How much currency which was paid.
  function pay(uint _currencyValue) public payable {
    _collectInvestment(msg.sender, _currencyValue, msg.value, false);
    require(state == STATE_RUN, "INVALID_STATE");
    require(_currencyValue > 0, "MISSING_CURRENCY");

    // Send a portion of the funds to the beneficiary, the rest is added to the buybackReserve
    // Math: if _currencyValue is < (2^256 - 1) / 10000 this will not overflow
    uint reserve = _currencyValue.mul(__revenueCommitmentBasisPoints);
    reserve /= BASIS_POINTS_DEN;

    // Math: this will never underflow since revenueCommitmentBasisPoints is capped to BASIS_POINTS_DEN
    _transferCurrency(beneficiary, _currencyValue - reserve);

    emit Pay(msg.sender, _currencyValue);
  }

  /// @notice Pay the organization on-chain without minting any tokens.
  /// @dev This allows you to add funds directly to the buybackReserve.
  function() external payable {
    require(address(currency) == address(0), "ONLY_FOR_CURRENCY_ETH");
  }

  function updateConfig(
    address _whitelistAddress,
    address payable _beneficiary,
    address _control,
    address payable _feeCollector,
    uint _feeBasisPoints,
    uint _revenueCommitmentBasisPoints,
    uint _minInvestment,
    uint _minDuration
  ) public {
    _updateConfig(
      _whitelistAddress,
      _beneficiary,
      _control,
      _feeCollector,
      _feeBasisPoints,
      _minInvestment,
      _minDuration
    );

    require(
      _revenueCommitmentBasisPoints <= BASIS_POINTS_DEN,
      "INVALID_COMMITMENT"
    );
    require(
      _revenueCommitmentBasisPoints >= __revenueCommitmentBasisPoints,
      "COMMITMENT_MAY_NOT_BE_REDUCED"
    );
    __revenueCommitmentBasisPoints = _revenueCommitmentBasisPoints;

    emit UpdateConfig(
      _whitelistAddress,
      _beneficiary,
      _control,
      _feeCollector,
      _revenueCommitmentBasisPoints,
      _feeBasisPoints,
      _minInvestment,
      _minDuration
    );
  }

  /// @notice A temporary function to set `runStartedOn`, to be used by contracts which were
  /// already deployed before this feature was introduced.
  /// @dev This function will be removed once known users have called the function.
  function initializeRunStartedOn(
    uint _runStartedOn
  ) external
  {
    require(msg.sender == control, "CONTROL_ONLY");
    require(state == STATE_RUN, "ONLY_CALL_IN_RUN");
    require(__startedOn == 0, "ONLY_CALL_IF_NOT_AUTO_SET");
    require(_runStartedOn <= block.timestamp, "DATE_MUST_BE_IN_PAST");

    __startedOn = _runStartedOn;
  }

  /// @dev Distributes _value currency between the buybackReserve, beneficiary, and feeCollector.
  function _distributeInvestment(
    uint _value
  ) internal
  {
    // Rounding favors buybackReserve, then beneficiary, and feeCollector is last priority.

    // Math: if investment value is < (2^256 - 1) / 10000 this will never overflow.
    // Except maybe with a huge single investment, but they can try again with multiple smaller investments.
    uint reserve = __investmentReserveBasisPoints.mul(_value);
    reserve /= BASIS_POINTS_DEN;
    reserve = _value.sub(reserve);
    uint fee = reserve.mul(feeBasisPoints);
    fee /= BASIS_POINTS_DEN;

    // Math: since feeBasisPoints is <= BASIS_POINTS_DEN, this will never underflow.
    _transferCurrency(beneficiary, reserve - fee);
    _transferCurrency(feeCollector, fee);
  }
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"uint256","name":"_fairValue","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_currencyValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_fairValue","type":"uint256"}],"name":"Buy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_exitFee","type":"uint256"}],"name":"Close","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"MinterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"MinterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"PauserAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"PauserRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"uint256","name":"_currencyValue","type":"uint256"}],"name":"Pay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_currencyValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_fairValue","type":"uint256"}],"name":"Sell","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_previousState","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newState","type":"uint256"}],"name":"StateChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_whitelistAddress","type":"address"},{"indexed":true,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":true,"internalType":"address","name":"_control","type":"address"},{"indexed":true,"internalType":"address","name":"_feeCollector","type":"address"},{"indexed":false,"internalType":"uint256","name":"_revenueCommitmentBasisPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_feeBasisPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_minInvestment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_minDuration","type":"uint256"}],"name":"UpdateConfig","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_BUY_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_SELL_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"__startedOn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addMinter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addPauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"beneficiary","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burnFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"burnedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_currencyValue","type":"uint256"},{"internalType":"uint256","name":"_minTokensBought","type":"uint256"}],"name":"buy","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"buySlopeDen","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"buySlopeNum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"buybackReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"close","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"control","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currency","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_currencyValue","type":"uint256"}],"name":"estimateBuyValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_msgValue","type":"uint256"}],"name":"estimateExitFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_quantityToSell","type":"uint256"}],"name":"estimateSellValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"feeBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"initGoal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"initInvestors","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_initReserve","type":"uint256"},{"internalType":"address","name":"_currencyAddress","type":"address"},{"internalType":"uint256","name":"_initGoal","type":"uint256"},{"internalType":"uint256","name":"_buySlopeNum","type":"uint256"},{"internalType":"uint256","name":"_buySlopeDen","type":"uint256"},{"internalType":"uint256","name":"_investmentReserveBasisPoints","type":"uint256"},{"internalType":"uint256","name":"_setupFee","type":"uint256"},{"internalType":"address payable","name":"_setupFeeRecipient","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"cap","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"initializeDomainSeparator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_runStartedOn","type":"uint256"}],"name":"initializeRunStartedOn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"investmentReserveBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isPauser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minInvestment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_currencyValue","type":"uint256"}],"name":"pay","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_currencyValue","type":"uint256"},{"internalType":"uint256","name":"_minTokensBought","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"permitBuy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_quantityToSell","type":"uint256"},{"internalType":"uint256","name":"_minCurrencyReturned","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"permitSell","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceMinter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renouncePauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"revenueCommitmentBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"runStartedOn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_quantityToSell","type":"uint256"},{"internalType":"uint256","name":"_minCurrencyReturned","type":"uint256"}],"name":"sell","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"setupFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"setupFeeRecipient","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_whitelistAddress","type":"address"},{"internalType":"address payable","name":"_beneficiary","type":"address"},{"internalType":"address","name":"_control","type":"address"},{"internalType":"address payable","name":"_feeCollector","type":"address"},{"internalType":"uint256","name":"_feeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"_revenueCommitmentBasisPoints","type":"uint256"},{"internalType":"uint256","name":"_minInvestment","type":"uint256"},{"internalType":"uint256","name":"_minDuration","type":"uint256"}],"name":"updateConfig","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"whitelist","outputs":[{"internalType":"contract IWhitelist","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]

6080604052615791806100136000396000f3fe6080604052600436106103ef5760003560e01c806382dc1ec411610208578063af575ab711610118578063c7159307116100ab578063d9cce5261161007a578063d9cce52614610e1b578063da35a26f14610e7d578063dd62ed3e14610eb6578063e5a6b10f14610ef1578063ff90956014610f06576103ef565b8063c715930714610d7e578063d29157fb14610d93578063d505accf14610da8578063d8de658714610e06576103ef565b8063c25b25bd116100e7578063c25b25bd14610d04578063c290d69114610d19578063c415b95c14610d36578063c4d66de814610d4b576103ef565b8063af575ab714610c4a578063b12f415314610cb0578063b8606eef14610cda578063c19d93fb14610cef576103ef565b80639df3f4f61161019b578063a59ac6dd1161016a578063a59ac6dd14610b82578063a71ddd2514610bb4578063a9059cbb14610bc9578063aa271e1a14610c02578063ad3b763314610c35576103ef565b80639df3f4f614610aba578063a40b56b914610acf578063a457c2d714610ae4578063a551bfc414610b1d576103ef565b806393e59dc1116101d757806393e59dc114610a4857806395d89b4114610a5d578063983b2d5614610a725780639865027514610aa5576103ef565b806382dc1ec4146109c15780638456cb59146109f4578063896d170814610a095780638ac2c68014610a33576103ef565b80633f4ba83a1161030357806358439fa5116102965780636ef8d66d116102655780636ef8d66d146108da57806370a08231146108ef578063736dcb1f1461092257806379cc6790146109555780637ecebe001461098e576103ef565b806358439fa51461085c5780635c975abb146108715780636177e37c146108865780636a2724621461089b576103ef565b806346fbf68e116102d257806346fbf68e146107ea57806354fd4d501461081d57806355d0a1d0146108325780635671576114610847576103ef565b80633f4ba83a1461076a57806340c10f191461077f57806342966c68146107b857806343d726d6146107e2576103ef565b80632e872bb311610386578063355274ea11610355578063355274ea146106c157806335e5cc31146106d65780633644e515146106eb57806338af3eed146107005780633950935114610731576103ef565b80632e872bb3146106425780632ff791611461066c57806330adf81f14610681578063313ce56714610696576103ef565b806323b872dd116103c257806323b872dd1461055b578063263154381461059e578063270588ee146105b35780632973434a14610618576103ef565b806306fdde0314610448578063095ea7b3146104d257806318160ddd1461051f5780631d833ec514610546575b61019e546001600160a01b031615610446576040805162461bcd60e51b815260206004820152601560248201527409e9c98b2be8c9ea4be86aaa4a48a9c86b2be8aa89605b1b604482015290519081900360640190fd5b005b34801561045457600080fd5b5061045d610f1b565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561049757818101518382015260200161047f565b50505050905090810190601f1680156104c45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104de57600080fd5b5061050b600480360360408110156104f557600080fd5b506001600160a01b038135169060200135610f42565b604080519115158252519081900360200190f35b34801561052b57600080fd5b50610534610fa3565b60408051918252519081900360200190f35b34801561055257600080fd5b50610534610fa9565b34801561056757600080fd5b5061050b6004803603606081101561057e57600080fd5b506001600160a01b03813581169160208101359091169060400135610fcd565b3480156105aa57600080fd5b50610534611030565b3480156105bf57600080fd5b5061044660048036036101008110156105d757600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060ff60a0820135169060c08101359060e00135611037565b34801561062457600080fd5b506104466004803603602081101561063b57600080fd5b503561122e565b34801561064e57600080fd5b506105346004803603602081101561066557600080fd5b5035611370565b34801561067857600080fd5b506104466114fb565b34801561068d57600080fd5b506105346115a0565b3480156106a257600080fd5b506106ab6115c4565b6040805160ff9092168252519081900360200190f35b3480156106cd57600080fd5b506105346115c9565b3480156106e257600080fd5b506105346115d0565b3480156106f757600080fd5b506105346115d7565b34801561070c57600080fd5b506107156115de565b604080516001600160a01b039092168252519081900360200190f35b34801561073d57600080fd5b5061050b6004803603604081101561075457600080fd5b506001600160a01b0381351690602001356115f3565b34801561077657600080fd5b5061044661164b565b34801561078b57600080fd5b5061050b600480360360408110156107a257600080fd5b506001600160a01b038135169060200135611734565b3480156107c457600080fd5b50610446600480360360208110156107db57600080fd5b5035611794565b6104466117a3565b3480156107f657600080fd5b5061050b6004803603602081101561080d57600080fd5b50356001600160a01b0316611808565b34801561082957600080fd5b5061045d61181b565b34801561083e57600080fd5b50610534611838565b34801561085357600080fd5b5061053461183f565b34801561086857600080fd5b50610534611846565b34801561087d57600080fd5b5061050b61184d565b34801561089257600080fd5b50610534611856565b3480156108a757600080fd5b50610446600480360360608110156108be57600080fd5b506001600160a01b03813516906020810135906040013561185d565b3480156108e657600080fd5b5061044661186e565b3480156108fb57600080fd5b506105346004803603602081101561091257600080fd5b50356001600160a01b0316611880565b34801561092e57600080fd5b506105346004803603602081101561094557600080fd5b50356001600160a01b031661189b565b34801561096157600080fd5b506104466004803603604081101561097857600080fd5b506001600160a01b0381351690602001356118ae565b34801561099a57600080fd5b50610534600480360360208110156109b157600080fd5b50356001600160a01b03166118fc565b3480156109cd57600080fd5b50610446600480360360208110156109e457600080fd5b50356001600160a01b031661190f565b348015610a0057600080fd5b5061044661195e565b348015610a1557600080fd5b5061053460048036036020811015610a2c57600080fd5b5035611a25565b348015610a3f57600080fd5b50610534611aac565b348015610a5457600080fd5b50610715611ab3565b348015610a6957600080fd5b5061045d611ac3565b348015610a7e57600080fd5b5061044660048036036020811015610a9557600080fd5b50356001600160a01b0316611ae3565b348015610ab157600080fd5b50610446611b32565b348015610ac657600080fd5b50610534611b42565b348015610adb57600080fd5b50610534611b49565b348015610af057600080fd5b5061050b60048036036040811015610b0757600080fd5b506001600160a01b038135169060200135611b50565b348015610b2957600080fd5b506104466004803603610100811015610b4157600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060ff60a0820135169060c08101359060e00135611ba8565b61044660048036036060811015610b9857600080fd5b506001600160a01b038135169060208101359060400135611d93565b348015610bc057600080fd5b50610534611d9f565b348015610bd557600080fd5b5061050b60048036036040811015610bec57600080fd5b506001600160a01b038135169060200135611da6565b348015610c0e57600080fd5b5061050b60048036036020811015610c2557600080fd5b50356001600160a01b0316611dfe565b348015610c4157600080fd5b50610534611e12565b348015610c5657600080fd5b506104466004803603610100811015610c6e57600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060808101359060a08101359060c08101359060e00135611e19565b348015610cbc57600080fd5b5061053460048036036020811015610cd357600080fd5b5035611f40565b348015610ce657600080fd5b50610534612060565b348015610cfb57600080fd5b50610534612067565b348015610d1057600080fd5b5061071561206e565b61044660048036036020811015610d2f57600080fd5b503561207e565b348015610d4257600080fd5b50610715612193565b348015610d5757600080fd5b5061044660048036036020811015610d6e57600080fd5b50356001600160a01b03166121a3565b348015610d8a57600080fd5b5061053461224e565b348015610d9f57600080fd5b50610534612255565b348015610db457600080fd5b50610446600480360360e0811015610dcb57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135612279565b348015610e1257600080fd5b50610715612466565b348015610e2757600080fd5b506104466004803603610100811015610e3f57600080fd5b508035906001600160a01b03602082013581169160408101359160608201359160808101359160a08201359160c08101359160e09091013516612476565b348015610e8957600080fd5b5061044660048036036040811015610ea057600080fd5b50803590602001356001600160a01b0316612578565b348015610ec257600080fd5b5061053460048036036040811015610ed957600080fd5b506001600160a01b0381358116916020013516612677565b348015610efd57600080fd5b506107156126a2565b348015610f1257600080fd5b506105346126b2565b60408051808201909152600c81526b2b34b9b4b7b7102a37b5b2b760a11b60208201525b90565b609b5460009060ff1615610f90576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610f9a8383612768565b90505b92915050565b60355490565b7faf42a244b3020d6a2253d9f291b4d3e82240da42b22129a8113a58aa7a3ddb6a81565b609b5460009060ff161561101b576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b61102684848461277c565b90505b9392505050565b6101a15481565b42841015611076576040805162461bcd60e51b81526020600482015260076024820152661156141254915160ca1b604482015290519081900360640190fd5b6001600160a01b0380891660008181526101a9602090815260408083208054600180820190925582517faf42a244b3020d6a2253d9f291b4d3e82240da42b22129a8113a58aa7a3ddb6a8186015280840196909652958d166060860152608085018c905260a085018b905260c085019590955260e08085018a905281518086039091018152610100850182528051908301206101aa5461190160f01b6101208701526101228601526101428086019190915281518086039091018152610162850180835281519184019190912090849052610182850180835281905260ff89166101a28601526101c285018890526101e285018790529051909492936102028082019392601f1981019281900390910190855afa15801561119b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906111d15750896001600160a01b0316816001600160a01b0316145b611216576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f5349474e415455524560781b604482015290519081900360640190fd5b6112228a8a8a8a612804565b50505050505050505050565b61019d546001600160a01b0316331461127d576040805162461bcd60e51b815260206004820152600c60248201526b434f4e54524f4c5f4f4e4c5960a01b604482015290519081900360640190fd5b60016101a854146112c8576040805162461bcd60e51b815260206004820152601060248201526f27a7262cafa1a0a6262fa4a72fa92aa760811b604482015290519081900360640190fd5b6101ae541561131e576040805162461bcd60e51b815260206004820152601960248201527f4f4e4c595f43414c4c5f49465f4e4f545f4155544f5f53455400000000000000604482015290519081900360640190fd5b4281111561136a576040805162461bcd60e51b81526020600482015260146024820152731110551157d35554d517d09157d25397d41054d560621b604482015290519081900360640190fd5b6101ae55565b60006101a654821015611385575060006114f6565b6000806101a854141561147a5782600061139d610fa3565b905060006113c161019b546101a15402836101a3546101a154010361019c54612aa8565b9050808311156113cf578092505b6113e58361019c5461019b546101a15402612aa8565b93508583146114725761019c54818703935060020261140a818563ffffffff612c3116565b6101a15461019b549195508002915061142a90829063ffffffff612c3116565b905061143c848263ffffffff612c8a16565b905061019b54818161144a57fe5b04905061145681612ce4565b6101a1549003905061146e858263ffffffff612c8a16565b9450505b5050506114f3565b60016101a85414156114e95760006101a35461019954611498610fa3565b010390506114b08461019c5460020261019b54612aa8565b91506114c48282800263ffffffff612c8a16565b91506114cf82612ce4565b91506114e1828263ffffffff612d5316565b9150506114f3565b60009150506114f6565b90505b919050565b604051469080605261554d82396052019050604051809103902061151d610f1b565b805160209182012060408051808201825260018152603360f81b90840152805180840194909452838101919091527f2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de606084015260808301939093523060a0808401919091528351808403909101815260c090920190925280519101206101aa55565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601290565b6101655490565b61019b5481565b6101aa5481565b61019a5461010090046001600160a01b031681565b609b5460009060ff1615611641576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610f9a8383612d95565b61165b611656612de9565b611808565b6116965760405162461bcd60e51b815260040180806020018281038252603081526020018061544a6030913960400191505060405180910390fd5b609b5460ff166116e4576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b609b805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa611717612de9565b604080516001600160a01b039092168252519081900360200190a1565b6000611746611741612de9565b611dfe565b6117815760405162461bcd60e51b81526004018080602001828103825260308152602001806154fc6030913960400191505060405180910390fd5b61178b8383612ded565b50600192915050565b6117a0338260006131db565b50565b6101a854600090600114156117ca576117bb34611a25565b90506117ca33823460016135f3565b6117d26136ed565b6040805182815290517fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf9181900360200190a150565b60006114f360688363ffffffff61389816565b604051806040016040528060018152602001603360f81b81525081565b6101995481565b6101ad5481565b61019c5481565b609b5460ff1690565b6101a75490565b611869338484846138ff565b505050565b61187e611879612de9565b613af1565b565b6001600160a01b031660009081526033602052604090205490565b6101a26020526000908152604090205481565b6118ec82336118e784604051806060016040528060248152602001615658602491396118da8833612677565b919063ffffffff613b3916565b613bd0565b6118f8828260006131db565b5050565b6101a96020526000908152604090205481565b61191a611656612de9565b6119555760405162461bcd60e51b815260040180806020018281038252603081526020018061544a6030913960400191505060405180910390fd5b6117a081613cbc565b611969611656612de9565b6119a45760405162461bcd60e51b815260040180806020018281038252603081526020018061544a6030913960400191505060405180910390fd5b609b5460ff16156119ef576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b609b805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611717612de9565b60008060016101a85414156114f3576000611a3e6126b2565b9050611a50818563ffffffff612d5316565b90506000611a5c610fa3565b9050611a748161019b54610199540261019c54612aa8565b9250611a89818261019b540261019c54612aa8565b83019250818311611a9d5760009250611aa3565b81830392505b50509050919050565b6101a65481565b610198546001600160a01b031681565b6040805180820190915260068152652b24a9a4a7a760d11b602082015290565b611aee611741612de9565b611b295760405162461bcd60e51b81526004018080602001828103825260308152602001806154fc6030913960400191505060405180910390fd5b6117a081613d04565b61187e611b3d612de9565b613d4d565b6101a45490565b6101ab5481565b609b5460009060ff1615611b9e576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610f9a8383613d96565b42841015611be7576040805162461bcd60e51b81526020600482015260076024820152661156141254915160ca1b604482015290519081900360640190fd5b6001600160a01b0380891660008181526101a9602090815260408083208054600180820190925582517f5dfdc7fb4c68a4c249de5e08597626b84fbbe7bfef4ed3500f58003e722cc5488186015280840196909652958d166060860152608085018c905260a085018b905260c085019590955260e08085018a905281518086039091018152610100850182528051908301206101aa5461190160f01b6101208701526101228601526101428086019190915281518086039091018152610162850180835281519184019190912090849052610182850180835281905260ff89166101a28601526101c285018890526101e285018790529051909492936102028082019392601f1981019281900390910190855afa158015611d0c573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611d425750896001600160a01b0316816001600160a01b0316145b611d87576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f5349474e415455524560781b604482015290519081900360640190fd5b6112228a8a8a8a6138ff565b61186933848484612804565b6101a35481565b609b5460009060ff1615611df4576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610f9a8383613e04565b60006114f36101008363ffffffff61389816565b6101ae5481565b611e2888888888888787613e18565b612710831115611e74576040805162461bcd60e51b81526020600482015260126024820152711253959053125117d0d3d35352551351539560721b604482015290519081900360640190fd5b6101a754831015611ecc576040805162461bcd60e51b815260206004820152601d60248201527f434f4d4d49544d454e545f4d41595f4e4f545f42455f52454455434544000000604482015290519081900360640190fd5b6101a7839055604080516001600160a01b038a8116825260208201869052818301879052606082018590526080820184905291518288169289811692908b16917fab33ca83001031840bf8a88b6a384c984aeb1ffcfebc562f13dab66a81306f969181900360a00190a45050505050505050565b600080611f4b6126b2565b9050600060016101a8541415611ffa57600061019954611f69610fa3565b019050611f95611f7f868563ffffffff612c3116565b610199548002611f8d610fa3565b848502614190565b91506000611fac866002860263ffffffff612c3116565b9050818181611fb757fe5b04928301929050611fda611fd1878063ffffffff612c3116565b8584850261433c565b905080831115611fee578083039250611ff3565b600092505b5050611029565b60026101a854141561203057612016848363ffffffff612c3116565b9050612020610fa3565b818161202857fe5b049050611029565b612040848363ffffffff612c3116565b90506101a35461204e610fa3565b03818161205757fe5b04949350505050565b6101a05481565b6101a85481565b6101ac546001600160a01b031681565b61208b33823460006135f3565b60016101a854146120d3576040805162461bcd60e51b815260206004820152600d60248201526c494e56414c49445f535441544560981b604482015290519081900360640190fd5b6000811161211b576040805162461bcd60e51b815260206004820152601060248201526f4d495353494e475f43555252454e435960801b604482015290519081900360640190fd5b60006121336101a75483612c3190919063ffffffff16565b61019a5461271090910491506121599061010090046001600160a01b0316828403614387565b60408051838152905133917f357b676c439b9e49b4410f8eb8680bee4223724802d8e3fd422e1756f87b475f919081900360200190a25050565b61019f546001600160a01b031681565b600054610100900460ff16806121bc57506121bc6143cb565b806121ca575060005460ff16155b6122055760405162461bcd60e51b815260040180806020018281038252602e81526020018061562a602e913960400191505060405180910390fd5b600054610100900460ff16158015612230576000805460ff1961ff0019909116610100171660011790555b612239826143d1565b80156118f8576000805461ff00191690555050565b6101ae5490565b7f5dfdc7fb4c68a4c249de5e08597626b84fbbe7bfef4ed3500f58003e722cc54881565b428410156122b8576040805162461bcd60e51b81526020600482015260076024820152661156141254915160ca1b604482015290519081900360640190fd5b6001600160a01b0380881660008181526101a9602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958c166060860152608085018b905260a085019590955260c08085018a90528151808603909101815260e0850182528051908301206101aa5461190160f01b6101008701526101028601526101228086019190915281518086039091018152610142850180835281519184019190912090849052610162850180835281905260ff89166101828601526101a285018890526101c285018790529051909492936101e28082019392601f1981019281900390910190855afa1580156123d5573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061240b5750886001600160a01b0316816001600160a01b0316145b612450576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f5349474e415455524560781b604482015290519081900360640190fd5b61245b898989613bd0565b505050505050505050565b61019d546001600160a01b031681565b61248588888888888787614474565b856124c6576101a8546040805191825260016020830152805160008051602061559f8339815191529281900390910190a160016101a855426101ae55612522565b6f4b3b4ca85a86c47a098a224000000000861061251b576040805162461bcd60e51b815260206004820152600e60248201526d115610d154d4d2559157d1d3d05360921b604482015290519081900360640190fd5b6101a18690555b61271083111561256b576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f5245534552564560881b604482015290519081900360640190fd5b50506101a4555050505050565b600054610100900460ff168061259157506125916143cb565b8061259f575060005460ff16155b6125da5760405162461bcd60e51b815260040180806020018281038252602e81526020018061562a602e913960400191505060405180910390fd5b600054610100900460ff16158015612605576000805460ff1961ff0019909116610100171660011790555b61260e826121a3565b6000831161265b576040805162461bcd60e51b8152602060048201526015602482015274045524332304361707065643a20636170206973203605c1b604482015290519081900360640190fd5b6101658390558015611869576000805461ff0019169055505050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b61019e546001600160a01b031681565b61019e5460009047906001600160a01b0316156127445761019e54604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b15801561271557600080fd5b505afa158015612729573d6000803e3d6000fd5b505050506040513d602081101561273f57600080fd5b505190505b6001600160801b03811115612763576001600160801b03915050610f3f565b905090565b600061178b612775612de9565b8484613bd0565b600061278984848461482e565b6127fa84612795612de9565b6118e7856040518060600160405280602881526020016155e0602891396001600160a01b038a166000908152603460205260408120906127d3612de9565b6001600160a01b03168152602081019190915260400160002054919063ffffffff613b3916565b5060019392505050565b6001600160a01b038316612851576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b6000811161289c576040805162461bcd60e51b81526020600482015260136024820152724d5553545f4255595f41545f4c454153545f3160681b604482015290519081900360640190fd5b60006128a783611370565b9050818110156128ef576040805162461bcd60e51b815260206004820152600e60248201526d50524943455f534c49505041474560901b604482015290519081900360640190fd5b836001600160a01b0316856001600160a01b03167f89f5adc174562e07c9c9b1cae7109bbecb21cf9d1b2847e550042b8653c54a0e8584604051808381526020018281526020019250505060405180910390a361294f85843460006135f3565b6101a854612a73576001600160a01b03841660009081526101a2602052604090208054820190556101a1546101a35482612987610fa3565b010310612a6e576101a8546040805191825260016020830152805160008051602061559f8339815191529281900390910190a160016101a8556101ae546129ce57426101ae555b61019a5461010090046001600160a01b031660009081526101a260205260408120546101a15461019b5461019c54612a0b93929190910290612aa8565b6101ab5490915015612a4c576101ac546101ab54612a32916001600160a01b031690614387565b6101ab54811115612a48576101ab549003612a4c565b5060005b612a6c612a6782612a5b6126b2565b9063ffffffff612d5316565b614b62565b505b612a97565b61019a546001600160a01b038581166101009092041614612a9757612a9783614b62565b612aa18482612ded565b5050505050565b6000831580612ab5575082155b15612ac257506000611029565b6000838560001981612ad057fe5b0410612aed5750838302828181612ae357fe5b0491506110299050565b838581811115612afd5750859050845b848281612b0657fe5b0492506305f5e100831115612b3057612b25838263ffffffff612c3116565b935061102992505050565b60001981016001600160801b038104600101905060001983016001600160801b0381046001019050808260001981612b6457fe5b0410612bd45790810290818481612b7757fe5b049450630bebc200851115612bd457612b96858463ffffffff612c3116565b9450506000198601818181612ba757fe5b049050612bbb81600163ffffffff612c8a16565b9050808581612bc657fe5b049550611029945050505050565b60016001600160801b03600019850104019150818381612bf057fe5b049450506000198601818181612c0257fe5b046001019050808481612c1157fe5b049050612c24858263ffffffff612c3116565b9998505050505050505050565b600082612c4057506000610f9d565b82820282848281612c4d57fe5b0414610f9a5760405162461bcd60e51b81526004018080602001828103825260218152602001806155bf6021913960400191505060405180910390fd5b600082820183811015610f9a576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600081612cf3575060006114f6565b60038211612d03575060016114f6565b600019821415612d1b57506001600160801b036114f6565b5080600260018201045b81811015612d4d57809150600281828581612d3c57fe5b040181612d4557fe5b049050612d25565b50919050565b6000610f9a83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613b39565b600061178b612da2612de9565b846118e78560346000612db3612de9565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff612c8a16565b3390565b610198546000908390839083906001600160a01b0316156130a157610198546040805163187601f760e21b81526001600160a01b038781166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b158015612e5857600080fd5b505af1158015612e6c573d6000803e3d6000fd5b505050506040513d6020811015612e8257600080fd5b5051158015612e9957506001600160a01b03841615155b8015612eb757506001600160a01b038316158015612eb5575080155b155b15612f245761019854604080516303e28f3760e01b81526001600160a01b038781166004830152915191909216916303e28f3791602480830192600092919082900301818387803b158015612f0b57600080fd5b505af1158015612f1f573d6000803e3d6000fd5b505050505b610198546040805163187601f760e21b81526001600160a01b038681166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b158015612f7457600080fd5b505af1158015612f88573d6000803e3d6000fd5b505050506040513d6020811015612f9e57600080fd5b5051158015612fb557506001600160a01b03831615155b156130225761019854604080516303e28f3760e01b81526001600160a01b038681166004830152915191909216916303e28f3791602480830192600092919082900301818387803b15801561300957600080fd5b505af115801561301d573d6000803e3d6000fd5b505050505b61019854604080516336dffedf60e01b81526001600160a01b0387811660048301528681166024830152604482018690528415156064830152915191909216916336dffedf91608480830192600092919082900301818387803b15801561308857600080fd5b505af115801561309c573d6000803e3d6000fd5b505050505b6130ab8686614be1565b6f4b3b4ca85a86c47a098a2240000000006130d7610199546130cb610fa3565b9063ffffffff612c8a16565b111561311d576040805162461bcd60e51b815260206004820152601060248201526f4558434553534956455f535550504c5960801b604482015290519081900360640190fd5b610198546001600160a01b0316156131d35761313884611880565b15801561314d57506001600160a01b03841615155b801561316b57506001600160a01b038316158015613169575080155b155b156131d3576101985460408051630b3ffd1d60e01b81526001600160a01b03878116600483015291519190921691630b3ffd1d91602480830192600092919082900301818387803b1580156131bf57600080fd5b505af1158015611222573d6000803e3d6000fd5b505050505050565b610198548390600090849084906001600160a01b03161561348f57610198546040805163187601f760e21b81526001600160a01b038781166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b15801561324657600080fd5b505af115801561325a573d6000803e3d6000fd5b505050506040513d602081101561327057600080fd5b505115801561328757506001600160a01b03841615155b80156132a557506001600160a01b0383161580156132a3575080155b155b156133125761019854604080516303e28f3760e01b81526001600160a01b038781166004830152915191909216916303e28f3791602480830192600092919082900301818387803b1580156132f957600080fd5b505af115801561330d573d6000803e3d6000fd5b505050505b610198546040805163187601f760e21b81526001600160a01b038681166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b15801561336257600080fd5b505af1158015613376573d6000803e3d6000fd5b505050506040513d602081101561338c57600080fd5b50511580156133a357506001600160a01b03831615155b156134105761019854604080516303e28f3760e01b81526001600160a01b038681166004830152915191909216916303e28f3791602480830192600092919082900301818387803b1580156133f757600080fd5b505af115801561340b573d6000803e3d6000fd5b505050505b61019854604080516336dffedf60e01b81526001600160a01b0387811660048301528681166024830152604482018690528415156064830152915191909216916336dffedf91608480830192600092919082900301818387803b15801561347657600080fd5b505af115801561348a573d6000803e3d6000fd5b505050505b6134998787614c4e565b8461352f5760016101a854146134e6576040805162461bcd60e51b815260206004820152600d60248201526c494e56414c49445f535441544560981b604482015290519081900360640190fd5b6101998054870190556040805187815290516001600160a01b038916917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5919081900360200190a25b610198546001600160a01b0316156135ea5761354a84611880565b15801561355f57506001600160a01b03841615155b801561357d57506001600160a01b03831615801561357b575080155b155b156135ea576101985460408051630b3ffd1d60e01b81526001600160a01b03878116600483015291519190921691630b3ffd1d91602480830192600092919082900301818387803b1580156135d157600080fd5b505af11580156135e5573d6000803e3d6000fd5b505050505b50505050505050565b61019e546001600160a01b031661368357801561363457600061361c838563ffffffff612d5316565b9050801561362e5761362e3382614d4a565b5061367e565b81831461367e576040805162461bcd60e51b8152602060048201526013602482015272494e434f52524543545f4d53475f56414c554560681b604482015290519081900360640190fd5b6136e7565b81156136c8576040805162461bcd60e51b815260206004820152600f60248201526e0889ebe9c9ea8bea68a9c88be8aa89608b1b604482015290519081900360640190fd5b61019e546136e7906001600160a01b031685308663ffffffff614e2f16565b50505050565b61019a5461010090046001600160a01b03163314613745576040805162461bcd60e51b815260206004820152601060248201526f42454e45464943494152595f4f4e4c5960801b604482015290519081900360640190fd5b6101a854613784576101a8546040805191825260036020830152805160008051602061559f8339815191529281900390910190a160036101a85561187e565b60016101a854141561385b576101ae546101ad5419116137db576040805162461bcd60e51b815260206004820152600d60248201526c4d41595f4e4f545f434c4f534560981b604482015290519081900360640190fd5b426101ae546101ad54011115613824576040805162461bcd60e51b8152602060048201526009602482015268544f4f5f4541524c5960b81b604482015290519081900360640190fd5b6101a8546040805191825260026020830152805160008051602061559f8339815191529281900390910190a160026101a85561187e565b6040805162461bcd60e51b815260206004820152600d60248201526c494e56414c49445f535441544560981b604482015290519081900360640190fd5b60006001600160a01b0382166138df5760405162461bcd60e51b81526004018080602001828103825260228152602001806156086022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b61019a546001600160a01b0385811661010090920416141580613926575060026101a85410155b6139615760405162461bcd60e51b815260040180806020018281038252602881526020018061567c6028913960400191505060405180910390fd5b600081116139ad576040805162461bcd60e51b81526020600482015260146024820152734d5553545f53454c4c5f41545f4c454153545f3160601b604482015290519081900360640190fd5b60006139b883611f40565b905081811015613a00576040805162461bcd60e51b815260206004820152600e60248201526d50524943455f534c49505041474560901b604482015290519081900360640190fd5b6101a8541580613a13575060036101a854145b15613a5d576001600160a01b03851660009081526101a26020526040902054613a42908463ffffffff612d5316565b6001600160a01b03861660009081526101a260205260409020555b613a69858460016131db565b600061019954613a77610fa3565b0190506101a354811015613a8c576101a38190555b613a968583614387565b846001600160a01b0316866001600160a01b03167fa082022e93cfcd9f1da5f9236718053910f7e840da080c789c7845698dc032ff8487604051808381526020018281526020019250505060405180910390a3505050505050565b613b0260688263ffffffff614e8916565b6040516001600160a01b038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b60008184841115613bc85760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613b8d578181015183820152602001613b75565b50505050905090810190601f168015613bba5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b038316613c155760405162461bcd60e51b81526004018080602001828103825260248152602001806156ea6024913960400191505060405180910390fd5b6001600160a01b038216613c5a5760405162461bcd60e51b815260040180806020018281038252602281526020018061547a6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260346020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b613ccd60688263ffffffff614ef016565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b613d166101008263ffffffff614ef016565b6040516001600160a01b038216907f6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f690600090a250565b613d5f6101008263ffffffff614e8916565b6040516001600160a01b038216907fe94479a9f7e1952cc78f2d6baab678adc1b772d936c6583def489e524cb6669290600090a250565b600061178b613da3612de9565b846118e7856040518060600160405280602581526020016157386025913960346000613dcd612de9565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff613b3916565b600061178b613e11612de9565b848461482e565b61019d546001600160a01b03163314613e67576040805162461bcd60e51b815260206004820152600c60248201526b434f4e54524f4c5f4f4e4c5960a01b604482015290519081900360640190fd5b61019880546001600160a01b0319166001600160a01b03898116919091179091558516613ecd576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b61019d80546001600160a01b0319166001600160a01b03878116919091179091558416613f33576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b61019f80546001600160a01b0319166001600160a01b038616179055612710831115613f94576040805162461bcd60e51b815260206004820152600b60248201526a494e56414c49445f46454560a81b604482015290519081900360640190fd5b6101a083905581613fe5576040805162461bcd60e51b81526020600482015260166024820152751253959053125117d3525397d253959154d51351539560521b604482015290519081900360640190fd5b6101a68290556101ad54811015614043576040805162461bcd60e51b815260206004820152601f60248201527f4d494e5f4455524154494f4e5f4d41595f4e4f545f42455f5245445543454400604482015290519081900360640190fd5b6101ad81905561019a546001600160a01b0387811661010090920416146135ea576001600160a01b0386166140b1576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b61019a546000906140cf9061010090046001600160a01b0316611880565b61019a546001600160a01b03610100909104811660009081526101a2602052604080822054928b16825290205491925061410f919063ffffffff612c8a16565b6001600160a01b0380891660009081526101a260205260408082209390935561019a54610100900490911681529081205580156141635761019a546141639061010090046001600160a01b0316888361482e565b5061019a80546001600160a01b03881661010002610100600160a81b031990911617905550505050505050565b600081836000198161419e57fe5b04106141b8576141b18585848602612aa8565b9050614334565b8415806141c3575083155b156141d057506000614334565b8183818111156141e05750839050825b60008688600019816141ee57fe5b0410614219575086860281818161420157fe5b04905082818161420d57fe5b04935061433492505050565b8688818111156142295750889050875b600084838161423457fe5b049050630bebc20081111561425b5761424e818388612aa8565b9650505050505050614334565b506001600160801b03600019838101829004600190810192848301040190829082908161428457fe5b04106142ff57810280848161429557fe5b049450630bebc2008511156142ff576142b4858463ffffffff612c3116565b94508585816142bf57fe5b0494506000851180156142dd57508085600019816142d957fe5b0410155b156142ff57938402938685816142ef57fe5b0497506143349650505050505050565b5050600160801b85046001600160801b038504810261432a81858161432057fe5b0484600019612aa8565b9750505050505050505b949350505050565b60008061434a858585612aa8565b90508061435b576001915050611029565b60016305f5e10060001983010401811981111561437e5760001992505050611029565b01949350505050565b80156118f85761019e546001600160a01b03166143ad576143a88282614d4a565b6118f8565b61019e546118f8906001600160a01b0316838363ffffffff614f7116565b303b1590565b600054610100900460ff16806143ea57506143ea6143cb565b806143f8575060005460ff16155b6144335760405162461bcd60e51b815260040180806020018281038252602e81526020018061562a602e913960400191505060405180910390fd5b600054610100900460ff1615801561445e576000805460ff1961ff0019909116610100171660011790555b61446782611dfe565b6122395761223982613d04565b6144896a0422ca8b0a00a42500000033612578565b61449233613cbc565b600084116144db576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f534c4f50455f4e554d60781b604482015290519081900360640190fd5b60008311614524576040805162461bcd60e51b815260206004820152601160248201527024a72b20a624a22fa9a627a822afa222a760791b604482015290519081900360640190fd5b6001600160801b038410614575576040805162461bcd60e51b81526020600482015260136024820152724558434553534956455f534c4f50455f4e554d60681b604482015290519081900360640190fd5b6001600160801b0383106145c6576040805162461bcd60e51b815260206004820152601360248201527222ac21a2a9a9a4ab22afa9a627a822afa222a760691b604482015290519081900360640190fd5b61019b84905561019c8390558115806145e757506001600160a01b03811615155b614638576040805162461bcd60e51b815260206004820152601b60248201527f4d495353494e475f53455455505f4645455f524543495049454e540000000000604482015290519081900360640190fd5b6001600160a01b038116158061464d57508115155b614692576040805162461bcd60e51b81526020600482015260116024820152704d495353494e475f53455455505f46454560781b604482015290519081900360640190fd5b8480026146a5818663ffffffff612c3116565b90508360020281816146b357fe5b04905080831115614701576040805162461bcd60e51b81526020600482015260136024820152724558434553534956455f53455455505f46454560681b604482015290519081900360640190fd5b6101ab8390556101ac80546001600160a01b0319166001600160a01b038481169190911790915560129088161561479d57876001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561476b57600080fd5b505afa15801561477f573d6000803e3d6000fd5b505050506040513d602081101561479557600080fd5b505160ff1690505b600a81900a6064026101a65561019a8054610100600160a81b0319163361010081029190911790915561019d80546001600160a01b0319908116831790915561019f8054821690921790915561019e80549091166001600160a01b038a161790558815614826576101a389905561019a546148269061010090046001600160a01b03168a612ded565b61245b6114fb565b610198548390839083906000906001600160a01b031615614ae257610198546040805163187601f760e21b81526001600160a01b038781166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b15801561489957600080fd5b505af11580156148ad573d6000803e3d6000fd5b505050506040513d60208110156148c357600080fd5b50511580156148da57506001600160a01b03841615155b80156148f857506001600160a01b0383161580156148f6575080155b155b156149655761019854604080516303e28f3760e01b81526001600160a01b038781166004830152915191909216916303e28f3791602480830192600092919082900301818387803b15801561494c57600080fd5b505af1158015614960573d6000803e3d6000fd5b505050505b610198546040805163187601f760e21b81526001600160a01b038681166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b1580156149b557600080fd5b505af11580156149c9573d6000803e3d6000fd5b505050506040513d60208110156149df57600080fd5b50511580156149f657506001600160a01b03831615155b15614a635761019854604080516303e28f3760e01b81526001600160a01b038681166004830152915191909216916303e28f3791602480830192600092919082900301818387803b158015614a4a57600080fd5b505af1158015614a5e573d6000803e3d6000fd5b505050505b61019854604080516336dffedf60e01b81526001600160a01b0387811660048301528681166024830152604482018690528415156064830152915191909216916336dffedf91608480830192600092919082900301818387803b158015614ac957600080fd5b505af1158015614add573d6000803e3d6000fd5b505050505b6101a854151580614b06575061019a546001600160a01b0388811661010090920416145b614b57576040805162461bcd60e51b815260206004820152601c60248201527f4f4e4c595f42454e45464943494152595f445552494e475f494e495400000000604482015290519081900360640190fd5b61352f878787614fc3565b6101a454600090614b79908363ffffffff612c3116565b61271090049050614b8a8282612d53565b90506000614ba46101a05483612c3190919063ffffffff16565b61019a546127109091049150614bca9061010090046001600160a01b0316828403614387565b61019f54611869906001600160a01b031682614387565b61016554614bf1826130cb610fa3565b1115614c44576040805162461bcd60e51b815260206004820152601960248201527f45524332304361707065643a2063617020657863656564656400000000000000604482015290519081900360640190fd5b6118f88282615121565b6001600160a01b038216614c935760405162461bcd60e51b81526004018080602001828103825260218152602001806156a46021913960400191505060405180910390fd5b614cd681604051806060016040528060228152602001615428602291396001600160a01b038516600090815260336020526040902054919063ffffffff613b3916565b6001600160a01b038316600090815260336020526040902055603554614d02908263ffffffff612d5316565b6035556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b80471015614d9f576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d8060008114614dea576040519150601f19603f3d011682016040523d82523d6000602084013e614def565b606091505b50509050806118695760405162461bcd60e51b815260040180806020018281038252603a8152602001806154c2603a913960400191505060405180910390fd5b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526136e7908590615213565b614e938282613898565b614ece5760405162461bcd60e51b815260040180806020018281038252602181526020018061552c6021913960400191505060405180910390fd5b6001600160a01b0316600090815260209190915260409020805460ff19169055565b614efa8282613898565b15614f4c576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611869908490615213565b6001600160a01b0383166150085760405162461bcd60e51b81526004018080602001828103825260258152602001806156c56025913960400191505060405180910390fd5b6001600160a01b03821661504d5760405162461bcd60e51b81526004018080602001828103825260238152602001806154056023913960400191505060405180910390fd5b6150908160405180606001604052806026815260200161549c602691396001600160a01b038616600090815260336020526040902054919063ffffffff613b3916565b6001600160a01b0380851660009081526033602052604080822093909355908416815220546150c5908263ffffffff612c8a16565b6001600160a01b0380841660008181526033602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6001600160a01b03821661517c576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b60355461518f908263ffffffff612c8a16565b6035556001600160a01b0382166000908152603360205260409020546151bb908263ffffffff612c8a16565b6001600160a01b03831660008181526033602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b615225826001600160a01b03166153cb565b615276576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106152b45780518252601f199092019160209182019101615295565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114615316576040519150601f19603f3d011682016040523d82523d6000602084013e61531b565b606091505b509150915081615372576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b8051156136e75780806020019051602081101561538e57600080fd5b50516136e75760405162461bcd60e51b815260040180806020018281038252602a81526020018061570e602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061433457505015159291505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e6365506175736572526f6c653a2063616c6c657220646f6573206e6f742068617665207468652050617573657220726f6c6545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d617920686176652072657665727465644d696e746572526f6c653a2063616c6c657220646f6573206e6f74206861766520746865204d696e74657220726f6c65526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c65454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429107dddb4541735557564238389eccfc9979bfdde5e57e24e9777b6fe79b4d22f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365526f6c65733a206163636f756e7420697320746865207a65726f2061646472657373436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a656445524332303a206275726e20616d6f756e74206578636565647320616c6c6f77616e636542454e45464943494152595f4f4e4c595f53454c4c5f494e5f434c4f53455f4f525f43414e43454c45524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a723158203f15b98e3dbe20b7002f3cf3d64568f40a6db9746000ff689c31c40a9f4bb62864736f6c63430005110032

Deployed Bytecode

0x6080604052600436106103ef5760003560e01c806382dc1ec411610208578063af575ab711610118578063c7159307116100ab578063d9cce5261161007a578063d9cce52614610e1b578063da35a26f14610e7d578063dd62ed3e14610eb6578063e5a6b10f14610ef1578063ff90956014610f06576103ef565b8063c715930714610d7e578063d29157fb14610d93578063d505accf14610da8578063d8de658714610e06576103ef565b8063c25b25bd116100e7578063c25b25bd14610d04578063c290d69114610d19578063c415b95c14610d36578063c4d66de814610d4b576103ef565b8063af575ab714610c4a578063b12f415314610cb0578063b8606eef14610cda578063c19d93fb14610cef576103ef565b80639df3f4f61161019b578063a59ac6dd1161016a578063a59ac6dd14610b82578063a71ddd2514610bb4578063a9059cbb14610bc9578063aa271e1a14610c02578063ad3b763314610c35576103ef565b80639df3f4f614610aba578063a40b56b914610acf578063a457c2d714610ae4578063a551bfc414610b1d576103ef565b806393e59dc1116101d757806393e59dc114610a4857806395d89b4114610a5d578063983b2d5614610a725780639865027514610aa5576103ef565b806382dc1ec4146109c15780638456cb59146109f4578063896d170814610a095780638ac2c68014610a33576103ef565b80633f4ba83a1161030357806358439fa5116102965780636ef8d66d116102655780636ef8d66d146108da57806370a08231146108ef578063736dcb1f1461092257806379cc6790146109555780637ecebe001461098e576103ef565b806358439fa51461085c5780635c975abb146108715780636177e37c146108865780636a2724621461089b576103ef565b806346fbf68e116102d257806346fbf68e146107ea57806354fd4d501461081d57806355d0a1d0146108325780635671576114610847576103ef565b80633f4ba83a1461076a57806340c10f191461077f57806342966c68146107b857806343d726d6146107e2576103ef565b80632e872bb311610386578063355274ea11610355578063355274ea146106c157806335e5cc31146106d65780633644e515146106eb57806338af3eed146107005780633950935114610731576103ef565b80632e872bb3146106425780632ff791611461066c57806330adf81f14610681578063313ce56714610696576103ef565b806323b872dd116103c257806323b872dd1461055b578063263154381461059e578063270588ee146105b35780632973434a14610618576103ef565b806306fdde0314610448578063095ea7b3146104d257806318160ddd1461051f5780631d833ec514610546575b61019e546001600160a01b031615610446576040805162461bcd60e51b815260206004820152601560248201527409e9c98b2be8c9ea4be86aaa4a48a9c86b2be8aa89605b1b604482015290519081900360640190fd5b005b34801561045457600080fd5b5061045d610f1b565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561049757818101518382015260200161047f565b50505050905090810190601f1680156104c45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104de57600080fd5b5061050b600480360360408110156104f557600080fd5b506001600160a01b038135169060200135610f42565b604080519115158252519081900360200190f35b34801561052b57600080fd5b50610534610fa3565b60408051918252519081900360200190f35b34801561055257600080fd5b50610534610fa9565b34801561056757600080fd5b5061050b6004803603606081101561057e57600080fd5b506001600160a01b03813581169160208101359091169060400135610fcd565b3480156105aa57600080fd5b50610534611030565b3480156105bf57600080fd5b5061044660048036036101008110156105d757600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060ff60a0820135169060c08101359060e00135611037565b34801561062457600080fd5b506104466004803603602081101561063b57600080fd5b503561122e565b34801561064e57600080fd5b506105346004803603602081101561066557600080fd5b5035611370565b34801561067857600080fd5b506104466114fb565b34801561068d57600080fd5b506105346115a0565b3480156106a257600080fd5b506106ab6115c4565b6040805160ff9092168252519081900360200190f35b3480156106cd57600080fd5b506105346115c9565b3480156106e257600080fd5b506105346115d0565b3480156106f757600080fd5b506105346115d7565b34801561070c57600080fd5b506107156115de565b604080516001600160a01b039092168252519081900360200190f35b34801561073d57600080fd5b5061050b6004803603604081101561075457600080fd5b506001600160a01b0381351690602001356115f3565b34801561077657600080fd5b5061044661164b565b34801561078b57600080fd5b5061050b600480360360408110156107a257600080fd5b506001600160a01b038135169060200135611734565b3480156107c457600080fd5b50610446600480360360208110156107db57600080fd5b5035611794565b6104466117a3565b3480156107f657600080fd5b5061050b6004803603602081101561080d57600080fd5b50356001600160a01b0316611808565b34801561082957600080fd5b5061045d61181b565b34801561083e57600080fd5b50610534611838565b34801561085357600080fd5b5061053461183f565b34801561086857600080fd5b50610534611846565b34801561087d57600080fd5b5061050b61184d565b34801561089257600080fd5b50610534611856565b3480156108a757600080fd5b50610446600480360360608110156108be57600080fd5b506001600160a01b03813516906020810135906040013561185d565b3480156108e657600080fd5b5061044661186e565b3480156108fb57600080fd5b506105346004803603602081101561091257600080fd5b50356001600160a01b0316611880565b34801561092e57600080fd5b506105346004803603602081101561094557600080fd5b50356001600160a01b031661189b565b34801561096157600080fd5b506104466004803603604081101561097857600080fd5b506001600160a01b0381351690602001356118ae565b34801561099a57600080fd5b50610534600480360360208110156109b157600080fd5b50356001600160a01b03166118fc565b3480156109cd57600080fd5b50610446600480360360208110156109e457600080fd5b50356001600160a01b031661190f565b348015610a0057600080fd5b5061044661195e565b348015610a1557600080fd5b5061053460048036036020811015610a2c57600080fd5b5035611a25565b348015610a3f57600080fd5b50610534611aac565b348015610a5457600080fd5b50610715611ab3565b348015610a6957600080fd5b5061045d611ac3565b348015610a7e57600080fd5b5061044660048036036020811015610a9557600080fd5b50356001600160a01b0316611ae3565b348015610ab157600080fd5b50610446611b32565b348015610ac657600080fd5b50610534611b42565b348015610adb57600080fd5b50610534611b49565b348015610af057600080fd5b5061050b60048036036040811015610b0757600080fd5b506001600160a01b038135169060200135611b50565b348015610b2957600080fd5b506104466004803603610100811015610b4157600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060ff60a0820135169060c08101359060e00135611ba8565b61044660048036036060811015610b9857600080fd5b506001600160a01b038135169060208101359060400135611d93565b348015610bc057600080fd5b50610534611d9f565b348015610bd557600080fd5b5061050b60048036036040811015610bec57600080fd5b506001600160a01b038135169060200135611da6565b348015610c0e57600080fd5b5061050b60048036036020811015610c2557600080fd5b50356001600160a01b0316611dfe565b348015610c4157600080fd5b50610534611e12565b348015610c5657600080fd5b506104466004803603610100811015610c6e57600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060808101359060a08101359060c08101359060e00135611e19565b348015610cbc57600080fd5b5061053460048036036020811015610cd357600080fd5b5035611f40565b348015610ce657600080fd5b50610534612060565b348015610cfb57600080fd5b50610534612067565b348015610d1057600080fd5b5061071561206e565b61044660048036036020811015610d2f57600080fd5b503561207e565b348015610d4257600080fd5b50610715612193565b348015610d5757600080fd5b5061044660048036036020811015610d6e57600080fd5b50356001600160a01b03166121a3565b348015610d8a57600080fd5b5061053461224e565b348015610d9f57600080fd5b50610534612255565b348015610db457600080fd5b50610446600480360360e0811015610dcb57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135612279565b348015610e1257600080fd5b50610715612466565b348015610e2757600080fd5b506104466004803603610100811015610e3f57600080fd5b508035906001600160a01b03602082013581169160408101359160608201359160808101359160a08201359160c08101359160e09091013516612476565b348015610e8957600080fd5b5061044660048036036040811015610ea057600080fd5b50803590602001356001600160a01b0316612578565b348015610ec257600080fd5b5061053460048036036040811015610ed957600080fd5b506001600160a01b0381358116916020013516612677565b348015610efd57600080fd5b506107156126a2565b348015610f1257600080fd5b506105346126b2565b60408051808201909152600c81526b2b34b9b4b7b7102a37b5b2b760a11b60208201525b90565b609b5460009060ff1615610f90576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610f9a8383612768565b90505b92915050565b60355490565b7faf42a244b3020d6a2253d9f291b4d3e82240da42b22129a8113a58aa7a3ddb6a81565b609b5460009060ff161561101b576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b61102684848461277c565b90505b9392505050565b6101a15481565b42841015611076576040805162461bcd60e51b81526020600482015260076024820152661156141254915160ca1b604482015290519081900360640190fd5b6001600160a01b0380891660008181526101a9602090815260408083208054600180820190925582517faf42a244b3020d6a2253d9f291b4d3e82240da42b22129a8113a58aa7a3ddb6a8186015280840196909652958d166060860152608085018c905260a085018b905260c085019590955260e08085018a905281518086039091018152610100850182528051908301206101aa5461190160f01b6101208701526101228601526101428086019190915281518086039091018152610162850180835281519184019190912090849052610182850180835281905260ff89166101a28601526101c285018890526101e285018790529051909492936102028082019392601f1981019281900390910190855afa15801561119b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906111d15750896001600160a01b0316816001600160a01b0316145b611216576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f5349474e415455524560781b604482015290519081900360640190fd5b6112228a8a8a8a612804565b50505050505050505050565b61019d546001600160a01b0316331461127d576040805162461bcd60e51b815260206004820152600c60248201526b434f4e54524f4c5f4f4e4c5960a01b604482015290519081900360640190fd5b60016101a854146112c8576040805162461bcd60e51b815260206004820152601060248201526f27a7262cafa1a0a6262fa4a72fa92aa760811b604482015290519081900360640190fd5b6101ae541561131e576040805162461bcd60e51b815260206004820152601960248201527f4f4e4c595f43414c4c5f49465f4e4f545f4155544f5f53455400000000000000604482015290519081900360640190fd5b4281111561136a576040805162461bcd60e51b81526020600482015260146024820152731110551157d35554d517d09157d25397d41054d560621b604482015290519081900360640190fd5b6101ae55565b60006101a654821015611385575060006114f6565b6000806101a854141561147a5782600061139d610fa3565b905060006113c161019b546101a15402836101a3546101a154010361019c54612aa8565b9050808311156113cf578092505b6113e58361019c5461019b546101a15402612aa8565b93508583146114725761019c54818703935060020261140a818563ffffffff612c3116565b6101a15461019b549195508002915061142a90829063ffffffff612c3116565b905061143c848263ffffffff612c8a16565b905061019b54818161144a57fe5b04905061145681612ce4565b6101a1549003905061146e858263ffffffff612c8a16565b9450505b5050506114f3565b60016101a85414156114e95760006101a35461019954611498610fa3565b010390506114b08461019c5460020261019b54612aa8565b91506114c48282800263ffffffff612c8a16565b91506114cf82612ce4565b91506114e1828263ffffffff612d5316565b9150506114f3565b60009150506114f6565b90505b919050565b604051469080605261554d82396052019050604051809103902061151d610f1b565b805160209182012060408051808201825260018152603360f81b90840152805180840194909452838101919091527f2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de606084015260808301939093523060a0808401919091528351808403909101815260c090920190925280519101206101aa55565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601290565b6101655490565b61019b5481565b6101aa5481565b61019a5461010090046001600160a01b031681565b609b5460009060ff1615611641576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610f9a8383612d95565b61165b611656612de9565b611808565b6116965760405162461bcd60e51b815260040180806020018281038252603081526020018061544a6030913960400191505060405180910390fd5b609b5460ff166116e4576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b609b805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa611717612de9565b604080516001600160a01b039092168252519081900360200190a1565b6000611746611741612de9565b611dfe565b6117815760405162461bcd60e51b81526004018080602001828103825260308152602001806154fc6030913960400191505060405180910390fd5b61178b8383612ded565b50600192915050565b6117a0338260006131db565b50565b6101a854600090600114156117ca576117bb34611a25565b90506117ca33823460016135f3565b6117d26136ed565b6040805182815290517fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf9181900360200190a150565b60006114f360688363ffffffff61389816565b604051806040016040528060018152602001603360f81b81525081565b6101995481565b6101ad5481565b61019c5481565b609b5460ff1690565b6101a75490565b611869338484846138ff565b505050565b61187e611879612de9565b613af1565b565b6001600160a01b031660009081526033602052604090205490565b6101a26020526000908152604090205481565b6118ec82336118e784604051806060016040528060248152602001615658602491396118da8833612677565b919063ffffffff613b3916565b613bd0565b6118f8828260006131db565b5050565b6101a96020526000908152604090205481565b61191a611656612de9565b6119555760405162461bcd60e51b815260040180806020018281038252603081526020018061544a6030913960400191505060405180910390fd5b6117a081613cbc565b611969611656612de9565b6119a45760405162461bcd60e51b815260040180806020018281038252603081526020018061544a6030913960400191505060405180910390fd5b609b5460ff16156119ef576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b609b805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611717612de9565b60008060016101a85414156114f3576000611a3e6126b2565b9050611a50818563ffffffff612d5316565b90506000611a5c610fa3565b9050611a748161019b54610199540261019c54612aa8565b9250611a89818261019b540261019c54612aa8565b83019250818311611a9d5760009250611aa3565b81830392505b50509050919050565b6101a65481565b610198546001600160a01b031681565b6040805180820190915260068152652b24a9a4a7a760d11b602082015290565b611aee611741612de9565b611b295760405162461bcd60e51b81526004018080602001828103825260308152602001806154fc6030913960400191505060405180910390fd5b6117a081613d04565b61187e611b3d612de9565b613d4d565b6101a45490565b6101ab5481565b609b5460009060ff1615611b9e576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610f9a8383613d96565b42841015611be7576040805162461bcd60e51b81526020600482015260076024820152661156141254915160ca1b604482015290519081900360640190fd5b6001600160a01b0380891660008181526101a9602090815260408083208054600180820190925582517f5dfdc7fb4c68a4c249de5e08597626b84fbbe7bfef4ed3500f58003e722cc5488186015280840196909652958d166060860152608085018c905260a085018b905260c085019590955260e08085018a905281518086039091018152610100850182528051908301206101aa5461190160f01b6101208701526101228601526101428086019190915281518086039091018152610162850180835281519184019190912090849052610182850180835281905260ff89166101a28601526101c285018890526101e285018790529051909492936102028082019392601f1981019281900390910190855afa158015611d0c573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611d425750896001600160a01b0316816001600160a01b0316145b611d87576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f5349474e415455524560781b604482015290519081900360640190fd5b6112228a8a8a8a6138ff565b61186933848484612804565b6101a35481565b609b5460009060ff1615611df4576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610f9a8383613e04565b60006114f36101008363ffffffff61389816565b6101ae5481565b611e2888888888888787613e18565b612710831115611e74576040805162461bcd60e51b81526020600482015260126024820152711253959053125117d0d3d35352551351539560721b604482015290519081900360640190fd5b6101a754831015611ecc576040805162461bcd60e51b815260206004820152601d60248201527f434f4d4d49544d454e545f4d41595f4e4f545f42455f52454455434544000000604482015290519081900360640190fd5b6101a7839055604080516001600160a01b038a8116825260208201869052818301879052606082018590526080820184905291518288169289811692908b16917fab33ca83001031840bf8a88b6a384c984aeb1ffcfebc562f13dab66a81306f969181900360a00190a45050505050505050565b600080611f4b6126b2565b9050600060016101a8541415611ffa57600061019954611f69610fa3565b019050611f95611f7f868563ffffffff612c3116565b610199548002611f8d610fa3565b848502614190565b91506000611fac866002860263ffffffff612c3116565b9050818181611fb757fe5b04928301929050611fda611fd1878063ffffffff612c3116565b8584850261433c565b905080831115611fee578083039250611ff3565b600092505b5050611029565b60026101a854141561203057612016848363ffffffff612c3116565b9050612020610fa3565b818161202857fe5b049050611029565b612040848363ffffffff612c3116565b90506101a35461204e610fa3565b03818161205757fe5b04949350505050565b6101a05481565b6101a85481565b6101ac546001600160a01b031681565b61208b33823460006135f3565b60016101a854146120d3576040805162461bcd60e51b815260206004820152600d60248201526c494e56414c49445f535441544560981b604482015290519081900360640190fd5b6000811161211b576040805162461bcd60e51b815260206004820152601060248201526f4d495353494e475f43555252454e435960801b604482015290519081900360640190fd5b60006121336101a75483612c3190919063ffffffff16565b61019a5461271090910491506121599061010090046001600160a01b0316828403614387565b60408051838152905133917f357b676c439b9e49b4410f8eb8680bee4223724802d8e3fd422e1756f87b475f919081900360200190a25050565b61019f546001600160a01b031681565b600054610100900460ff16806121bc57506121bc6143cb565b806121ca575060005460ff16155b6122055760405162461bcd60e51b815260040180806020018281038252602e81526020018061562a602e913960400191505060405180910390fd5b600054610100900460ff16158015612230576000805460ff1961ff0019909116610100171660011790555b612239826143d1565b80156118f8576000805461ff00191690555050565b6101ae5490565b7f5dfdc7fb4c68a4c249de5e08597626b84fbbe7bfef4ed3500f58003e722cc54881565b428410156122b8576040805162461bcd60e51b81526020600482015260076024820152661156141254915160ca1b604482015290519081900360640190fd5b6001600160a01b0380881660008181526101a9602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958c166060860152608085018b905260a085019590955260c08085018a90528151808603909101815260e0850182528051908301206101aa5461190160f01b6101008701526101028601526101228086019190915281518086039091018152610142850180835281519184019190912090849052610162850180835281905260ff89166101828601526101a285018890526101c285018790529051909492936101e28082019392601f1981019281900390910190855afa1580156123d5573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061240b5750886001600160a01b0316816001600160a01b0316145b612450576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f5349474e415455524560781b604482015290519081900360640190fd5b61245b898989613bd0565b505050505050505050565b61019d546001600160a01b031681565b61248588888888888787614474565b856124c6576101a8546040805191825260016020830152805160008051602061559f8339815191529281900390910190a160016101a855426101ae55612522565b6f4b3b4ca85a86c47a098a224000000000861061251b576040805162461bcd60e51b815260206004820152600e60248201526d115610d154d4d2559157d1d3d05360921b604482015290519081900360640190fd5b6101a18690555b61271083111561256b576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f5245534552564560881b604482015290519081900360640190fd5b50506101a4555050505050565b600054610100900460ff168061259157506125916143cb565b8061259f575060005460ff16155b6125da5760405162461bcd60e51b815260040180806020018281038252602e81526020018061562a602e913960400191505060405180910390fd5b600054610100900460ff16158015612605576000805460ff1961ff0019909116610100171660011790555b61260e826121a3565b6000831161265b576040805162461bcd60e51b8152602060048201526015602482015274045524332304361707065643a20636170206973203605c1b604482015290519081900360640190fd5b6101658390558015611869576000805461ff0019169055505050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b61019e546001600160a01b031681565b61019e5460009047906001600160a01b0316156127445761019e54604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b15801561271557600080fd5b505afa158015612729573d6000803e3d6000fd5b505050506040513d602081101561273f57600080fd5b505190505b6001600160801b03811115612763576001600160801b03915050610f3f565b905090565b600061178b612775612de9565b8484613bd0565b600061278984848461482e565b6127fa84612795612de9565b6118e7856040518060600160405280602881526020016155e0602891396001600160a01b038a166000908152603460205260408120906127d3612de9565b6001600160a01b03168152602081019190915260400160002054919063ffffffff613b3916565b5060019392505050565b6001600160a01b038316612851576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b6000811161289c576040805162461bcd60e51b81526020600482015260136024820152724d5553545f4255595f41545f4c454153545f3160681b604482015290519081900360640190fd5b60006128a783611370565b9050818110156128ef576040805162461bcd60e51b815260206004820152600e60248201526d50524943455f534c49505041474560901b604482015290519081900360640190fd5b836001600160a01b0316856001600160a01b03167f89f5adc174562e07c9c9b1cae7109bbecb21cf9d1b2847e550042b8653c54a0e8584604051808381526020018281526020019250505060405180910390a361294f85843460006135f3565b6101a854612a73576001600160a01b03841660009081526101a2602052604090208054820190556101a1546101a35482612987610fa3565b010310612a6e576101a8546040805191825260016020830152805160008051602061559f8339815191529281900390910190a160016101a8556101ae546129ce57426101ae555b61019a5461010090046001600160a01b031660009081526101a260205260408120546101a15461019b5461019c54612a0b93929190910290612aa8565b6101ab5490915015612a4c576101ac546101ab54612a32916001600160a01b031690614387565b6101ab54811115612a48576101ab549003612a4c565b5060005b612a6c612a6782612a5b6126b2565b9063ffffffff612d5316565b614b62565b505b612a97565b61019a546001600160a01b038581166101009092041614612a9757612a9783614b62565b612aa18482612ded565b5050505050565b6000831580612ab5575082155b15612ac257506000611029565b6000838560001981612ad057fe5b0410612aed5750838302828181612ae357fe5b0491506110299050565b838581811115612afd5750859050845b848281612b0657fe5b0492506305f5e100831115612b3057612b25838263ffffffff612c3116565b935061102992505050565b60001981016001600160801b038104600101905060001983016001600160801b0381046001019050808260001981612b6457fe5b0410612bd45790810290818481612b7757fe5b049450630bebc200851115612bd457612b96858463ffffffff612c3116565b9450506000198601818181612ba757fe5b049050612bbb81600163ffffffff612c8a16565b9050808581612bc657fe5b049550611029945050505050565b60016001600160801b03600019850104019150818381612bf057fe5b049450506000198601818181612c0257fe5b046001019050808481612c1157fe5b049050612c24858263ffffffff612c3116565b9998505050505050505050565b600082612c4057506000610f9d565b82820282848281612c4d57fe5b0414610f9a5760405162461bcd60e51b81526004018080602001828103825260218152602001806155bf6021913960400191505060405180910390fd5b600082820183811015610f9a576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600081612cf3575060006114f6565b60038211612d03575060016114f6565b600019821415612d1b57506001600160801b036114f6565b5080600260018201045b81811015612d4d57809150600281828581612d3c57fe5b040181612d4557fe5b049050612d25565b50919050565b6000610f9a83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613b39565b600061178b612da2612de9565b846118e78560346000612db3612de9565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff612c8a16565b3390565b610198546000908390839083906001600160a01b0316156130a157610198546040805163187601f760e21b81526001600160a01b038781166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b158015612e5857600080fd5b505af1158015612e6c573d6000803e3d6000fd5b505050506040513d6020811015612e8257600080fd5b5051158015612e9957506001600160a01b03841615155b8015612eb757506001600160a01b038316158015612eb5575080155b155b15612f245761019854604080516303e28f3760e01b81526001600160a01b038781166004830152915191909216916303e28f3791602480830192600092919082900301818387803b158015612f0b57600080fd5b505af1158015612f1f573d6000803e3d6000fd5b505050505b610198546040805163187601f760e21b81526001600160a01b038681166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b158015612f7457600080fd5b505af1158015612f88573d6000803e3d6000fd5b505050506040513d6020811015612f9e57600080fd5b5051158015612fb557506001600160a01b03831615155b156130225761019854604080516303e28f3760e01b81526001600160a01b038681166004830152915191909216916303e28f3791602480830192600092919082900301818387803b15801561300957600080fd5b505af115801561301d573d6000803e3d6000fd5b505050505b61019854604080516336dffedf60e01b81526001600160a01b0387811660048301528681166024830152604482018690528415156064830152915191909216916336dffedf91608480830192600092919082900301818387803b15801561308857600080fd5b505af115801561309c573d6000803e3d6000fd5b505050505b6130ab8686614be1565b6f4b3b4ca85a86c47a098a2240000000006130d7610199546130cb610fa3565b9063ffffffff612c8a16565b111561311d576040805162461bcd60e51b815260206004820152601060248201526f4558434553534956455f535550504c5960801b604482015290519081900360640190fd5b610198546001600160a01b0316156131d35761313884611880565b15801561314d57506001600160a01b03841615155b801561316b57506001600160a01b038316158015613169575080155b155b156131d3576101985460408051630b3ffd1d60e01b81526001600160a01b03878116600483015291519190921691630b3ffd1d91602480830192600092919082900301818387803b1580156131bf57600080fd5b505af1158015611222573d6000803e3d6000fd5b505050505050565b610198548390600090849084906001600160a01b03161561348f57610198546040805163187601f760e21b81526001600160a01b038781166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b15801561324657600080fd5b505af115801561325a573d6000803e3d6000fd5b505050506040513d602081101561327057600080fd5b505115801561328757506001600160a01b03841615155b80156132a557506001600160a01b0383161580156132a3575080155b155b156133125761019854604080516303e28f3760e01b81526001600160a01b038781166004830152915191909216916303e28f3791602480830192600092919082900301818387803b1580156132f957600080fd5b505af115801561330d573d6000803e3d6000fd5b505050505b610198546040805163187601f760e21b81526001600160a01b038681166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b15801561336257600080fd5b505af1158015613376573d6000803e3d6000fd5b505050506040513d602081101561338c57600080fd5b50511580156133a357506001600160a01b03831615155b156134105761019854604080516303e28f3760e01b81526001600160a01b038681166004830152915191909216916303e28f3791602480830192600092919082900301818387803b1580156133f757600080fd5b505af115801561340b573d6000803e3d6000fd5b505050505b61019854604080516336dffedf60e01b81526001600160a01b0387811660048301528681166024830152604482018690528415156064830152915191909216916336dffedf91608480830192600092919082900301818387803b15801561347657600080fd5b505af115801561348a573d6000803e3d6000fd5b505050505b6134998787614c4e565b8461352f5760016101a854146134e6576040805162461bcd60e51b815260206004820152600d60248201526c494e56414c49445f535441544560981b604482015290519081900360640190fd5b6101998054870190556040805187815290516001600160a01b038916917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5919081900360200190a25b610198546001600160a01b0316156135ea5761354a84611880565b15801561355f57506001600160a01b03841615155b801561357d57506001600160a01b03831615801561357b575080155b155b156135ea576101985460408051630b3ffd1d60e01b81526001600160a01b03878116600483015291519190921691630b3ffd1d91602480830192600092919082900301818387803b1580156135d157600080fd5b505af11580156135e5573d6000803e3d6000fd5b505050505b50505050505050565b61019e546001600160a01b031661368357801561363457600061361c838563ffffffff612d5316565b9050801561362e5761362e3382614d4a565b5061367e565b81831461367e576040805162461bcd60e51b8152602060048201526013602482015272494e434f52524543545f4d53475f56414c554560681b604482015290519081900360640190fd5b6136e7565b81156136c8576040805162461bcd60e51b815260206004820152600f60248201526e0889ebe9c9ea8bea68a9c88be8aa89608b1b604482015290519081900360640190fd5b61019e546136e7906001600160a01b031685308663ffffffff614e2f16565b50505050565b61019a5461010090046001600160a01b03163314613745576040805162461bcd60e51b815260206004820152601060248201526f42454e45464943494152595f4f4e4c5960801b604482015290519081900360640190fd5b6101a854613784576101a8546040805191825260036020830152805160008051602061559f8339815191529281900390910190a160036101a85561187e565b60016101a854141561385b576101ae546101ad5419116137db576040805162461bcd60e51b815260206004820152600d60248201526c4d41595f4e4f545f434c4f534560981b604482015290519081900360640190fd5b426101ae546101ad54011115613824576040805162461bcd60e51b8152602060048201526009602482015268544f4f5f4541524c5960b81b604482015290519081900360640190fd5b6101a8546040805191825260026020830152805160008051602061559f8339815191529281900390910190a160026101a85561187e565b6040805162461bcd60e51b815260206004820152600d60248201526c494e56414c49445f535441544560981b604482015290519081900360640190fd5b60006001600160a01b0382166138df5760405162461bcd60e51b81526004018080602001828103825260228152602001806156086022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b61019a546001600160a01b0385811661010090920416141580613926575060026101a85410155b6139615760405162461bcd60e51b815260040180806020018281038252602881526020018061567c6028913960400191505060405180910390fd5b600081116139ad576040805162461bcd60e51b81526020600482015260146024820152734d5553545f53454c4c5f41545f4c454153545f3160601b604482015290519081900360640190fd5b60006139b883611f40565b905081811015613a00576040805162461bcd60e51b815260206004820152600e60248201526d50524943455f534c49505041474560901b604482015290519081900360640190fd5b6101a8541580613a13575060036101a854145b15613a5d576001600160a01b03851660009081526101a26020526040902054613a42908463ffffffff612d5316565b6001600160a01b03861660009081526101a260205260409020555b613a69858460016131db565b600061019954613a77610fa3565b0190506101a354811015613a8c576101a38190555b613a968583614387565b846001600160a01b0316866001600160a01b03167fa082022e93cfcd9f1da5f9236718053910f7e840da080c789c7845698dc032ff8487604051808381526020018281526020019250505060405180910390a3505050505050565b613b0260688263ffffffff614e8916565b6040516001600160a01b038216907fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e90600090a250565b60008184841115613bc85760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613b8d578181015183820152602001613b75565b50505050905090810190601f168015613bba5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b038316613c155760405162461bcd60e51b81526004018080602001828103825260248152602001806156ea6024913960400191505060405180910390fd5b6001600160a01b038216613c5a5760405162461bcd60e51b815260040180806020018281038252602281526020018061547a6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260346020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b613ccd60688263ffffffff614ef016565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b613d166101008263ffffffff614ef016565b6040516001600160a01b038216907f6ae172837ea30b801fbfcdd4108aa1d5bf8ff775444fd70256b44e6bf3dfc3f690600090a250565b613d5f6101008263ffffffff614e8916565b6040516001600160a01b038216907fe94479a9f7e1952cc78f2d6baab678adc1b772d936c6583def489e524cb6669290600090a250565b600061178b613da3612de9565b846118e7856040518060600160405280602581526020016157386025913960346000613dcd612de9565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff613b3916565b600061178b613e11612de9565b848461482e565b61019d546001600160a01b03163314613e67576040805162461bcd60e51b815260206004820152600c60248201526b434f4e54524f4c5f4f4e4c5960a01b604482015290519081900360640190fd5b61019880546001600160a01b0319166001600160a01b03898116919091179091558516613ecd576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b61019d80546001600160a01b0319166001600160a01b03878116919091179091558416613f33576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b61019f80546001600160a01b0319166001600160a01b038616179055612710831115613f94576040805162461bcd60e51b815260206004820152600b60248201526a494e56414c49445f46454560a81b604482015290519081900360640190fd5b6101a083905581613fe5576040805162461bcd60e51b81526020600482015260166024820152751253959053125117d3525397d253959154d51351539560521b604482015290519081900360640190fd5b6101a68290556101ad54811015614043576040805162461bcd60e51b815260206004820152601f60248201527f4d494e5f4455524154494f4e5f4d41595f4e4f545f42455f5245445543454400604482015290519081900360640190fd5b6101ad81905561019a546001600160a01b0387811661010090920416146135ea576001600160a01b0386166140b1576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b61019a546000906140cf9061010090046001600160a01b0316611880565b61019a546001600160a01b03610100909104811660009081526101a2602052604080822054928b16825290205491925061410f919063ffffffff612c8a16565b6001600160a01b0380891660009081526101a260205260408082209390935561019a54610100900490911681529081205580156141635761019a546141639061010090046001600160a01b0316888361482e565b5061019a80546001600160a01b03881661010002610100600160a81b031990911617905550505050505050565b600081836000198161419e57fe5b04106141b8576141b18585848602612aa8565b9050614334565b8415806141c3575083155b156141d057506000614334565b8183818111156141e05750839050825b60008688600019816141ee57fe5b0410614219575086860281818161420157fe5b04905082818161420d57fe5b04935061433492505050565b8688818111156142295750889050875b600084838161423457fe5b049050630bebc20081111561425b5761424e818388612aa8565b9650505050505050614334565b506001600160801b03600019838101829004600190810192848301040190829082908161428457fe5b04106142ff57810280848161429557fe5b049450630bebc2008511156142ff576142b4858463ffffffff612c3116565b94508585816142bf57fe5b0494506000851180156142dd57508085600019816142d957fe5b0410155b156142ff57938402938685816142ef57fe5b0497506143349650505050505050565b5050600160801b85046001600160801b038504810261432a81858161432057fe5b0484600019612aa8565b9750505050505050505b949350505050565b60008061434a858585612aa8565b90508061435b576001915050611029565b60016305f5e10060001983010401811981111561437e5760001992505050611029565b01949350505050565b80156118f85761019e546001600160a01b03166143ad576143a88282614d4a565b6118f8565b61019e546118f8906001600160a01b0316838363ffffffff614f7116565b303b1590565b600054610100900460ff16806143ea57506143ea6143cb565b806143f8575060005460ff16155b6144335760405162461bcd60e51b815260040180806020018281038252602e81526020018061562a602e913960400191505060405180910390fd5b600054610100900460ff1615801561445e576000805460ff1961ff0019909116610100171660011790555b61446782611dfe565b6122395761223982613d04565b6144896a0422ca8b0a00a42500000033612578565b61449233613cbc565b600084116144db576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f534c4f50455f4e554d60781b604482015290519081900360640190fd5b60008311614524576040805162461bcd60e51b815260206004820152601160248201527024a72b20a624a22fa9a627a822afa222a760791b604482015290519081900360640190fd5b6001600160801b038410614575576040805162461bcd60e51b81526020600482015260136024820152724558434553534956455f534c4f50455f4e554d60681b604482015290519081900360640190fd5b6001600160801b0383106145c6576040805162461bcd60e51b815260206004820152601360248201527222ac21a2a9a9a4ab22afa9a627a822afa222a760691b604482015290519081900360640190fd5b61019b84905561019c8390558115806145e757506001600160a01b03811615155b614638576040805162461bcd60e51b815260206004820152601b60248201527f4d495353494e475f53455455505f4645455f524543495049454e540000000000604482015290519081900360640190fd5b6001600160a01b038116158061464d57508115155b614692576040805162461bcd60e51b81526020600482015260116024820152704d495353494e475f53455455505f46454560781b604482015290519081900360640190fd5b8480026146a5818663ffffffff612c3116565b90508360020281816146b357fe5b04905080831115614701576040805162461bcd60e51b81526020600482015260136024820152724558434553534956455f53455455505f46454560681b604482015290519081900360640190fd5b6101ab8390556101ac80546001600160a01b0319166001600160a01b038481169190911790915560129088161561479d57876001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561476b57600080fd5b505afa15801561477f573d6000803e3d6000fd5b505050506040513d602081101561479557600080fd5b505160ff1690505b600a81900a6064026101a65561019a8054610100600160a81b0319163361010081029190911790915561019d80546001600160a01b0319908116831790915561019f8054821690921790915561019e80549091166001600160a01b038a161790558815614826576101a389905561019a546148269061010090046001600160a01b03168a612ded565b61245b6114fb565b610198548390839083906000906001600160a01b031615614ae257610198546040805163187601f760e21b81526001600160a01b038781166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b15801561489957600080fd5b505af11580156148ad573d6000803e3d6000fd5b505050506040513d60208110156148c357600080fd5b50511580156148da57506001600160a01b03841615155b80156148f857506001600160a01b0383161580156148f6575080155b155b156149655761019854604080516303e28f3760e01b81526001600160a01b038781166004830152915191909216916303e28f3791602480830192600092919082900301818387803b15801561494c57600080fd5b505af1158015614960573d6000803e3d6000fd5b505050505b610198546040805163187601f760e21b81526001600160a01b038681166004830152915191909216916361d807dc9160248083019260209291908290030181600087803b1580156149b557600080fd5b505af11580156149c9573d6000803e3d6000fd5b505050506040513d60208110156149df57600080fd5b50511580156149f657506001600160a01b03831615155b15614a635761019854604080516303e28f3760e01b81526001600160a01b038681166004830152915191909216916303e28f3791602480830192600092919082900301818387803b158015614a4a57600080fd5b505af1158015614a5e573d6000803e3d6000fd5b505050505b61019854604080516336dffedf60e01b81526001600160a01b0387811660048301528681166024830152604482018690528415156064830152915191909216916336dffedf91608480830192600092919082900301818387803b158015614ac957600080fd5b505af1158015614add573d6000803e3d6000fd5b505050505b6101a854151580614b06575061019a546001600160a01b0388811661010090920416145b614b57576040805162461bcd60e51b815260206004820152601c60248201527f4f4e4c595f42454e45464943494152595f445552494e475f494e495400000000604482015290519081900360640190fd5b61352f878787614fc3565b6101a454600090614b79908363ffffffff612c3116565b61271090049050614b8a8282612d53565b90506000614ba46101a05483612c3190919063ffffffff16565b61019a546127109091049150614bca9061010090046001600160a01b0316828403614387565b61019f54611869906001600160a01b031682614387565b61016554614bf1826130cb610fa3565b1115614c44576040805162461bcd60e51b815260206004820152601960248201527f45524332304361707065643a2063617020657863656564656400000000000000604482015290519081900360640190fd5b6118f88282615121565b6001600160a01b038216614c935760405162461bcd60e51b81526004018080602001828103825260218152602001806156a46021913960400191505060405180910390fd5b614cd681604051806060016040528060228152602001615428602291396001600160a01b038516600090815260336020526040902054919063ffffffff613b3916565b6001600160a01b038316600090815260336020526040902055603554614d02908263ffffffff612d5316565b6035556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b80471015614d9f576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d8060008114614dea576040519150601f19603f3d011682016040523d82523d6000602084013e614def565b606091505b50509050806118695760405162461bcd60e51b815260040180806020018281038252603a8152602001806154c2603a913960400191505060405180910390fd5b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526136e7908590615213565b614e938282613898565b614ece5760405162461bcd60e51b815260040180806020018281038252602181526020018061552c6021913960400191505060405180910390fd5b6001600160a01b0316600090815260209190915260409020805460ff19169055565b614efa8282613898565b15614f4c576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611869908490615213565b6001600160a01b0383166150085760405162461bcd60e51b81526004018080602001828103825260258152602001806156c56025913960400191505060405180910390fd5b6001600160a01b03821661504d5760405162461bcd60e51b81526004018080602001828103825260238152602001806154056023913960400191505060405180910390fd5b6150908160405180606001604052806026815260200161549c602691396001600160a01b038616600090815260336020526040902054919063ffffffff613b3916565b6001600160a01b0380851660009081526033602052604080822093909355908416815220546150c5908263ffffffff612c8a16565b6001600160a01b0380841660008181526033602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6001600160a01b03821661517c576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b60355461518f908263ffffffff612c8a16565b6035556001600160a01b0382166000908152603360205260409020546151bb908263ffffffff612c8a16565b6001600160a01b03831660008181526033602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b615225826001600160a01b03166153cb565b615276576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106152b45780518252601f199092019160209182019101615295565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114615316576040519150601f19603f3d011682016040523d82523d6000602084013e61531b565b606091505b509150915081615372576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b8051156136e75780806020019051602081101561538e57600080fd5b50516136e75760405162461bcd60e51b815260040180806020018281038252602a81526020018061570e602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061433457505015159291505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e6365506175736572526f6c653a2063616c6c657220646f6573206e6f742068617665207468652050617573657220726f6c6545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d617920686176652072657665727465644d696e746572526f6c653a2063616c6c657220646f6573206e6f74206861766520746865204d696e74657220726f6c65526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c65454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429107dddb4541735557564238389eccfc9979bfdde5e57e24e9777b6fe79b4d22f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365526f6c65733a206163636f756e7420697320746865207a65726f2061646472657373436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a656445524332303a206275726e20616d6f756e74206578636565647320616c6c6f77616e636542454e45464943494152595f4f4e4c595f53454c4c5f494e5f434c4f53455f4f525f43414e43454c45524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a723158203f15b98e3dbe20b7002f3cf3d64568f40a6db9746000ff689c31c40a9f4bb62864736f6c63430005110032

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.