Contract 0x845856776D110a200Cf41f35C9428C938e72E604 2

 
 
Txn Hash
Method
Block
From
To
Value
0x1abb951bf3c447cf76a22a48bbd0b5df4cbb9c4d9c1842712c5b87eb4adc94e80x6080604099878312020-05-02 16:25:19950 days 16 hrs ago0xc4b60a931929d3ed0ac423f9ea80e5962726da73 IN  Create: DecentralizedAutonomousTrust0 Ether0.0353041910
[ Download CSV Export 
View more zero value Internal Transactions in Advanced View mode
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DecentralizedAutonomousTrust

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-05-04
*/

// File: contracts/interfaces/IWhitelist.sol

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;
}

// File: @openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol

pragma solidity ^0.5.0;

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

// File: contracts/math/BigDiv.sol

pragma solidity ^0.5.0;


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

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

  /// @notice When multiplying 2 terms <= this value the result won't overflow
  uint256 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
  uint256 private constant MAX_ERROR = 100000000;

  /// @notice A larger error threshold to use when multiple rounding errors may apply
  uint256 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(
    uint256 _numA,
    uint256 _numB,
    uint256 _den
  ) internal pure
    returns(uint256)
  {
    if(_numA == 0 || _numB == 0)
    {
      // would div by 0 or underflow if we don't special case 0
      return 0;
    }

    uint256 value;

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

    // Sort numerators
    uint256 numMax = _numB;
    uint256 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))
    uint256 factor = numMin - 1;
    factor /= MAX_BEFORE_SQUARE;
    factor += 1;
    uint256 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(
    uint256 _numA,
    uint256 _numB,
    uint256 _den
  ) internal pure
    returns(uint256)
  {
    // first get the rounded down result
    uint256 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
    uint256 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(
    uint256 _numA,
    uint256 _numB,
    uint256 _denA,
    uint256 _denB
  ) internal pure
    returns (uint256)
  {
    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
    uint256 denMax = _denB;
    uint256 denMin = _denA;
    if(_denA > _denB)
    {
      denMax = _denA;
      denMin = _denB;
    }

    uint256 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
    uint256 numMax = _numB;
    uint256 numMin = _numA;
    if(_numA > _numB)
    {
      numMax = _numA;
      numMin = _numB;
    }

    // formula = (a/d) * b / c
    uint256 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))
    uint256 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);
  }
}

// File: contracts/math/Sqrt.sol

pragma solidity ^0.5.0;


/**
 * @title Calculates the square root of a given value.
 * @dev Results may be off by 1.
 */
library Sqrt
{
  /// @notice The max possible value
  uint256 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;
    }
  }
}

// File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol

pragma solidity ^0.5.0;

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

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

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

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

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

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

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

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

// File: @openzeppelin/contracts-ethereum-package/contracts/utils/Address.sol

pragma solidity ^0.5.5;

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

// File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/SafeERC20.sol

pragma solidity ^0.5.0;




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

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

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

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

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

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "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");
        }
    }
}

// File: @openzeppelin/upgrades/contracts/Initializable.sol

pragma solidity >=0.4.24 <0.7.0;


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

// File: @openzeppelin/contracts-ethereum-package/contracts/GSN/Context.sol

pragma solidity ^0.5.0;


/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context 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;
    }
}

// File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol

pragma solidity ^0.5.0;





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

// File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Detailed.sol

pragma solidity ^0.5.0;



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

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

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

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

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

    uint256[50] private ______gap;
}

// File: contracts/DecentralizedAutonomousTrust.sol

pragma solidity 0.5.17;











/**
 * @title Decentralized Autonomous Trust
 * This contract is a modified version of the 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.
 * Code from : https://github.com/Fairmint/c-org/blob/dfd3129f9bce8717406aba54d1f1888d8e253dbb/contracts/DecentralizedAutonomousTrust.sol
 * Changes Added: https://github.com/Fairmint/c-org/commit/60bb63b9112a82996f275a75a87c28b1d73e3f11
 *
 * Use at your own risk. 
 */
contract DecentralizedAutonomousTrust
  is ERC20, ERC20Detailed
{
  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 Pay(
    address indexed _from,
    address indexed _to,
    uint _currencyValue,
    uint _fairValue
  );
  event Close(
    uint _exitFee
  );
  event StateChange(
    uint _previousState,
    uint _newState
  );
  event UpdateConfig(
    address _whitelistAddress,
    address indexed _beneficiary,
    address indexed _control,
    address indexed _feeCollector,
    bool _autoBurn,
    uint _revenueCommitmentBasisPoints,
    uint _feeBasisPoints,
    uint _minInvestment,
    uint _openUntilAtLeast
  );

  /**
   * Constants
   */

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

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

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

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

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

  /// @notice The denominator component for values specified in basis points.
  uint private 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 private 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 COT tokens, excluding tokens burned from a `Sell` action in the DAT.
  uint public burnedSupply;

  /**
   * Data for DAT business logic
   */

  /// @notice Set if the COTs minted by the organization when it commits its revenues are
  /// automatically burnt (`true`) or not (`false`). Defaults to `false` meaning that there
  /// is no automatic burn.
  bool public 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 COT.
  /// @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 COT.
  /// @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 COT are issued expressed in basis points.
  uint public feeBasisPoints;

  /// @notice The initial fundraising goal (expressed in COT) 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 COT 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 COTs.
  /// @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.
  uint public investmentReserveBasisPoints;

  /// @notice The earliest date/time (in seconds) that the DAT may enter the `CLOSE` state, ensuring
  /// that if the DAT reaches the `RUN` state it will remain running for at least this period of time.
  /// @dev This value may be increased anytime by the control account
  uint public openUntilAtLeast;

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

  /// @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.
  uint public revenueCommitmentBasisPoints;

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

  string public constant version = "2";
  // --- EIP712 niceties ---
  // Original source: https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f#code
  mapping (address => uint) public nonces;
  bytes32 public DOMAIN_SEPARATOR;
  // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)");
  bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb;

  modifier authorizeTransfer(
    address _from,
    address _to,
    uint _value,
    bool _isSell
  )
  {
    if(address(whitelist) != address(0))
    {
      // This is not set for the minting of initialReserve
      whitelist.authorizeTransfer(_from, _to, _value, _isSell);
    }
    _;
  }

  /**
   * 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 for the whitelist
   */

  function _detectTransferRestriction(
    address _from,
    address _to,
    uint _value
  ) private view
    returns (uint)
  {
    if(address(whitelist) != address(0))
    {
      // This is not set for the minting of initialReserve
      return whitelist.detectTransferRestriction(_from, _to, _value);
    }

    return 0;
  }

  /**
   * 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, "ONLY_DURING_RUN");
      // 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(
    uint _quantityToInvest,
    uint _msgValue,
    bool _refundRemainder
  ) private
  {
    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(msg.sender, address(this), _quantityToInvest);
    }
  }

  /// @dev Send `_amount` currency from the contract to the `_to` account.
  function _transferCurrency(
    address payable _to,
    uint _amount
  ) private
  {
    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 _investmentReserveBasisPoints,
    string memory _name,
    string memory _symbol
  ) public
  {
    require(control == address(0), "ALREADY_INITIALIZED");

    ERC20Detailed.initialize(_name, _symbol, 18);

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

    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;
    // 100% or less
    require(_investmentReserveBasisPoints <= BASIS_POINTS_DEN, "INVALID_RESERVE");
    investmentReserveBasisPoints = _investmentReserveBasisPoints;

    // Set default values (which may be updated using `updateConfig`)
    minInvestment = 100 ether;
    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);
    }

    // Initialize permit
    DOMAIN_SEPARATOR = keccak256(
      abi.encode(
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
        keccak256(bytes(name())),
        keccak256(bytes(version)),
        getChainId(),
        address(this)
      )
    );
  }
  function getChainId(
  ) private pure
    returns (uint id)
  {
    // solium-disable-next-line
    assembly
    {
      id := chainid()
    }
  }

  function updateConfig(
    address _whitelistAddress,
    address payable _beneficiary,
    address _control,
    address payable _feeCollector,
    uint _feeBasisPoints,
    bool _autoBurn,
    uint _revenueCommitmentBasisPoints,
    uint _minInvestment,
    uint _openUntilAtLeast
  ) public
  {
    // 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;

    autoBurn = _autoBurn;

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

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

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

    require(_openUntilAtLeast >= openUntilAtLeast, "OPEN_UNTIL_MAY_NOT_BE_REDUCED");
    openUntilAtLeast = _openUntilAtLeast;

    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;
    }

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

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

  // Buy

  /// @dev Distributes _value currency between the buybackReserve, beneficiary, and feeCollector.
  function _distributeInvestment(
    uint _value
  ) private
  {
    // 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);
  }

  /// @notice Calculate how many COT 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 COT.
  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)/2
      // n/d: buy_slope (MAX_BEFORE_SQUARE / MAX_BEFORE_SQUARE)
      // g: init_goal (MAX_BEFORE_SQUARE/2)
      // t: total_supply (MAX_BEFORE_SQUARE/2)
      // r: init_reserve (MAX_BEFORE_SQUARE/2)
      // source: ((n/d)*g)*(g+r-t)/2
      // impl: (g n (g + r - t))/(2 d)
      uint max = BigDiv.bigDiv2x1(
        initGoal * buySlopeNum,
        initGoal + initReserve - _totalSupply,
        2 * buySlopeDen
      );
      if(currencyValue > max)
      {
        currencyValue = max;
      }
      // Math: worst case
      // MAX * 2 * MAX_BEFORE_SQUARE
      // / MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE
      tokenValue = BigDiv.bigDiv2x1(
        currencyValue,
        2 * 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;
  }

  /// @notice Purchase COT tokens with the given amount of currency.
  /// @param _to The account to receive the COT tokens from this purchase.
  /// @param _currencyValue How much currency to spend in order to buy COT.
  /// @param _minTokensBought Buy at least this many COT 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
  {
    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(msg.sender, _to, _currencyValue, tokenValue);

    _collectInvestment(_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;
        // Math worst case:
        // MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE * MAX_BEFORE_SQUARE/2
        // / MAX_BEFORE_SQUARE * 2
        uint beneficiaryContribution = BigDiv.bigDiv2x1(
          initInvestors[beneficiary],
          buySlopeNum * initGoal,
          buySlopeDen * 2
        );
        _distributeInvestment(buybackReserve().sub(beneficiaryContribution));
      }
    }
    else // implied: if(state == STATE_RUN)
    {
      if(_to != beneficiary)
      {
        _distributeInvestment(_currencyValue);
      }
    }

    _mint(_to, tokenValue);

    if(state == STATE_RUN && msg.sender == beneficiary && _to == beneficiary && autoBurn)
    {
      // must mint before this call
      _burn(beneficiary, tokenValue, false);
    }
  }

  /// 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 COT 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
      currencyValue -= BigDiv.bigDiv2x1RoundUp(
        _quantityToSell.mul(_quantityToSell),
        reserve,
        supply * supply
      );
    }
    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: COT blocks initReserve from being burned unless we reach the RUN state which prevents an underflow
      currencyValue /= totalSupply() - initReserve;
    }

    return currencyValue;
  }

  /// @notice Sell COT tokens for at least the given amount of currency.
  /// @param _to The account to receive the currency from this sale.
  /// @param _quantityToSell How many COT 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
  {
    require(msg.sender != 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[msg.sender] = initInvestors[msg.sender].sub(_quantityToSell);
    }

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

    _transferCurrency(_to, currencyValue);
    emit Sell(msg.sender, _to, currencyValue, _quantityToSell);
  }

  /// Pay

  function estimatePayValue(
    uint _currencyValue
  ) public view
    returns (uint)
  {
    // buy_slope = n/d
    // revenue_commitment = c/g
    // sqrt(
    //  (2 a c d)
    //  /
    //  (g n)
    //  + s^2
    // ) - s

    uint supply = totalSupply() + burnedSupply;

    // Math: worst case
    // MAX * 2 * 10000 * MAX_BEFORE_SQUARE
    // / 10000 * MAX_BEFORE_SQUARE
    uint tokenValue = BigDiv.bigDiv2x1(
      _currencyValue.mul(2 * revenueCommitmentBasisPoints),
      buySlopeDen,
      BASIS_POINTS_DEN * buySlopeNum
    );

    tokenValue = tokenValue.add(supply * supply);
    tokenValue = tokenValue.sqrt();

    if(tokenValue > supply)
    {
      tokenValue -= supply;
    }
    else
    {
      tokenValue = 0;
    }

    return tokenValue;
  }

  /// @dev Pay the organization on-chain.
  /// @param _to The account which receives tokens for the contribution.
  /// @param _currencyValue How much currency which was paid.
  function _pay(
    address _to,
    uint _currencyValue
  ) private
  {
    require(_currencyValue > 0, "MISSING_CURRENCY");
    require(state == STATE_RUN, "INVALID_STATE");

    // 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(investmentReserveBasisPoints);
    reserve /= BASIS_POINTS_DEN;

    uint tokenValue = estimatePayValue(_currencyValue);

    // Update the to address to the beneficiary if the currency value would fail
    address to = _to;
    if(to == address(0))
    {
      to = beneficiary;
    }
    else if(_detectTransferRestriction(address(0), _to, tokenValue) != 0)
    {
      to = beneficiary;
    }

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

    // Distribute tokens
    if(tokenValue > 0)
    {
      _mint(to, tokenValue);
      if(to == beneficiary && autoBurn)
      {
        // must mint before this call
        _burn(beneficiary, tokenValue, false);
      }
    }

    emit Pay(msg.sender, _to, _currencyValue, tokenValue);
  }

  /// @dev Pay the organization on-chain.
  /// @param _to The account which receives tokens for the contribution. If this address
  /// is not authorized to receive tokens then they will be sent to the beneficiary account instead.
  /// @param _currencyValue How much currency which was paid.
  function pay(
    address _to,
    uint _currencyValue
  ) public payable
  {
    _collectInvestment(_currencyValue, msg.value, false);
    _pay(_to, _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");
  }
  
  /// 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
  {
    require(msg.sender == beneficiary, "BENEFICIARY_ONLY");

    uint exitFee = 0;

    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(openUntilAtLeast <= block.timestamp, "TOO_EARLY");

      exitFee = estimateExitFee(msg.value);

      emit StateChange(state, STATE_CLOSE);
      state = STATE_CLOSE;

      _collectInvestment(exitFee, msg.value, true);
    }
    else
    {
      revert("INVALID_STATE");
    }

    emit Close(exitFee);
  }

  // --- Approve by signature ---
  // Original source: https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f#code
  function permit(
    address holder,
    address spender,
    uint256 nonce,
    uint256 expiry,
    bool allowed,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) external
  {
    bytes32 digest = keccak256(
      abi.encodePacked(
        "\x19\x01",
        DOMAIN_SEPARATOR,
        keccak256(
          abi.encode(PERMIT_TYPEHASH,
                    holder,
                    spender,
                    nonce,
                    expiry,
                    allowed
          )
        )
      )
    );

    require(holder != address(0), "DAT/invalid-address-0");
    require(holder == ecrecover(digest, v, r, s), "DAT/invalid-permit");
    require(expiry == 0 || now <= expiry, "DAT/permit-expired");
    require(nonce == nonces[holder]++, "DAT/invalid-nonce");
    uint wad = allowed ? uint(-1) : 0;
    _approve(holder, spender, wad);
  }
}

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":"_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":"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":"_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":"bool","name":"_autoBurn","type":"bool"},{"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":"_openUntilAtLeast","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_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","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":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"autoBurn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","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":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":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":"_currencyValue","type":"uint256"}],"name":"estimatePayValue","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":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"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":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"initialize","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":[],"name":"minInvestment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","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":true,"inputs":[],"name":"openUntilAtLeast","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"}],"name":"pay","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"bool","name":"allowed","type":"bool"},{"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":true,"inputs":[],"name":"revenueCommitmentBasisPoints","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":"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":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"bool","name":"_autoBurn","type":"bool"},{"internalType":"uint256","name":"_revenueCommitmentBasisPoints","type":"uint256"},{"internalType":"uint256","name":"_minInvestment","type":"uint256"},{"internalType":"uint256","name":"_openUntilAtLeast","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"}]

6080604052613ee4806100136000396000f3fe6080604052600436106102885760003560e01c806370a082311161015a578063a71ddd25116100c1578063c415b95c1161007a578063c415b95c14610bfd578063d8de658714610c12578063dcf81d1714610c27578063dd62ed3e14610c3c578063e5a6b10f14610c77578063ff90956014610c8c57610288565b8063a71ddd2514610b2f578063a9059cbb14610b44578063b12f415314610b7d578063b8606eef14610ba7578063c19d93fb14610bbc578063c407687614610bd157610288565b806393e59dc11161011357806393e59dc114610a7057806395d89b4114610a855780639df3f4f614610a9a578063a457c2d714610aaf578063a59ac6dd14610ae8578063a63b91f414610b1a57610288565b806370a0823114610931578063736dcb1f146109645780637ecebe0014610997578063896d1708146109ca5780638ac2c680146109f45780638fcbaf0c14610a0957610288565b80633644e515116101fe5780634f3424df116101b75780634f3424df1461087457806354fd4d501461089e57806355d0a1d0146108b357806358439fa5146108c85780636177e37c146108dd5780636a272462146108f257610288565b80633644e5151461075457806338af3eed14610769578063395093511461079a57806342966c68146107d3578063438f45a3146107fd57806343d726d61461086c57610288565b806323b872dd1161025057806323b872dd1461067d57806326315438146106c05780632e872bb3146106d557806330adf81f146106ff578063313ce5671461071457806335e5cc311461073f57610288565b806306fdde03146102e0578063095ea7b31461036a5780631624f6c6146103b757806318160ddd146104f257806321dfb63314610519575b60a3546001600160a01b0316156102de576040805162461bcd60e51b815260206004820152601560248201527409e9c98b2be8c9ea4be86aaa4a48a9c86b2be8aa89605b1b604482015290519081900360640190fd5b005b3480156102ec57600080fd5b506102f5610ca1565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561032f578181015183820152602001610317565b50505050905090810190601f16801561035c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561037657600080fd5b506103a36004803603604081101561038d57600080fd5b506001600160a01b038135169060200135610d38565b604080519115158252519081900360200190f35b3480156103c357600080fd5b506102de600480360360608110156103da57600080fd5b810190602081018135600160201b8111156103f457600080fd5b82018360208201111561040657600080fd5b803590602001918460018302840111600160201b8311171561042757600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b81111561047957600080fd5b82018360208201111561048b57600080fd5b803590602001918460018302840111600160201b831117156104ac57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295505050903560ff169150610d569050565b3480156104fe57600080fd5b50610507610e32565b60408051918252519081900360200190f35b34801561052557600080fd5b506102de600480360361010081101561053d57600080fd5b8135916001600160a01b036020820135169160408201359160608101359160808201359160a08101359181019060e0810160c0820135600160201b81111561058457600080fd5b82018360208201111561059657600080fd5b803590602001918460018302840111600160201b831117156105b757600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b81111561060957600080fd5b82018360208201111561061b57600080fd5b803590602001918460018302840111600160201b8311171561063c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610e38945050505050565b34801561068957600080fd5b506103a3600480360360608110156106a057600080fd5b506001600160a01b038135811691602081013590911690604001356111f5565b3480156106cc57600080fd5b50610507611283565b3480156106e157600080fd5b50610507600480360360208110156106f857600080fd5b5035611289565b34801561070b57600080fd5b50610507611406565b34801561072057600080fd5b5061072961142a565b6040805160ff9092168252519081900360200190f35b34801561074b57600080fd5b50610507611433565b34801561076057600080fd5b50610507611439565b34801561077557600080fd5b5061077e61143f565b604080516001600160a01b039092168252519081900360200190f35b3480156107a657600080fd5b506103a3600480360360408110156107bd57600080fd5b506001600160a01b038135169060200135611453565b3480156107df57600080fd5b506102de600480360360208110156107f657600080fd5b50356114a7565b34801561080957600080fd5b506102de600480360361012081101561082157600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060808101359060a081013515159060c08101359060e08101359061010001356114b6565b6102de611941565b34801561088057600080fd5b506105076004803603602081101561089757600080fd5b5035611ae4565b3480156108aa57600080fd5b506102f5611b5c565b3480156108bf57600080fd5b50610507611b79565b3480156108d457600080fd5b50610507611b7f565b3480156108e957600080fd5b50610507611b85565b3480156108fe57600080fd5b506102de6004803603606081101561091557600080fd5b506001600160a01b038135169060208101359060400135611b8b565b34801561093d57600080fd5b506105076004803603602081101561095457600080fd5b50356001600160a01b0316611d53565b34801561097057600080fd5b506105076004803603602081101561098757600080fd5b50356001600160a01b0316611d6e565b3480156109a357600080fd5b50610507600480360360208110156109ba57600080fd5b50356001600160a01b0316611d80565b3480156109d657600080fd5b50610507600480360360208110156109ed57600080fd5b5035611d92565b348015610a0057600080fd5b50610507611e13565b348015610a1557600080fd5b506102de6004803603610100811015610a2d57600080fd5b506001600160a01b038135811691602081013590911690604081013590606081013590608081013515159060ff60a0820135169060c08101359060e00135611e19565b348015610a7c57600080fd5b5061077e6120ba565b348015610a9157600080fd5b506102f56120c9565b348015610aa657600080fd5b5061050761212a565b348015610abb57600080fd5b506103a360048036036040811015610ad257600080fd5b506001600160a01b038135169060200135612130565b6102de60048036036060811015610afe57600080fd5b506001600160a01b03813516906020810135906040013561219e565b348015610b2657600080fd5b506103a3612448565b348015610b3b57600080fd5b50610507612451565b348015610b5057600080fd5b506103a360048036036040811015610b6757600080fd5b506001600160a01b038135169060200135612457565b348015610b8957600080fd5b5061050760048036036020811015610ba057600080fd5b503561246b565b348015610bb357600080fd5b50610507612571565b348015610bc857600080fd5b50610507612577565b6102de60048036036040811015610be757600080fd5b506001600160a01b03813516906020013561257d565b348015610c0957600080fd5b5061077e612597565b348015610c1e57600080fd5b5061077e6125a6565b348015610c3357600080fd5b506105076125b5565b348015610c4857600080fd5b5061050760048036036040811015610c5f57600080fd5b506001600160a01b03813581169160200135166125bb565b348015610c8357600080fd5b5061077e6125e6565b348015610c9857600080fd5b506105076125f5565b60688054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610d2d5780601f10610d0257610100808354040283529160200191610d2d565b820191906000526020600020905b815481529060010190602001808311610d1057829003601f168201915b505050505090505b90565b6000610d4c610d456126a9565b84846126ad565b5060015b92915050565b600054610100900460ff1680610d6f5750610d6f612799565b80610d7d575060005460ff16155b610db85760405162461bcd60e51b815260040180806020018281038252602e815260200180613da1602e913960400191505060405180910390fd5b600054610100900460ff16158015610de3576000805460ff1961ff0019909116610100171660011790555b8351610df6906068906020870190613b86565b508251610e0a906069906020860190613b86565b50606a805460ff191660ff84161790558015610e2c576000805461ff00191690555b50505050565b60355490565b60a2546001600160a01b031615610e8c576040805162461bcd60e51b81526020600482015260136024820152721053149150511657d253925512505312569151606a1b604482015290519081900360640190fd5b610e9882826012610d56565b85610ed25760ad5460408051918252600160208301528051600080516020613d388339815191529281900390910190a1600160ad55610f2d565b6f4b3b4ca85a86c47a098a2240000000008610610f27576040805162461bcd60e51b815260206004820152600e60248201526d115610d154d4d2559157d1d3d05360921b604482015290519081900360640190fd5b60a68690555b60008511610f76576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f534c4f50455f4e554d60781b604482015290519081900360640190fd5b60008411610fbf576040805162461bcd60e51b815260206004820152601160248201527024a72b20a624a22fa9a627a822afa222a760791b604482015290519081900360640190fd5b6001600160801b038510611010576040805162461bcd60e51b81526020600482015260136024820152724558434553534956455f534c4f50455f4e554d60681b604482015290519081900360640190fd5b6001600160801b038410611061576040805162461bcd60e51b815260206004820152601360248201527222ac21a2a9a9a4ab22afa9a627a822afa222a760691b604482015290519081900360640190fd5b60a085905560a18490556127108311156110b4576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f5245534552564560881b604482015290519081900360640190fd5b60a983905568056bc75e2d6310000060ab55609f8054610100600160a81b0319163361010081029190911790915560a280546001600160a01b0319908116831790915560a48054821690921790915560a380549091166001600160a01b038916179055871561113d5760a8889055609f5461113d9061010090046001600160a01b03168961279f565b604051806052613ce682396052019050604051809103902061115d610ca1565b80516020918201206040805180820190915260018152601960f91b9201919091527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a56111a76128ba565b6040805160208082019690965280820194909452606084019290925260808301523060a0808401919091528151808403909101815260c09092019052805191012060af555050505050505050565b60006112028484846128be565b6112788461120e6126a9565b61127385604051806060016040528060288152602001613d79602891396001600160a01b038a1660009081526034602052604081209061124c6126a9565b6001600160a01b03168152602081019190915260400160002054919063ffffffff6129dd16565b6126ad565b5060015b9392505050565b60a65481565b600060ab5482101561129d57506000611401565b60008060ad54141561138a578260006112b4610e32565b905060006112d660a05460a654028360a85460a654010360a154600202612a74565b9050808311156112e4578092505b6112fa8360a15460020260a05460a65402612a74565b93508583146113825760a154818703935060020261131e818563ffffffff612bfd16565b60a65460a0549195508002915061133c90829063ffffffff612bfd16565b905061134e848263ffffffff612c5616565b905060a054818161135b57fe5b04905061136781612cb0565b60a6549003905061137e858263ffffffff612c5616565b9450505b5050506113fe565b600160ad5414156113f457600060a854609e546113a5610e32565b010390506113bb8460a15460020260a054612a74565b91506113cf8282800263ffffffff612c5616565b91506113da82612cb0565b91506113ec828263ffffffff612d1f16565b9150506113fe565b6000915050611401565b90505b919050565b7fea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb81565b606a5460ff1690565b60a05481565b60af5481565b609f5461010090046001600160a01b031681565b6000610d4c6114606126a9565b8461127385603460006114716126a9565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff612c5616565b6114b333826000612d61565b50565b60a2546001600160a01b03163314611504576040805162461bcd60e51b815260206004820152600c60248201526b434f4e54524f4c5f4f4e4c5960a01b604482015290519081900360640190fd5b609d80546001600160a01b0319166001600160a01b038b8116919091179091558716611569576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b60a280546001600160a01b0319166001600160a01b038981169190911790915586166115ce576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b60a480546001600160a01b0319166001600160a01b038816179055609f805460ff1916851515179055612710831115611643576040805162461bcd60e51b81526020600482015260126024820152711253959053125117d0d3d35352551351539560721b604482015290519081900360640190fd5b60ac5483101561169a576040805162461bcd60e51b815260206004820152601d60248201527f434f4d4d49544d454e545f4d41595f4e4f545f42455f52454455434544000000604482015290519081900360640190fd5b60ac8390556127108511156116e4576040805162461bcd60e51b815260206004820152600b60248201526a494e56414c49445f46454560a81b604482015290519081900360640190fd5b60a585905581611734576040805162461bcd60e51b81526020600482015260166024820152751253959053125117d3525397d253959154d51351539560521b604482015290519081900360640190fd5b60ab82905560aa54811015611790576040805162461bcd60e51b815260206004820152601d60248201527f4f50454e5f554e54494c5f4d41595f4e4f545f42455f52454455434544000000604482015290519081900360640190fd5b60aa819055609f546001600160a01b0389811661010090920416146118ca576001600160a01b0388166117fc576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b609f546000906118199061010090046001600160a01b0316611d53565b609f546001600160a01b036101009091048116600090815260a7602052604080822054928d168252902054919250611857919063ffffffff612c5616565b6001600160a01b03808b16600090815260a7602052604080822093909355609f54610100900490911681529081205580156118a857609f546118a89061010090046001600160a01b03168a836128be565b50609f8054610100600160a81b0319166101006001600160a01b038b16021790555b604080516001600160a01b038b811682528615156020830152818301869052606082018890526080820185905260a082018490529151828916928a811692908c16917f64c539ad5ca31b3ba33150837a33d9e038c90023b19e46e187dcf033bbdae5b39181900360c00190a4505050505050505050565b609f5461010090046001600160a01b03163314611998576040805162461bcd60e51b815260206004820152601060248201526f42454e45464943494152595f4f4e4c5960801b604482015290519081900360640190fd5b60ad546000906119d75760ad5460408051918252600360208301528051600080516020613d388339815191529281900390910190a1600360ad55611aae565b600160ad541415611a71574260aa541115611a25576040805162461bcd60e51b8152602060048201526009602482015268544f4f5f4541524c5960b81b604482015290519081900360640190fd5b611a2e34611d92565b60ad5460408051918252600260208301528051929350600080516020613d3883398151915292918290030190a1600260ad55611a6c81346001612ea1565b611aae565b6040805162461bcd60e51b815260206004820152600d60248201526c494e56414c49445f535441544560981b604482015290519081900360640190fd5b6040805182815290517fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf9181900360200190a150565b600080609e54611af2610e32565b0190506000611b21611b1260ac5460020286612bfd90919063ffffffff16565b60a15460a05461271002612a74565b9050611b358183800263ffffffff612c5616565b9050611b4081612cb0565b905081811115611b525781900361127c565b5060009392505050565b604051806040016040528060018152602001601960f91b81525081565b609e5481565b60a15481565b60ac5481565b609f5461010090046001600160a01b031633141580611bad5750600260ad5410155b611be85760405162461bcd60e51b8152600401808060200182810382526028815260200180613dcf6028913960400191505060405180910390fd5b60008111611c34576040805162461bcd60e51b81526020600482015260146024820152734d5553545f53454c4c5f41545f4c454153545f3160601b604482015290519081900360640190fd5b6000611c3f8361246b565b905081811015611c87576040805162461bcd60e51b815260206004820152600e60248201526d50524943455f534c49505041474560901b604482015290519081900360640190fd5b60ad541580611c985750600360ad54145b15611cce5733600090815260a76020526040902054611cbd908463ffffffff612d1f16565b33600090815260a760205260409020555b611cda33846001612d61565b6000609e54611ce7610e32565b01905060a854811015611cfa5760a88190555b611d048583612f98565b604080518381526020810186905281516001600160a01b0388169233927fa082022e93cfcd9f1da5f9236718053910f7e840da080c789c7845698dc032ff929081900390910190a35050505050565b6001600160a01b031660009081526033602052604090205490565b60a76020526000908152604090205481565b60ae6020526000908152604090205481565b600080600160ad5414156113fe576000611daa6125f5565b9050611dbc818563ffffffff612d1f16565b90506000611dc8610e32565b9050611ddd8160a054609e540260a154612a74565b9250611df0818260a0540260a154612a74565b83019250818311611e045760009250611e0a565b81830392505b50509050919050565b60ab5481565b60af54604080517fea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb6020808301919091526001600160a01b03808d16838501819052908c166060840152608083018b905260a083018a905288151560c0808501919091528451808503909101815260e08401855280519083012061190160f01b61010085015261010284019590955261012280840195909552835180840390950185526101429092019092528251929091019190912090611f19576040805162461bcd60e51b815260206004820152601560248201527404441542f696e76616c69642d616464726573732d3605c1b604482015290519081900360640190fd5b6040805160008152602080820180845284905260ff8716828401526060820186905260808201859052915160019260a0808401939192601f1981019281900390910190855afa158015611f70573d6000803e3d6000fd5b505050602060405103516001600160a01b0316896001600160a01b031614611fd4576040805162461bcd60e51b81526020600482015260126024820152711110550bda5b9d985b1a590b5c195c9b5a5d60721b604482015290519081900360640190fd5b851580611fe15750854211155b612027576040805162461bcd60e51b81526020600482015260126024820152711110550bdc195c9b5a5d0b595e1c1a5c995960721b604482015290519081900360640190fd5b6001600160a01b038916600090815260ae60205260409020805460018101909155871461208f576040805162461bcd60e51b81526020600482015260116024820152704441542f696e76616c69642d6e6f6e636560781b604482015290519081900360640190fd5b60008561209d5760006120a1565b6000195b90506120ae8a8a836126ad565b50505050505050505050565b609d546001600160a01b031681565b60698054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610d2d5780601f10610d0257610100808354040283529160200191610d2d565b60a95481565b6000610d4c61213d6126a9565b8461127385604051806060016040528060258152602001613e8b60259139603460006121676126a9565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff6129dd16565b6001600160a01b0383166121eb576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b60008111612236576040805162461bcd60e51b81526020600482015260136024820152724d5553545f4255595f41545f4c454153545f3160681b604482015290519081900360640190fd5b600061224183611289565b905081811015612289576040805162461bcd60e51b815260206004820152600e60248201526d50524943455f534c49505041474560901b604482015290519081900360640190fd5b604080518481526020810183905281516001600160a01b0387169233927f89f5adc174562e07c9c9b1cae7109bbecb21cf9d1b2847e550042b8653c54a0e929081900390910190a36122dd83346000612ea1565b60ad546123ac576001600160a01b038416600090815260a76020526040902080548201905560a65460a85482612311610e32565b0103106123a75760ad5460408051918252600160208301528051600080516020613d388339815191529281900390910190a1600160ad55609f5461010090046001600160a01b0316600090815260a7602052604081205460a65460a05460a15461238393929190910290600202612a74565b90506123a56123a0826123946125f5565b9063ffffffff612d1f16565b612fda565b505b6123cf565b609f546001600160a01b0385811661010090920416146123cf576123cf83612fda565b6123d9848261279f565b600160ad541480156123fa5750609f5461010090046001600160a01b031633145b80156124185750609f546001600160a01b0385811661010090920416145b80156124265750609f5460ff165b15610e2c57609f54610e2c9061010090046001600160a01b0316826000612d61565b609f5460ff1681565b60a85481565b6000610d4c6124646126a9565b84846128be565b6000806124766125f5565b90506000600160ad54141561250d576000609e54612492610e32565b0190506124bd6124a8868563ffffffff612bfd16565b609e5480026124b5610e32565b848502613055565b915060006124d4866002860263ffffffff612bfd16565b90508181816124df57fe5b049283019290506125026124f9878063ffffffff612bfd16565b85848502613201565b83039250505061127c565b600260ad54141561254257612528848363ffffffff612bfd16565b9050612532610e32565b818161253a57fe5b04905061127c565b612552848363ffffffff612bfd16565b905060a85461255f610e32565b03818161256857fe5b04949350505050565b60a55481565b60ad5481565b61258981346000612ea1565b612593828261324c565b5050565b60a4546001600160a01b031681565b60a2546001600160a01b031681565b60aa5481565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b60a3546001600160a01b031681565b60a35460009047906001600160a01b0316156126855760a354604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b15801561265657600080fd5b505afa15801561266a573d6000803e3d6000fd5b505050506040513d602081101561268057600080fd5b505190505b6001600160801b038111156126a4576001600160801b03915050610d35565b905090565b3390565b6001600160a01b0383166126f25760405162461bcd60e51b8152600401808060200182810382526024815260200180613e3d6024913960400191505060405180910390fd5b6001600160a01b0382166127375760405162461bcd60e51b8152600401808060200182810382526022815260200180613c646022913960400191505060405180910390fd5b6001600160a01b03808416600081815260346020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b303b1590565b609d546000908390839083906001600160a01b03161561283757609d54604080516336dffedf60e01b81526001600160a01b0387811660048301528681166024830152604482018690528415156064830152915191909216916336dffedf91608480830192600092919082900301818387803b15801561281e57600080fd5b505af1158015612832573d6000803e3d6000fd5b505050505b6128418686613412565b6f4b3b4ca85a86c47a098a22400000000061286c609e54612860610e32565b9063ffffffff612c5616565b11156128b2576040805162461bcd60e51b815260206004820152601060248201526f4558434553534956455f535550504c5960801b604482015290519081900360640190fd5b505050505050565b4690565b609d548390839083906000906001600160a01b03161561295657609d54604080516336dffedf60e01b81526001600160a01b0387811660048301528681166024830152604482018690528415156064830152915191909216916336dffedf91608480830192600092919082900301818387803b15801561293d57600080fd5b505af1158015612951573d6000803e3d6000fd5b505050505b60ad541515806129785750609f546001600160a01b0388811661010090920416145b6129c9576040805162461bcd60e51b815260206004820152601c60248201527f4f4e4c595f42454e45464943494152595f445552494e475f494e495400000000604482015290519081900360640190fd5b6129d4878787613504565b50505050505050565b60008184841115612a6c5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612a31578181015183820152602001612a19565b50505050905090810190601f168015612a5e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000831580612a81575082155b15612a8e5750600061127c565b6000838560001981612a9c57fe5b0410612ab95750838302828181612aaf57fe5b04915061127c9050565b838581811115612ac95750859050845b848281612ad257fe5b0492506305f5e100831115612afc57612af1838263ffffffff612bfd16565b935061127c92505050565b60001981016001600160801b038104600101905060001983016001600160801b0381046001019050808260001981612b3057fe5b0410612ba05790810290818481612b4357fe5b049450630bebc200851115612ba057612b62858463ffffffff612bfd16565b9450506000198601818181612b7357fe5b049050612b8781600163ffffffff612c5616565b9050808581612b9257fe5b04955061127c945050505050565b60016001600160801b03600019850104019150818381612bbc57fe5b049450506000198601818181612bce57fe5b046001019050808481612bdd57fe5b049050612bf0858263ffffffff612bfd16565b9998505050505050505050565b600082612c0c57506000610d50565b82820282848281612c1957fe5b041461127c5760405162461bcd60e51b8152600401808060200182810382526021815260200180613d586021913960400191505060405180910390fd5b60008282018381101561127c576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600081612cbf57506000611401565b60038211612ccf57506001611401565b600019821415612ce757506001600160801b03611401565b5080600260018201045b81811015612d1957809150600281828581612d0857fe5b040181612d1157fe5b049050612cf1565b50919050565b600061127c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506129dd565b609d548390600090849084906001600160a01b031615612df957609d54604080516336dffedf60e01b81526001600160a01b0387811660048301528681166024830152604482018690528415156064830152915191909216916336dffedf91608480830192600092919082900301818387803b158015612de057600080fd5b505af1158015612df4573d6000803e3d6000fd5b505050505b612e038787613662565b846129d457600160ad5414612e51576040805162461bcd60e51b815260206004820152600f60248201526e27a7262cafa22aa924a723afa92aa760891b604482015290519081900360640190fd5b609e8054870190556040805187815290516001600160a01b038916917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5919081900360200190a250505050505050565b60a3546001600160a01b0316612f30578015612ee1576000612ec9838563ffffffff612d1f16565b90508015612edb57612edb338261375e565b50612f2b565b818314612f2b576040805162461bcd60e51b8152602060048201526013602482015272494e434f52524543545f4d53475f56414c554560681b604482015290519081900360640190fd5b612f93565b8115612f75576040805162461bcd60e51b815260206004820152600f60248201526e0889ebe9c9ea8bea68a9c88be8aa89608b1b604482015290519081900360640190fd5b60a354612f93906001600160a01b031633308663ffffffff61384316565b505050565b80156125935760a3546001600160a01b0316612fbd57612fb8828261375e565b612593565b60a354612593906001600160a01b0316838363ffffffff61389d16565b60a954600090612ff0908363ffffffff612bfd16565b612710900490506130018282612d1f565b9050600061301a60a55483612bfd90919063ffffffff16565b609f54612710909104915061303f9061010090046001600160a01b0316828403612f98565b60a454612f93906001600160a01b031682612f98565b600081836000198161306357fe5b041061307d576130768585848602612a74565b90506131f9565b841580613088575083155b15613095575060006131f9565b8183818111156130a55750839050825b60008688600019816130b357fe5b04106130de57508686028181816130c657fe5b0490508281816130d257fe5b0493506131f992505050565b8688818111156130ee5750889050875b60008483816130f957fe5b049050630bebc20081111561312057613113818388612a74565b96505050505050506131f9565b506001600160801b03600019838101829004600190810192848301040190829082908161314957fe5b04106131c457810280848161315a57fe5b049450630bebc2008511156131c457613179858463ffffffff612bfd16565b945085858161318457fe5b0494506000851180156131a2575080856000198161319e57fe5b0410155b156131c457938402938685816131b457fe5b0497506131f99650505050505050565b5050600160801b85046001600160801b03850481026131ef8185816131e557fe5b0484600019612a74565b9750505050505050505b949350505050565b60008061320f858585612a74565b90508061322057600191505061127c565b60016305f5e100600019830104018119811115613243576000199250505061127c565b01949350505050565b60008111613294576040805162461bcd60e51b815260206004820152601060248201526f4d495353494e475f43555252454e435960801b604482015290519081900360640190fd5b600160ad54146132db576040805162461bcd60e51b815260206004820152600d60248201526c494e56414c49445f535441544560981b604482015290519081900360640190fd5b60006132f260a95483612bfd90919063ffffffff16565b61271090049050600061330483611ae4565b9050836001600160a01b03811661332c5750609f5461010090046001600160a01b0316613350565b613338600086846138ef565b156133505750609f5461010090046001600160a01b03165b609f5461336d9061010090046001600160a01b0316848603612f98565b81156133c35761337d818361279f565b609f546001600160a01b03828116610100909204161480156133a15750609f5460ff165b156133c357609f546133c39061010090046001600160a01b0316836000612d61565b604080518581526020810184905281516001600160a01b0388169233927f0849372be021f4dce74a8a4cc15fcfaa23fdcfa92ae99fa045f6cdf0c0836436929081900390910190a35050505050565b6001600160a01b03821661346d576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b603554613480908263ffffffff612c5616565b6035556001600160a01b0382166000908152603360205260409020546134ac908263ffffffff612c5616565b6001600160a01b03831660008181526033602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b0383166135495760405162461bcd60e51b8152600401808060200182810382526025815260200180613e186025913960400191505060405180910390fd5b6001600160a01b03821661358e5760405162461bcd60e51b8152600401808060200182810382526023815260200180613c1f6023913960400191505060405180910390fd5b6135d181604051806060016040528060268152602001613c86602691396001600160a01b038616600090815260336020526040902054919063ffffffff6129dd16565b6001600160a01b038085166000908152603360205260408082209390935590841681522054613606908263ffffffff612c5616565b6001600160a01b0380841660008181526033602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6001600160a01b0382166136a75760405162461bcd60e51b8152600401808060200182810382526021815260200180613df76021913960400191505060405180910390fd5b6136ea81604051806060016040528060228152602001613c42602291396001600160a01b038516600090815260336020526040902054919063ffffffff6129dd16565b6001600160a01b038316600090815260336020526040902055603554613716908263ffffffff612d1f16565b6035556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b804710156137b3576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d80600081146137fe576040519150601f19603f3d011682016040523d82523d6000602084013e613803565b606091505b5050905080612f935760405162461bcd60e51b815260040180806020018281038252603a815260200180613cac603a913960400191505060405180910390fd5b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610e2c908590613995565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612f93908490613995565b609d546000906001600160a01b031615611b5257609d546040805163d4ce141560e01b81526001600160a01b0387811660048301528681166024830152604482018690529151919092169163d4ce1415916064808301926020929190829003018186803b15801561395f57600080fd5b505afa158015613973573d6000803e3d6000fd5b505050506040513d602081101561398957600080fd5b505160ff16905061127c565b6139a7826001600160a01b0316613b4d565b6139f8576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310613a365780518252601f199092019160209182019101613a17565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613a98576040519150601f19603f3d011682016040523d82523d6000602084013e613a9d565b606091505b509150915081613af4576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115610e2c57808060200190516020811015613b1057600080fd5b5051610e2c5760405162461bcd60e51b815260040180806020018281038252602a815260200180613e61602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906131f9575050151592915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613bc757805160ff1916838001178555613bf4565b82800160010185558215613bf4579182015b82811115613bf4578251825591602001919060010190613bd9565b50613c00929150613c04565b5090565b610d3591905b80821115613c005760008155600101613c0a56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d61792068617665207265766572746564454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429107dddb4541735557564238389eccfc9979bfdde5e57e24e9777b6fe79b4d22f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a656442454e45464943494152595f4f4e4c595f53454c4c5f494e5f434c4f53455f4f525f43414e43454c45524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a723158203df6ab943caf92756530e7b49d4e6d37d1cd0e41d9bea7d7d815e192038bc1eb64736f6c63430005110032

Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.