Contract Address Details

0x337EbAba483A4F7Cb2bfc9e6039462d5E6B1FBFa

Contract Name
IDOMaster
Creator
0x81113e–f12b4f at 0x62a46b–279fe8
Balance
0 REI
Tokens
Fetching tokens...
Transactions
3 Transactions
Transfers
0 Transfers
Gas Used
12,637,989
Last Balance Update
33989090
Contract name:
IDOMaster




Optimization enabled
true
Compiler version
v0.8.7+commit.e28d00a7




Optimization runs
200
Verified at
2022-12-02T04:25:02.099618Z

Contract source code

// Sources flattened with hardhat v2.9.3 https://hardhat.org

// File @openzeppelin/contracts/utils/math/[email protected]

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // 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 (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @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) {
        return a + b;
    }

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

    /**
     * @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) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting 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 a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

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

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}


// File @openzeppelin/contracts/token/ERC20/[email protected]


// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from,
        address to,
        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/utils/[email protected]


// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @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
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @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].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}


// File @openzeppelin/contracts/token/ERC20/utils/[email protected]


// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.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 IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    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));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    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'
        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) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}


// File @openzeppelin/contracts/utils/[email protected]


// OpenZeppelin Contracts v4.4.1 (utils/Create2.sol)

pragma solidity ^0.8.0;

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(
        uint256 amount,
        bytes32 salt,
        bytes memory bytecode
    ) internal returns (address) {
        address addr;
        require(address(this).balance >= amount, "Create2: insufficient balance");
        require(bytecode.length != 0, "Create2: bytecode length is zero");
        assembly {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
        }
        require(addr != address(0), "Create2: Failed on deploy");
        return addr;
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(
        bytes32 salt,
        bytes32 bytecodeHash,
        address deployer
    ) internal pure returns (address) {
        bytes32 _data = keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash));
        return address(uint160(uint256(_data)));
    }
}


// File @openzeppelin/contracts/security/[email protected]


// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

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

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

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


// File contracts/VestingWallet.sol


pragma solidity 0.8.7;


/**
 * @title VestingWallet
 * @dev This contract handles the vesting of Eth and ERC20 tokens for a given beneficiary. Custody of multiple tokens
 * can be given to this contract, which will release the token to the beneficiary following a given vesting schedule.
 * The vesting schedule is customizable through the {vestedAmount} function.
 *
 * Any token transferred to this contract will follow the vesting schedule as if they were locked from the beginning.
 * Consequently, if the vesting has already started, any amount of tokens sent to this contract will (at least partly)
 * be immediately releasable.
 */
contract VestingWallet  {
    event EtherReleased(uint256 amount);
    event ERC20Released(address indexed token, uint256 amount);

    address private  _beneficiary;
    uint64 private  _start;
    uint64 private  _duration;

    /**
     * @dev Set the beneficiary, start timestamp and vesting duration of the vesting wallet.
     */
    function VestingWallet_initialize(
        address beneficiaryAddress,
        uint64 startTimestamp,
        uint64 durationSeconds
    ) internal {
        require(beneficiaryAddress != address(0), "VestingWallet: beneficiary is zero address");
        _beneficiary = beneficiaryAddress;
        _start = startTimestamp;
        _duration = durationSeconds;
    }

    /**
     * @dev Getter for the beneficiary address.
     */
    function beneficiary() public view virtual returns (address) {
        return _beneficiary;
    }

    /**
     * @dev Getter for the start timestamp.
     */
    function start() public view virtual returns (uint256) {
        return _start;
    }

    /**
     * @dev Getter for the vesting duration.
     */
    function duration() public view virtual returns (uint256) {
        return _duration;
    }

    /**
     * @dev Calculates the amount of ether that has already vested. Default implementation is a linear vesting curve.
     */
    function vestedAmount(uint64 timestamp) public view virtual returns (uint256) {
        return _vestingSchedule(address(this).balance, timestamp);
    }

    /**
     * @dev Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve.
     */
    function vestedAmount(address token, uint64 timestamp) public view virtual returns (uint256) {
        return _vestingSchedule(IERC20(token).balanceOf(address(this)), timestamp);
    }

    /**
     * @dev Virtual implementation of the vesting formula. This returns the amout vested, as a function of time, for
     * an asset given its total historical allocation.
     */
    function _vestingSchedule(uint256 totalAllocation, uint64 timestamp) internal view virtual returns (uint256) {
       if (timestamp >= start() + duration()) {
            return totalAllocation;
        }else{
            return 0;
        }
    }
}


// File contracts/MultiSigWallet.sol


pragma solidity 0.8.7;

contract MultiSigWallet {
    /*
     *  Events
     */
    event Confirmation(address indexed sender, uint indexed transactionId);
    event Revocation(address indexed sender, uint indexed transactionId);
    event Submission(uint indexed transactionId);
    event Execution(uint indexed transactionId);
    event ExecutionFailure(uint indexed transactionId);
    event Deposit(address indexed sender, uint value);
    event OwnerAddition(address indexed owner);
    event OwnerRemoval(address indexed owner);
    event RequirementChange(uint required);

    /*
     *  Constants
     */
    uint constant public MAX_OWNER_COUNT = 50;

    /*
     *  Storage
     */
    mapping (uint => Transaction) public transactions;
    mapping (uint => mapping (address => bool)) public confirmations;
    mapping (address => bool) public isOwner;
    address[] public owners;
    uint public required;
    uint public transactionCount;

    struct Transaction {
        address destination;
        uint value;
        bytes data;
        bool executed;
    }

    /*
     *  Modifiers
     */
    modifier onlyWallet() {
        require(msg.sender == address(this));
        _;
    }

    modifier ownerDoesNotExist(address owner) {
        require(!isOwner[owner]);
        _;
    }

    modifier ownerExists(address owner) {
        require(isOwner[owner]);
        _;
    }

    modifier transactionExists(uint transactionId) {
        require(transactions[transactionId].destination != address(0));
        _;
    }

    modifier confirmed(uint transactionId, address owner) {
        require(confirmations[transactionId][owner]);
        _;
    }

    modifier notConfirmed(uint transactionId, address owner) {
        require(!confirmations[transactionId][owner]);
        _;
    }

    modifier notExecuted(uint transactionId) {
        require(!transactions[transactionId].executed);
        _;
    }

    modifier notNull(address _address) {
        require(_address != address(0));
        _;
    }

    modifier validRequirement(uint ownerCount, uint _required) {
        require(ownerCount <= MAX_OWNER_COUNT
            && _required <= ownerCount
            && _required != 0
            && ownerCount != 0);
        _;
    }

    /// @dev Fallback function allows to deposit ether.
    fallback()
        external
        payable
    {
        if (msg.value > 0)
            emit Deposit(msg.sender, msg.value);
    }

    receive()
        external
        payable
    {
        if (msg.value > 0)
            emit Deposit(msg.sender, msg.value);
    }

    /*
     * Public functions
     */
    /// @dev Contract constructor sets initial owners and required number of confirmations.
    /// @param _owners List of initial owners.
    /// @param _required Number of required confirmations.
    function MultiSigWallet_initialize(address[] memory _owners, uint _required)
        validRequirement(_owners.length, _required) internal
    {
        for (uint i=0; i<_owners.length; i++) {
            require(!isOwner[_owners[i]] && _owners[i] != address(0));
            isOwner[_owners[i]] = true;
        }
        owners = _owners;
        required = _required;
    }

    /// @dev Allows to add a new owner. Transaction has to be sent by wallet.
    /// @param owner Address of new owner.
    function addOwner(address owner)
        public
        onlyWallet
        ownerDoesNotExist(owner)
        notNull(owner)
        validRequirement(owners.length + 1, required)
    {
        isOwner[owner] = true;
        owners.push(owner);
        emit OwnerAddition(owner);
    }

    /// @dev Allows to remove an owner. Transaction has to be sent by wallet.
    /// @param owner Address of owner.
    function removeOwner(address owner)
        public
        onlyWallet
        ownerExists(owner)
    {
        isOwner[owner] = false;
        for (uint i=0; i<owners.length - 1; i++)
            if (owners[i] == owner) {
                owners[i] = owners[owners.length - 1];
                break;
            }
        owners.pop();
        if (required > owners.length)
            changeRequirement(owners.length);
        emit OwnerRemoval(owner);
    }

    /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
    /// @param owner Address of owner to be replaced.
    /// @param newOwner Address of new owner.
    function replaceOwner(address owner, address newOwner)
        public
        onlyWallet
        ownerExists(owner)
        ownerDoesNotExist(newOwner)
    {
        for (uint i=0; i<owners.length; i++)
            if (owners[i] == owner) {
                owners[i] = newOwner;
                break;
            }
        isOwner[owner] = false;
        isOwner[newOwner] = true;
        emit OwnerRemoval(owner);
        emit OwnerAddition(newOwner);
    }

    /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
    /// @param _required Number of required confirmations.
    function changeRequirement(uint _required)
        public
        onlyWallet
        validRequirement(owners.length, _required)
    {
        required = _required;
        emit RequirementChange(_required);
    }

    /// @dev Allows an owner to submit and confirm a transaction.
    /// @param destination Transaction target address.
    /// @param value Transaction ether value.
    /// @param data Transaction data payload.
    /// @return transactionId Returns transaction ID.
    function submitTransaction(address destination, uint value, bytes memory data)
        public
        returns (uint transactionId)
    {
        transactionId = addTransaction(destination, value, data);
        confirmTransaction(transactionId);
    }

    /// @dev Allows an owner to confirm a transaction.
    /// @param transactionId Transaction ID.
    function confirmTransaction(uint transactionId)
        public
        virtual
        ownerExists(msg.sender)
        transactionExists(transactionId)
        notConfirmed(transactionId, msg.sender)
    {
        confirmations[transactionId][msg.sender] = true;
        emit Confirmation(msg.sender, transactionId);
        executeTransaction(transactionId);
    }

    /// @dev Allows an owner to revoke a confirmation for a transaction.
    /// @param transactionId Transaction ID.
    function revokeConfirmation(uint transactionId)
        public
        ownerExists(msg.sender)
        confirmed(transactionId, msg.sender)
        notExecuted(transactionId)
    {
        confirmations[transactionId][msg.sender] = false;
        emit Revocation(msg.sender, transactionId);
    }

    /// @dev Allows anyone to execute a confirmed transaction.
    /// @param transactionId Transaction ID.
    function executeTransaction(uint transactionId)
        public
        virtual
        ownerExists(msg.sender)
        confirmed(transactionId, msg.sender)
        notExecuted(transactionId)
    {
        if (isConfirmed(transactionId)) {
            Transaction storage txn = transactions[transactionId];
            txn.executed = true;
            if (external_call(txn.destination, txn.value, txn.data.length, txn.data))
                emit Execution(transactionId);
            else {
                emit ExecutionFailure(transactionId);
                txn.executed = false;
            }
        }
    }

    // call has been separated into its own function in order to take advantage
    // of the Solidity's code generator to produce a loop that copies tx.data into memory.
    function external_call(address destination, uint value, uint dataLength, bytes memory data) internal returns (bool) {
        bool result;
        assembly {
            let x := mload(0x40)   // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention)
            let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that
            result := call(
                sub(gas(), 34710),   // 34710 is the value that solidity is currently emitting
                                   // It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) +
                                   // callNewAccountGas (25000, in case the destination address does not exist and needs creating)
                destination,
                value,
                d,
                dataLength,        // Size of the input (in bytes) - this is what fixes the padding problem
                x,
                0                  // Output is ignored, therefore the output size is zero
            )
        }
        return result;
    }

    /// @dev Returns the confirmation status of a transaction.
    /// @param transactionId Transaction ID.
    /// @return Confirmation status.
    function isConfirmed(uint transactionId)
        public
        view
        returns (bool)
    {
        uint count = 0;
        for (uint i=0; i<owners.length; i++) {
            if (confirmations[transactionId][owners[i]])
                count += 1;
            if (count == required)
                return true;
        }

        return false;
    }

    /*
     * Internal functions
     */
    /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
    /// @param destination Transaction target address.
    /// @param value Transaction ether value.
    /// @param data Transaction data payload.
    /// @return transactionId Returns transaction ID.
    function addTransaction(address destination, uint value, bytes memory data)
        internal
        notNull(destination)
        returns (uint transactionId)
    {
        transactionId = transactionCount;
        transactions[transactionId] = Transaction({
            destination: destination,
            value: value,
            data: data,
            executed: false
        });
        transactionCount += 1;
        emit Submission(transactionId);
    }

    /*
     * Web3 call functions
     */
    /// @dev Returns number of confirmations of a transaction.
    /// @param transactionId Transaction ID.
    /// @return count Number of confirmations.
    function getConfirmationCount(uint transactionId)
        public
        view
        returns (uint count)
    {
        for (uint i=0; i<owners.length; i++)
            if (confirmations[transactionId][owners[i]])
                count += 1;
    }

    /// @dev Returns total number of transactions after filers are applied.
    /// @param pending Include pending transactions.
    /// @param executed Include executed transactions.
    /// @return count Total number of transactions after filters are applied.
    function getTransactionCount(bool pending, bool executed)
        public
        view
        returns (uint count)
    {
        for (uint i=0; i<transactionCount; i++)
            if (   pending && !transactions[i].executed
                || executed && transactions[i].executed)
                count += 1;
    }

    /// @dev Returns list of owners.
    /// @return List of owner addresses.
    function getOwners()
        public
        view
        returns (address[] memory)
    {
        return owners;
    }

    /// @dev Returns array with owner addresses, which confirmed transaction.
    /// @param transactionId Transaction ID.
    /// @return _confirmations Returns array of owner addresses.
    function getConfirmations(uint transactionId)
        public
        view
        returns (address[] memory _confirmations)
    {
        address[] memory confirmationsTemp = new address[](owners.length);
        uint count = 0;
        uint i;
        for (i=0; i<owners.length; i++)
            if (confirmations[transactionId][owners[i]]) {
                confirmationsTemp[count] = owners[i];
                count += 1;
            }
        _confirmations = new address[](count);
        for (i=0; i<count; i++)
            _confirmations[i] = confirmationsTemp[i];
    }

    /// @dev Returns list of transaction IDs in defined range.
    /// @param from Index start position of transaction array.
    /// @param to Index end position of transaction array.
    /// @param pending Include pending transactions.
    /// @param executed Include executed transactions.
    /// @return _transactionIds Returns array of transaction IDs.
    function getTransactionIds(uint from, uint to, bool pending, bool executed)
        public
        view
        returns (uint[] memory _transactionIds)
    {
        uint[] memory transactionIdsTemp = new uint[](transactionCount);
        uint count = 0;
        uint i;
        for (i=0; i<transactionCount; i++)
            if (   pending && !transactions[i].executed
                || executed && transactions[i].executed)
            {
                transactionIdsTemp[count] = i;
                count += 1;
            }
        _transactionIds = new uint[](to - from);
        for (i=from; i<to; i++)
            _transactionIds[i - from] = transactionIdsTemp[i];
    }
}


// File contracts/MultiSigVesting.sol


pragma solidity 0.8.7;


contract MultiSigVesting  is MultiSigWallet,VestingWallet{

    address public  _tokenLp;
    address public  _token;

    address private  _wrei;

    // address private  _pool;

    address private immutable _idopool;

    constructor() {
         _idopool = msg.sender;
    }

    function initialize(
        address[] memory _owners,
        uint256 _required,
        uint64 _durationSeconds,
        address _benefit,
        uint64 _time,
        address token,
        address _lpAddr,
        address wrei
       
    ) external {
        require(msg.sender == _idopool,"only pool");

        MultiSigWallet_initialize(_owners, _required);
        VestingWallet_initialize(_benefit,_time,_durationSeconds);

       _token = token;
       _wrei = wrei;
        _tokenLp = _lpAddr;
    }

    function releaseLp() public onlyWallet {
        uint256 releasable = vestedAmount(_tokenLp, uint64(block.timestamp));
        emit ERC20Released(_tokenLp, releasable);
        SafeERC20.safeTransfer(IERC20(_tokenLp), beneficiary(), releasable);
    }

    function release(uint256 _amount) public onlyWallet {
         uint256 value;
         require(start() < block.timestamp,"end!");
        
        if(_token == _wrei) {
            value = address(this).balance;
            
            require(_amount <= value,"amount lt balanceOf");

            payable(beneficiary()).transfer(_amount);
        }else{
            value = IERC20(_token).balanceOf(address(this));
            
            require(_amount <= value,"amount lt balanceOf");

            IERC20(_token).transfer(beneficiary(), _amount);
        }   

        emit EtherReleased(_amount);
    }
}


// File contracts/libraries/IDOData.sol


pragma solidity 0.8.7;

library IDOData {

    struct IDOinput {
        address _addr;
        uint256 _tokenPrice;
        uint256 _pairPrice;
        uint256 _targetAmount;
        IERC20   _srcToken;
        IERC20   _rewardToken;
        uint256 _startTimestamp;
        uint256 _finishTimestamp;
        uint256 _perMaxDistributedTokenAmount;
        address _rei;
        address _factory;
        address _router;
    }
}


// File contracts/IDOPool.sol


pragma solidity 0.8.7;





interface IERC20Detail {
    function decimals() external view returns (uint8);
}

interface IRouter{
    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
}

interface IFactory{
    function getPair(address tokenA, address tokenB) external view returns (address pair);
}

interface IMultiSigVest{
    function initialize(
        address[] memory _owners,
        uint256 _required,
        uint64 _durationSeconds,
        address _benefit,
        uint64 _time,
        address token,
        address _lpAddr,
        address wrei
    ) external;
}

contract IDOPool is ReentrancyGuard{
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    address public owner;

    uint256 public tokenPrice;
    IERC20 public sellToken;
    IERC20 public rewardToken;

    uint256 public buyDecimals;
    uint256 public sellDecimals;

    uint256 public startTimestamp;
    uint256 public finishTimestamp;

    uint256 public maxDistributedTokenAmount;
    uint256 public perMaxDistributedTokenAmount;
    uint256 public tokensForDistribution;

    bool public finish;

    address private wrei;
    IRouter private router;
    IFactory private factory;
    address private dao;

    uint256 private pairPrice;

    address[] public  signAddrs = [0x06677520c1449D9977E7A245f0797A65e7efF219,0xb9EB39C42d0E9f4966d411bDfBfc711235945936,0xA551a1683FF764a4F5Ff143f57206067fF29fAc5];
    uint64 private constant periors = 31536000;

    uint256 public interval;
    uint256 public duration;
    uint256 public start;

    struct Vesting {
        uint256 balance;
        uint256 released;
    }

    mapping (address => Vesting) private _vestings;

    event TokensSell(
        address indexed holder,
        uint256 ethAmount,
        uint256 tokenAmount
    );

    event Released(uint256 amount);
    
    event MultiSigVestingEvent(address multiSigVesting,address sender,uint256 amount);

    constructor(
        IDOData.IDOinput memory input
    )  {
        owner = input._addr;
        tokenPrice = input._tokenPrice;
        sellToken   = input._srcToken;
        rewardToken = input._rewardToken;
        sellDecimals = IERC20Detail(address(sellToken)).decimals();
        
        pairPrice = input._pairPrice;

        wrei = input._rei;
        router = IRouter(input._router);
        factory = IFactory(input._factory);

        maxDistributedTokenAmount = input._targetAmount;

        perMaxDistributedTokenAmount = input._perMaxDistributedTokenAmount;

        require(
            input._startTimestamp < input._finishTimestamp,
            "Start number must be less than finish number"
        );
        require(
           input._finishTimestamp > block.timestamp,
            "Finish number must be more than current block"
        );

        startTimestamp = input._startTimestamp;
        finishTimestamp = input._finishTimestamp;

        interval = 86400;
        duration = 31536000;

        start = finishTimestamp;
    }

    function pay() payable external nonReentrant{
        require(address(rewardToken) == wrei,"payREI:Not Rei");
        require(block.timestamp >= startTimestamp, "payREI:Not started");
        require(block.timestamp < finishTimestamp, "payREI:Ended");
        require(!finish,"payREI:Finished");

        uint256 amount = msg.value;

        uint256 tokenAmount = getTokenAmount(amount);

        require(perMaxDistributedTokenAmount >= tokenAmount,"payREI: perMaxDistributedTokenAmount");

        if(tokensForDistribution.add(amount) >  maxDistributedTokenAmount) {
            finish = true;
            
            payable(msg.sender).transfer(amount.sub(maxDistributedTokenAmount.sub(tokensForDistribution)));
            amount = maxDistributedTokenAmount.sub(tokensForDistribution);
        }

        tokensForDistribution = tokensForDistribution.add(amount);
        tokenAmount = getTokenAmount(amount);

        createVesting(msg.sender,tokenAmount);

        if(finish){
            dealFinish();
        }

        emit TokensSell(msg.sender, amount, tokenAmount);
    }

    function pay(uint256 _amount) external nonReentrant {
        require(block.timestamp >= startTimestamp, "pay:Not started");
        require(block.timestamp < finishTimestamp, "pay:ended");
        require(!finish,"payREI:Finished");

        uint256 tokenAmount = getTokenAmount(_amount);

        require(perMaxDistributedTokenAmount >= tokenAmount,"payREI: perMaxDistributedTokenAmount");

        if(tokensForDistribution.add(_amount) >=  maxDistributedTokenAmount) {
            finish = true;
            _amount = maxDistributedTokenAmount.sub(tokensForDistribution);
        }

        tokensForDistribution = tokensForDistribution.add(_amount);

        rewardToken.safeTransferFrom(msg.sender, address(address(this)), _amount);
        tokenAmount = getTokenAmount(_amount);

        createVesting(msg.sender,tokenAmount);

       if(finish){
            dealFinish();
        }
        
        emit TokensSell(msg.sender, _amount, tokenAmount);
    }

    function getTokenAmount(uint256 amount)
        internal
        view
        returns (uint256)
    {
        return amount.mul(10**sellDecimals).div(tokenPrice);
    }

    function finished() public nonReentrant {
        require(block.timestamp > finishTimestamp, "pay:Not started");
        require(!finish,"already finished");

        dealFinish();
    } 

    function dealFinish() private {
        bytes32 salt = keccak256(abi.encodePacked(owner, rewardToken,sellToken));
        bytes memory bytecode = type(MultiSigVesting).creationCode;
        address multiSigVestAddr = Create2.deploy(0, salt, bytecode);

        address lpToken;

        if(address(rewardToken) == wrei) {
             uint256 value = address(this).balance;
            uint256 amountBDesired = value.mul(20).div(100).mul(10**sellDecimals).div(pairPrice);
            sellToken.safeApprove(address(router),amountBDesired);
           
            (,,uint liquidity) = router.addLiquidityETH{value:value.mul(20).div(100)}(address(sellToken),amountBDesired,0,0,address(multiSigVestAddr),uint64(block.timestamp));
            lpToken = factory.getPair(wrei,address(sellToken));
            
            emit MultiSigVestingEvent(address(multiSigVestAddr),owner,liquidity);

            payable(multiSigVestAddr).transfer(value.mul(80).div(100));
        }else{
            uint256 amountADesired = rewardToken.balanceOf(address(this));
            uint256 amountBDesired = amountADesired.mul(20).div(100).mul(10**sellDecimals).div(pairPrice);
            
            rewardToken.safeApprove(address(router),amountADesired);
            sellToken.safeApprove(address(router),amountBDesired);

            (,,uint liquidity) = router.addLiquidity(address(rewardToken),address(sellToken),amountADesired.mul(20).div(100),amountBDesired,0,0,address(multiSigVestAddr),uint64(block.timestamp));  
            lpToken = factory.getPair(address(rewardToken),address(sellToken));

            rewardToken.safeTransfer(address(multiSigVestAddr),amountADesired.mul(80).div(100));

           emit MultiSigVestingEvent(address(multiSigVestAddr),owner,liquidity);
        }

        IMultiSigVest(multiSigVestAddr).initialize(signAddrs,2,periors,owner,uint64(block.timestamp),address(rewardToken),lpToken,wrei);
    }

    function createVesting(
        address beneficiary,
        uint256 amount
    ) private {
        require(interval > 0 , "TokenVesting #createVesting: interval must be greater than 0");
        require(duration >= interval, "TokenVesting #createVesting: interval cannot be bigger than duration");

        Vesting storage vest = _vestings[beneficiary];

        vest.balance = vest.balance.add(amount);
    }

    function getInfo(address beneficiary) public view returns (uint256, uint256, uint256) {
        Vesting memory v = _vestings[beneficiary];
        return (v.balance+v.released,releasableAmount(beneficiary),v.released);
    }
    
    function release(address beneficiary) external {
        uint256 unreleased = releasableAmount(beneficiary);
        require(unreleased > 0, "TokenVesting #release: nothing to release");

        Vesting storage vest = _vestings[beneficiary];

        vest.released = vest.released.add(unreleased);
        vest.balance = vest.balance.sub(unreleased);

        sellToken.safeTransfer(beneficiary, unreleased);
        emit Released(unreleased);
    }

    function releasableAmount(address beneficiary) public view returns (uint256) {
        return vestedAmount(beneficiary).sub(_vestings[beneficiary].released);
    }

    function vestedAmount(address beneficiary) public view returns (uint256) {
        Vesting memory vest = _vestings[beneficiary];
        uint256 currentBalance = vest.balance;
        uint256 totalBalance = currentBalance.add(vest.released);

        if(start > block.timestamp) {
            return 0;
        }

        if (block.timestamp >= start.add(duration)) {
            return totalBalance;
        } else {
            uint256 numberOfInvervals = block.timestamp.sub(start).div(interval);
            uint256 totalIntervals = duration.div(interval);
            return totalBalance.mul(numberOfInvervals).div(totalIntervals);
        }
    }
}


// File contracts/IDOMaster.sol


pragma solidity 0.8.7;




contract IDOMaster {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    uint256 private count;

    struct itemsInfo {
        address owner;
        address idoPool;
        uint256 tokenPrice;
        uint256 targetAmount;
        address srcToken;
        address rewardToken;
        uint256 startTimestamp;
        uint256 finishTimestamp;
        uint256 perMaxDistributedTokenAmount;
    }

    mapping(uint256=>itemsInfo) private  itemsInfos;

    event IDOCreated(address owner, address idoPool,
        uint256 tokenPrice,
        uint256 targetAmount,
        address srcToken,
        address rewardToken,
        uint256 startTimestamp,
        uint256 finishTimestamp,
        uint256 perMaxDistributedTokenAmount
        );

    function createIDO(
        IDOData.IDOinput calldata input
    ) external {
        IDOPool idoPool =
            new IDOPool(
                input
            );

        
       transferAmount(input._targetAmount,input._tokenPrice,input._pairPrice,input._srcToken,address(idoPool));

        emit IDOCreated(input._addr, 
                        address(idoPool),
                        input._tokenPrice,
                        input._targetAmount,
                        address(input._srcToken),
                        address(input._rewardToken),
                        input._startTimestamp,
                        input._finishTimestamp,
                        input._perMaxDistributedTokenAmount);

        itemsInfos[count] = itemsInfo ({
                owner: input._addr,
                idoPool: address(idoPool),
                tokenPrice: input._tokenPrice,
                targetAmount: input._targetAmount,
                srcToken: address(input._srcToken),
                rewardToken: address(input._rewardToken),
                startTimestamp:  input._startTimestamp,
                finishTimestamp: input._finishTimestamp,
                perMaxDistributedTokenAmount:input._perMaxDistributedTokenAmount
        });

        count++;
    }

    function getItemCount() external view returns(uint256){
        return count;
    }

    function getItemInfo(uint256 index) external view returns(itemsInfo memory ){
        return itemsInfos[index];
    }
 
    function transferAmount(uint256 _targetAmount,uint256 _tokenPrice,uint256 _pairPrice,IERC20 _srcToken,address _idoPool) private {
        uint256 amount = _targetAmount.mul(10**18).div(_tokenPrice).add(_targetAmount.mul(10**18).mul(20).div(100).div(_pairPrice));

        _srcToken.safeTransferFrom(
            msg.sender,
            _idoPool,
            amount
        );
    }
}
        
>

Contract ABI

[{"type":"event","name":"IDOCreated","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":false},{"type":"address","name":"idoPool","internalType":"address","indexed":false},{"type":"uint256","name":"tokenPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"targetAmount","internalType":"uint256","indexed":false},{"type":"address","name":"srcToken","internalType":"address","indexed":false},{"type":"address","name":"rewardToken","internalType":"address","indexed":false},{"type":"uint256","name":"startTimestamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"finishTimestamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"perMaxDistributedTokenAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createIDO","inputs":[{"type":"tuple","name":"input","internalType":"struct IDOData.IDOinput","components":[{"type":"address","name":"_addr","internalType":"address"},{"type":"uint256","name":"_tokenPrice","internalType":"uint256"},{"type":"uint256","name":"_pairPrice","internalType":"uint256"},{"type":"uint256","name":"_targetAmount","internalType":"uint256"},{"type":"address","name":"_srcToken","internalType":"contract IERC20"},{"type":"address","name":"_rewardToken","internalType":"contract IERC20"},{"type":"uint256","name":"_startTimestamp","internalType":"uint256"},{"type":"uint256","name":"_finishTimestamp","internalType":"uint256"},{"type":"uint256","name":"_perMaxDistributedTokenAmount","internalType":"uint256"},{"type":"address","name":"_rei","internalType":"address"},{"type":"address","name":"_factory","internalType":"address"},{"type":"address","name":"_router","internalType":"address"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getItemCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct IDOMaster.itemsInfo","components":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"idoPool","internalType":"address"},{"type":"uint256","name":"tokenPrice","internalType":"uint256"},{"type":"uint256","name":"targetAmount","internalType":"uint256"},{"type":"address","name":"srcToken","internalType":"address"},{"type":"address","name":"rewardToken","internalType":"address"},{"type":"uint256","name":"startTimestamp","internalType":"uint256"},{"type":"uint256","name":"finishTimestamp","internalType":"uint256"},{"type":"uint256","name":"perMaxDistributedTokenAmount","internalType":"uint256"}]}],"name":"getItemInfo","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]}]
              

Contract Creation Code

0x608060405234801561001057600080fd5b506152b6806100206000396000f3fe60806040523480156200001157600080fd5b5060043610620000465760003560e01c8063707f507c146200004b5780637749cf231462000064578063de7fe3e7146200007a575b600080fd5b620000626200005c3660046200087f565b6200010b565b005b6000546040519081526020015b60405180910390f35b620000916200008b36600462000899565b6200039f565b60405162000071919081516001600160a01b039081168252602080840151821690830152604080840151908301526060808401519083015260808084015182169083015260a0808401519091169082015260c0808301519082015260e0808301519082015261010091820151918101919091526101200190565b6000816040516200011c906200081b565b62000128919062000906565b604051809103906000f08015801562000145573d6000803e3d6000fd5b509050620001746060830135602084013560408501356200016d60a08701608088016200083b565b856200049d565b7fdf28fe625edaab14d82ac291ae937512fc672b0977357600f5f48a68209aa599620001a460208401846200083b565b8260208501356060860135620001c160a08801608089016200083b565b620001d360c0890160a08a016200083b565b604080516001600160a01b039788168152958716602087015285019390935260608401919091528316608083015290911660a082015260c0848101359082015260e0808501359082015261010080850135908201526101200160405180910390a1604080516101208101909152806200025060208501856200083b565b6001600160a01b03168152602001826001600160a01b0316815260200183602001358152602001836060013581526020018360800160208101906200029691906200083b565b6001600160a01b03168152602001620002b660c0850160a086016200083b565b6001600160a01b03908116825260c08581013560208085019190915260e080880135604080870191909152610100808a013560609788015260008054815260018086528382208a5181546001600160a01b0319908116918b16919091178255968b015191810180548816928a16929092179091559289015160028401559688015160038301556080880151600483018054861691881691909117905560a088015160058301805490951696169590951790925591850151600682015590840151600782015592015160089092019190915580549080620003968362000a8a565b91905055505050565b6200041360405180610120016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b5060009081526001602081815260409283902083516101208101855281546001600160a01b0390811682529382015484169281019290925260028101549382019390935260038301546060820152600483015482166080820152600583015490911660a0820152600682015460c0820152600782015460e082015260089091015461010082015290565b6000620004f3620004d385620004cc6064816014620004c58d670de0b6b3a764000062000514565b9062000514565b9062000529565b620004ec87620004cc8a670de0b6b3a764000062000514565b9062000537565b90506200050c6001600160a01b03841633848462000545565b505050505050565b600062000522828462000a39565b9392505050565b600062000522828462000a16565b6000620005228284620009fb565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052620005a1908590620005a7565b50505050565b6000620005fe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620006899092919063ffffffff16565b8051909150156200068457808060200190518101906200061f91906200085b565b620006845760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084015b60405180910390fd5b505050565b60606200069a8484600085620006a2565b949350505050565b606082471015620007055760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016200067b565b6001600160a01b0385163b6200075e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016200067b565b600080866001600160a01b031685876040516200077c9190620008b3565b60006040518083038185875af1925050503d8060008114620007bb576040519150601f19603f3d011682016040523d82523d6000602084013e620007c0565b606091505b5091509150620007d2828286620007dd565b979650505050505050565b60608315620007ee57508162000522565b825115620007ff5782518084602001fd5b8160405162461bcd60e51b81526004016200067b9190620008d1565b6147a98062000ad883390190565b8035620008368162000abe565b919050565b6000602082840312156200084e57600080fd5b8135620005228162000abe565b6000602082840312156200086e57600080fd5b815180151581146200052257600080fd5b600061018082840312156200089357600080fd5b50919050565b600060208284031215620008ac57600080fd5b5035919050565b60008251620008c781846020870162000a5b565b9190910192915050565b6020815260008251806020840152620008f281604085016020870162000a5b565b601f01601f19169190910160400192915050565b610180810162000928826200091b8562000829565b6001600160a01b03169052565b602083013560208301526040830135604083015260608301356060830152620009546080840162000829565b6001600160a01b031660808301526200097060a0840162000829565b6001600160a01b031660a083015260c0838101359083015260e080840135908301526101008084013590830152610120620009ad81850162000829565b6001600160a01b031690830152610140620009ca84820162000829565b6001600160a01b031690830152610160620009e784820162000829565b6001600160a01b0316920191909152919050565b6000821982111562000a115762000a1162000aa8565b500190565b60008262000a3457634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161562000a565762000a5662000aa8565b500290565b60005b8381101562000a7857818101518382015260200162000a5e565b83811115620005a15750506000910152565b600060001982141562000aa15762000aa162000aa8565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811462000ad457600080fd5b5056fe60e06040527306677520c1449d9977e7a245f0797a65e7eff219608090815273b9eb39c42d0e9f4966d411bdfbfc71123594593660a05273a551a1683ff764a4f5ff143f57206067ff29fac560c0526200005e906011906003620002d2565b503480156200006c57600080fd5b50604051620047a9380380620047a98339810160408190526200008f9162000370565b60016000819055815181546001600160a01b039182166001600160a01b0319918216179092556020808401516002556080840151600380549184169185168217905560a0850151600480549190941694169390931782556040805163313ce56760e01b8152905163313ce567938281019392829003018186803b1580156200011657600080fd5b505afa1580156200012b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000151919062000442565b60ff166006556040810151601055610120810151600c80546001600160a01b03928316610100908102610100600160a81b031990921691909117909155610160830151600d80549184166001600160a01b0319928316179055610140840151600e8054919094169116179091556060820151600955810151600a5560e081015160c0820151106200023e5760405162461bcd60e51b815260206004820152602c60248201527f5374617274206e756d626572206d757374206265206c657373207468616e206660448201526b34b734b9b410373ab6b132b960a11b60648201526084015b60405180910390fd5b428160e0015111620002a95760405162461bcd60e51b815260206004820152602d60248201527f46696e697368206e756d626572206d757374206265206d6f7265207468616e2060448201526c63757272656e7420626c6f636b60981b606482015260840162000235565b60c081015160075560e001516008819055620151806012556301e13380601355601455620004a6565b8280548282559060005260206000209081019282156200032a579160200282015b828111156200032a57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190620002f3565b50620003389291506200033c565b5090565b5b808211156200033857600081556001016200033d565b80516001600160a01b03811681146200036b57600080fd5b919050565b600061018082840312156200038457600080fd5b6200038e6200046e565b620003998362000353565b8152602083015160208201526040830151604082015260608301516060820152620003c76080840162000353565b6080820152620003da60a0840162000353565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206200040f81850162000353565b908201526101406200042384820162000353565b908201526101606200043784820162000353565b908201529392505050565b6000602082840312156200045557600080fd5b815160ff811681146200046757600080fd5b9392505050565b60405161018081016001600160401b0381118282101715620004a057634e487b7160e01b600052604160045260246000fd5b60405290565b6142f380620004b66000396000f3fe6080604052600436106101405760003560e01c8063947a36fb116100b6578063d56b28891161006f578063d56b28891461031f578063d6df2e5814610349578063e0ee43a21461035f578063e6fd48bc14610375578063f7c618c11461038b578063ffdd5cf1146103ab57600080fd5b8063947a36fb1461027e5780639769f0b014610294578063be9a6555146102b4578063bef4876b146102ca578063c290d691146102df578063c8d88871146102ff57600080fd5b8063384711cc11610108578063384711cc146101ce57806343d7d321146101ee57806349c08238146102045780634b1a4c0c1461021a5780637ff9b596146102305780638da5cb5b1461024657600080fd5b80630fb5a6b4146101455780631726cbc81461016e578063191655871461018e5780631b9265b8146101b05780632382f645146101b8575b600080fd5b34801561015157600080fd5b5061015b60135481565b6040519081526020015b60405180910390f35b34801561017a57600080fd5b5061015b6101893660046117bb565b6103e6565b34801561019a57600080fd5b506101ae6101a93660046117bb565b61041b565b005b6101ae610518565b3480156101c457600080fd5b5061015b600a5481565b3480156101da57600080fd5b5061015b6101e93660046117bb565b61078d565b3480156101fa57600080fd5b5061015b60085481565b34801561021057600080fd5b5061015b60065481565b34801561022657600080fd5b5061015b600b5481565b34801561023c57600080fd5b5061015b60025481565b34801561025257600080fd5b50600154610266906001600160a01b031681565b6040516001600160a01b039091168152602001610165565b34801561028a57600080fd5b5061015b60125481565b3480156102a057600080fd5b50600354610266906001600160a01b031681565b3480156102c057600080fd5b5061015b60145481565b3480156102d657600080fd5b506101ae61085d565b3480156102eb57600080fd5b506101ae6102fa366004611817565b61091d565b34801561030b57600080fd5b5061026661031a366004611817565b610a9f565b34801561032b57600080fd5b50600c546103399060ff1681565b6040519015158152602001610165565b34801561035557600080fd5b5061015b60055481565b34801561036b57600080fd5b5061015b60095481565b34801561038157600080fd5b5061015b60075481565b34801561039757600080fd5b50600454610266906001600160a01b031681565b3480156103b757600080fd5b506103cb6103c63660046117bb565b610ac9565b60408051938452602084019290925290820152606001610165565b6001600160a01b0381166000908152601560205260408120600101546104159061040f8461078d565b90610b27565b92915050565b6000610426826103e6565b90506000811161048f5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e56657374696e67202372656c656173653a206e6f7468696e6720746044820152686f2072656c6561736560b81b60648201526084015b60405180910390fd5b6001600160a01b038216600090815260156020526040902060018101546104b69083610b3a565b600182015580546104c79083610b27565b81556003546104e0906001600160a01b03168484610b46565b6040518281527ffb81f9b30d73d830c3544b34d827c08142579ee75710b490bab0b3995468c5659060200160405180910390a1505050565b6002600054141561053b5760405162461bcd60e51b8152600401610486906119a1565b6002600055600c546004546001600160a01b0390811661010090920416146105965760405162461bcd60e51b815260206004820152600e60248201526d7061795245493a4e6f742052656960901b6044820152606401610486565b6007544210156105dd5760405162461bcd60e51b81526020600482015260126024820152711c185e5491524e939bdd081cdd185c9d195960721b6044820152606401610486565b600854421061061d5760405162461bcd60e51b815260206004820152600c60248201526b1c185e5491524e915b99195960a21b6044820152606401610486565b600c5460ff16156106625760405162461bcd60e51b815260206004820152600f60248201526e1c185e5491524e919a5b9a5cda1959608a1b6044820152606401610486565b34600061066e82610bae565b905080600a5410156106925760405162461bcd60e51b81526004016104869061195d565b600954600b546106a29084610b3a565b111561071157600c805460ff19166001179055600b5460095433916108fc916106d6916106cf9190610b27565b8590610b27565b6040518115909202916000818181858888f193505050501580156106fe573d6000803e3d6000fd5b50600b5460095461070e91610b27565b91505b600b5461071e9083610b3a565b600b5561072a82610bae565b90506107363382610bcf565b600c5460ff161561074957610749610cf9565b604080518381526020810183905233917fba7a32849fb0a371567222ea0cb62b2055fead07c17efb43d99728b10f09d699910160405180910390a250506001600055565b6001600160a01b038116600090815260156020908152604080832081518083019092528054808352600190910154928201839052909183906107d0908390610b3a565b90504260145411156107e757506000949350505050565b6013546014546107f691610b3a565b421061080457949350505050565b600061082760125461082160145442610b2790919063ffffffff16565b90611354565b9050600061084260125460135461135490919063ffffffff16565b9050610852816108218585611360565b979650505050505050565b600260005414156108805760405162461bcd60e51b8152600401610486906119a1565b600260005560085442116108c85760405162461bcd60e51b815260206004820152600f60248201526e1c185e4e939bdd081cdd185c9d1959608a1b6044820152606401610486565b600c5460ff161561090e5760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e48199a5b9a5cda195960821b6044820152606401610486565b610916610cf9565b6001600055565b600260005414156109405760405162461bcd60e51b8152600401610486906119a1565b60026000556007544210156109895760405162461bcd60e51b815260206004820152600f60248201526e1c185e4e939bdd081cdd185c9d1959608a1b6044820152606401610486565b60085442106109c65760405162461bcd60e51b81526020600482015260096024820152681c185e4e995b99195960ba1b6044820152606401610486565b600c5460ff1615610a0b5760405162461bcd60e51b815260206004820152600f60248201526e1c185e5491524e919a5b9a5cda1959608a1b6044820152606401610486565b6000610a1682610bae565b905080600a541015610a3a5760405162461bcd60e51b81526004016104869061195d565b600954600b54610a4a9084610b3a565b10610a6e57600c805460ff19166001179055600b54600954610a6b91610b27565b91505b600b54610a7b9083610b3a565b600b55600454610a96906001600160a01b031633308561136c565b61072a82610bae565b60118181548110610aaf57600080fd5b6000918252602090912001546001600160a01b0316905081565b6001600160a01b0381166000908152601560209081526040808320815180830190925280548083526001909101549282018390528392839291610b0c91906119d8565b610b15866103e6565b60209092015190969195509350915050565b6000610b338284611b1c565b9392505050565b6000610b3382846119d8565b6040516001600160a01b038316602482015260448101829052610ba990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526113aa565b505050565b6000610415600254610821600654600a610bc89190611a55565b8590611360565b600060125411610c475760405162461bcd60e51b815260206004820152603c60248201527f546f6b656e56657374696e67202363726561746556657374696e673a20696e7460448201527f657276616c206d7573742062652067726561746572207468616e2030000000006064820152608401610486565b6012546013541015610ccf5760405162461bcd60e51b8152602060048201526044602482018190527f546f6b656e56657374696e67202363726561746556657374696e673a20696e74908201527f657276616c2063616e6e6f7420626520626967676572207468616e20647572616064820152633a34b7b760e11b608482015260a401610486565b6001600160a01b03821660009081526015602052604090208054610cf39083610b3a565b90555050565b6001546004546003546040516bffffffffffffffffffffffff19606094851b8116602083015292841b83166034820152921b166048820152600090605c01604051602081830303815290604052805190602001209050600060405180602001610d61906117ae565b601f1982820381018352601f9091011660405290506000610d8381848461147c565b600c546004549192506000916001600160a01b03908116610100909204161415610ffb5760004790506000610ddc601054610821600654600a610dc69190611a55565b610dd66064610821886014611360565b90611360565b600d54600354919250610dfc916001600160a01b03908116911683611586565b600d546000906001600160a01b031663f305d719610e206064610821876014611360565b60035460405160e084901b6001600160e01b03191681526001600160a01b039182166004820152602481018790526000604482018190526064820152908916608482015267ffffffffffffffff421660a482015260c4016060604051808303818588803b158015610e9057600080fd5b505af1158015610ea4573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610ec99190611849565b600e54600c5460035460405163e6a4390560e01b81526001600160a01b0361010090930483166004820152908216602482015292955016925063e6a43905915060440160206040518083038186803b158015610f2457600080fd5b505afa158015610f38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5c91906117d8565b600154604080516001600160a01b03808a168252909216602083015281018390529094507f6443c245157515cfcdd90c76a3e200a6736156f16241f7237ff1810282f349bb9060600160405180910390a16001600160a01b0385166108fc610fca6064610821876050611360565b6040518115909202916000818181858888f19350505050158015610ff2573d6000803e3d6000fd5b505050506112c8565b600480546040516370a0823160e01b815230928101929092526000916001600160a01b03909116906370a082319060240160206040518083038186803b15801561104457600080fd5b505afa158015611058573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107c9190611830565b90506000611098601054610821600654600a610dc69190611a55565b600d546004549192506110b8916001600160a01b03908116911684611586565b600d546003546110d5916001600160a01b03918216911683611586565b600d546004546003546000926001600160a01b039081169263e8e337009290821691166111086064610821896014611360565b6040516001600160e01b031960e086901b1681526001600160a01b039384166004820152918316602483015260448201526064810186905260006084820181905260a482015290881660c482015267ffffffffffffffff421660e482015261010401606060405180830381600087803b15801561118457600080fd5b505af1158015611198573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111bc9190611849565b600e546004805460035460405163e6a4390560e01b81526001600160a01b0392831693810193909352811660248301529295509116925063e6a43905915060440160206040518083038186803b15801561121557600080fd5b505afa158015611229573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124d91906117d8565b9350611276856112636064610821876050611360565b6004546001600160a01b03169190610b46565b600154604080516001600160a01b038089168252909216602083015281018290527f6443c245157515cfcdd90c76a3e200a6736156f16241f7237ff1810282f349bb9060600160405180910390a15050505b60015460048054600c5460405163cf5bf23f60e01b81526001600160a01b038088169563cf5bf23f9561131c956011956002956301e1338095948516944294938116938d9361010090049091169101611893565b600060405180830381600087803b15801561133657600080fd5b505af115801561134a573d6000803e3d6000fd5b5050505050505050565b6000610b3382846119f0565b6000610b338284611afd565b6040516001600160a01b03808516602483015283166044820152606481018290526113a49085906323b872dd60e01b90608401610b72565b50505050565b60006113ff826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166116aa9092919063ffffffff16565b805190915015610ba9578080602001905181019061141d91906117f5565b610ba95760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610486565b600080844710156114cf5760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610486565b825161151d5760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610486565b8383516020850187f590506001600160a01b03811661157e5760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610486565b949350505050565b80158061160f5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b1580156115d557600080fd5b505afa1580156115e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160d9190611830565b155b61167a5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610486565b6040516001600160a01b038316602482015260448101829052610ba990849063095ea7b360e01b90606401610b72565b606061157e8484600085856001600160a01b0385163b61170c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610486565b600080866001600160a01b031685876040516117289190611877565b60006040518083038185875af1925050503d8060008114611765576040519150601f19603f3d011682016040523d82523d6000602084013e61176a565b606091505b509150915061085282828660608315611784575081610b33565b8251156117945782518084602001fd5b8160405162461bcd60e51b8152600401610486919061192a565b61273080611b8e83390190565b6000602082840312156117cd57600080fd5b8135610b3381611b75565b6000602082840312156117ea57600080fd5b8151610b3381611b75565b60006020828403121561180757600080fd5b81518015158114610b3357600080fd5b60006020828403121561182957600080fd5b5035919050565b60006020828403121561184257600080fd5b5051919050565b60008060006060848603121561185e57600080fd5b8351925060208401519150604084015190509250925092565b60008251611889818460208701611b33565b9190910192915050565b610100808252895490820181905260008a815260208082209192610120850192845b828110156118da5781546001600160a01b0316855293830193600191820191016118b5565b5050508301999099525067ffffffffffffffff96871660408201526001600160a01b03958616606082015293909516608084015290831660a0830152821660c0820152911660e090910152919050565b6020815260008251806020840152611949816040850160208701611b33565b601f01601f19169190910160400192915050565b60208082526024908201527f7061795245493a207065724d61784469737472696275746564546f6b656e416d6040820152631bdd5b9d60e21b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600082198211156119eb576119eb611b5f565b500190565b600082611a0d57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115611a4d578160001904821115611a3357611a33611b5f565b80851615611a4057918102915b93841c9390800290611a17565b509250929050565b6000610b338383600082611a6b57506001610415565b81611a7857506000610415565b8160018114611a8e5760028114611a9857611ab4565b6001915050610415565b60ff841115611aa957611aa9611b5f565b50506001821b610415565b5060208310610133831016604e8410600b8410161715611ad7575081810a610415565b611ae18383611a12565b8060001904821115611af557611af5611b5f565b029392505050565b6000816000190483118215151615611b1757611b17611b5f565b500290565b600082821015611b2e57611b2e611b5f565b500390565b60005b83811015611b4e578181015183820152602001611b36565b838111156113a45750506000910152565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b0381168114611b8a57600080fd5b5056fe60a060405234801561001057600080fd5b5033606081901b6080526126fe61003260003960006115ce01526126fe6000f3fe6080604052600436106101dc5760003560e01c80639ace38c211610102578063c642747411610095578063dc8452cd11610064578063dc8452cd14610625578063e20056e61461063b578063ecd0c0c31461065b578063ee22610b1461067b57610220565b8063c6427474146105a9578063cf5bf23f146105c9578063d6c3179d146105e9578063d74f8edd1461061057610220565b8063b77bf600116100d1578063b77bf6001461052e578063ba51a6df14610544578063be9a655514610564578063c01a8c841461058957610220565b80639ace38c21461048f578063a0e67e2b146104bf578063a8abe69a146104e1578063b5dc40c31461050e57610220565b806337bdc99b1161017a5780637065cb48116101495780637065cb481461040f578063784547a71461042f578063810ec23b1461044f5780638b51d13f1461046f57610220565b806337bdc99b1461039c57806338af3eed146103bc57806343ad92d5146103da57806354741525146103ef57610220565b8063173825d9116101b6578063173825d9146102e157806320ea8d86146103015780632f54bf6e146103215780633411c81c1461036157610220565b8063025e7c27146102585780630a17b06b146102955780630fb5a6b4146102c357610220565b3661022057341561021e5760405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c906020015b60405180910390a25b005b341561021e5760405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90602001610215565b34801561026457600080fd5b506102786102733660046123af565b61069b565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102a157600080fd5b506102b56102b036600461244e565b6106c5565b60405190815260200161028c565b3480156102cf57600080fd5b506007546001600160401b03166102b5565b3480156102ed57600080fd5b5061021e6102fc36600461210e565b6106d7565b34801561030d57600080fd5b5061021e61031c3660046123af565b61088e565b34801561032d57600080fd5b5061035161033c36600461210e565b60026020526000908152604090205460ff1681565b604051901515815260200161028c565b34801561036d57600080fd5b5061035161037c3660046123e1565b600160209081526000928352604080842090915290825290205460ff1681565b3480156103a857600080fd5b5061021e6103b73660046123af565b610944565b3480156103c857600080fd5b506006546001600160a01b0316610278565b3480156103e657600080fd5b5061021e610bec565b3480156103fb57600080fd5b506102b561040a366004612376565b610c95565b34801561041b57600080fd5b5061021e61042a36600461210e565b610d12565b34801561043b57600080fd5b5061035161044a3660046123af565b610e2b565b34801561045b57600080fd5b506102b561046a36600461220a565b610eca565b34801561047b57600080fd5b506102b561048a3660046123af565b610f55565b34801561049b57600080fd5b506104af6104aa3660046123af565b610fdb565b60405161028c94939291906124b1565b3480156104cb57600080fd5b506104d4611099565b60405161028c91906124eb565b3480156104ed57600080fd5b506105016104fc366004612404565b6110fb565b60405161028c9190612538565b34801561051a57600080fd5b506104d46105293660046123af565b611291565b34801561053a57600080fd5b506102b560055481565b34801561055057600080fd5b5061021e61055f3660046123af565b611467565b34801561057057600080fd5b50600654600160a01b90046001600160401b03166102b5565b34801561059557600080fd5b5061021e6105a43660046123af565b6114e4565b3480156105b557600080fd5b506102b56105c436600461215c565b6115ab565b3480156105d557600080fd5b5061021e6105e4366004612234565b6115c3565b3480156105f557600080fd5b5060075461027890600160401b90046001600160a01b031681565b34801561061c57600080fd5b506102b5603281565b34801561063157600080fd5b506102b560045481565b34801561064757600080fd5b5061021e610656366004612129565b611698565b34801561066757600080fd5b50600854610278906001600160a01b031681565b34801561068757600080fd5b5061021e6106963660046123af565b61182b565b600381815481106106ab57600080fd5b6000918252602090912001546001600160a01b0316905081565b60006106d147836119ee565b92915050565b3330146106e357600080fd5b6001600160a01b038116600090815260026020526040902054819060ff1661070a57600080fd5b6001600160a01b0382166000908152600260205260408120805460ff191690555b60035461073a906001906125cb565b81101561080a57826001600160a01b03166003828154811061075e5761075e61268e565b6000918252602090912001546001600160a01b031614156107f85760038054610789906001906125cb565b815481106107995761079961268e565b600091825260209091200154600380546001600160a01b0390921691839081106107c5576107c561268e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061080a565b8061080281612647565b91505061072b565b50600380548061081c5761081c612678565b600082815260209020810160001990810180546001600160a01b031916905501905560035460045411156108565760035461085690611467565b6040516001600160a01b038316907f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9090600090a25050565b3360008181526002602052604090205460ff166108aa57600080fd5b60008281526001602090815260408083203380855292529091205483919060ff166108d457600080fd5b600084815260208190526040902060030154849060ff16156108f557600080fd5b6000858152600160209081526040808320338085529252808320805460ff191690555187927ff6a317157440607f36269043eb55f1287a5a19ba2216afeab88cd46cbcfb88e991a35050505050565b33301461095057600080fd5b60004261096d6006546001600160401b03600160a01b9091041690565b106109ac5760405162461bcd60e51b81526004016109a390602080825260049082015263656e642160e01b604082015260600190565b60405180910390fd5b6009546008546001600160a01b0390811691161415610a4d57504780821115610a0d5760405162461bcd60e51b815260206004820152601360248201527230b6b7bab73a10363a103130b630b731b2a7b360691b60448201526064016109a3565b6006546040516001600160a01b039091169083156108fc029084906000818181858888f19350505050158015610a47573d6000803e3d6000fd5b50610bb5565b6008546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015610a9057600080fd5b505afa158015610aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac891906123c8565b905080821115610b105760405162461bcd60e51b815260206004820152601360248201527230b6b7bab73a10363a103130b630b731b2a7b360691b60448201526064016109a3565b6008546001600160a01b031663a9059cbb610b336006546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381600087803b158015610b7b57600080fd5b505af1158015610b8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb39190612359565b505b6040518281527fda9d4e5f101b8b9b1c5b76d0c5a9f7923571acfc02376aa076b75a8c080c956b9060200160405180910390a15050565b333014610bf857600080fd5b600754600090610c1890600160401b90046001600160a01b031642610eca565b600754604051828152919250600160401b90046001600160a01b0316907fc0e523490dd523c33b1878c9eb14ff46991e3f5b2cd33710918618f2a39cba1b9060200160405180910390a2600754610c92906001600160a01b03600160401b90910416610c8c6006546001600160a01b031690565b83611a3d565b50565b6000805b600554811015610d0b57838015610cc2575060008181526020819052604090206003015460ff16155b80610ce65750828015610ce6575060008181526020819052604090206003015460ff165b15610cf957610cf66001836125b3565b91505b80610d0381612647565b915050610c99565b5092915050565b333014610d1e57600080fd5b6001600160a01b038116600090815260026020526040902054819060ff1615610d4657600080fd5b816001600160a01b038116610d5a57600080fd5b600354610d689060016125b3565b60045460328211158015610d7c5750818111155b8015610d8757508015155b8015610d9257508115155b610d9b57600080fd5b6001600160a01b038516600081815260026020526040808220805460ff1916600190811790915560038054918201815583527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b03191684179055517ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d9190a25050505050565b600080805b600354811015610ec05760008481526001602052604081206003805491929184908110610e5f57610e5f61268e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615610e9a57610e976001836125b3565b91505b600454821415610eae575060019392505050565b80610eb881612647565b915050610e30565b5060009392505050565b6040516370a0823160e01b8152306004820152600090610f4e906001600160a01b038516906370a082319060240160206040518083038186803b158015610f1057600080fd5b505afa158015610f24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4891906123c8565b836119ee565b9392505050565b6000805b600354811015610fd55760008381526001602052604081206003805491929184908110610f8857610f8861268e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615610fc357610fc06001836125b3565b91505b80610fcd81612647565b915050610f59565b50919050565b6000602081905290815260409020805460018201546002830180546001600160a01b0390931693919261100d90612612565b80601f016020809104026020016040519081016040528092919081815260200182805461103990612612565b80156110865780601f1061105b57610100808354040283529160200191611086565b820191906000526020600020905b81548152906001019060200180831161106957829003601f168201915b5050506003909301549192505060ff1684565b606060038054806020026020016040519081016040528092919081815260200182805480156110f157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116110d3575b5050505050905090565b606060006005546001600160401b03811115611119576111196126a4565b604051908082528060200260200182016040528015611142578160200160208202803683370190505b5090506000805b6005548110156111d957858015611172575060008181526020819052604090206003015460ff16155b806111965750848015611196575060008181526020819052604090206003015460ff165b156111c757808383815181106111ae576111ae61268e565b60209081029190910101526111c46001836125b3565b91505b806111d181612647565b915050611149565b6111e388886125cb565b6001600160401b038111156111fa576111fa6126a4565b604051908082528060200260200182016040528015611223578160200160208202803683370190505b5093508790505b86811015611286578281815181106112445761124461268e565b602002602001015184898361125991906125cb565b815181106112695761126961268e565b60209081029190910101528061127e81612647565b91505061122a565b505050949350505050565b6003546060906000906001600160401b038111156112b1576112b16126a4565b6040519080825280602002602001820160405280156112da578160200160208202803683370190505b5090506000805b6003548110156113b857600085815260016020526040812060038054919291849081106113105761131061268e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff16156113a657600381815481106113505761135061268e565b9060005260206000200160009054906101000a90046001600160a01b03168383815181106113805761138061268e565b6001600160a01b03909216602092830291909101909101526113a36001836125b3565b91505b806113b081612647565b9150506112e1565b816001600160401b038111156113d0576113d06126a4565b6040519080825280602002602001820160405280156113f9578160200160208202803683370190505b509350600090505b8181101561145f5782818151811061141b5761141b61268e565b60200260200101518482815181106114355761143561268e565b6001600160a01b03909216602092830291909101909101528061145781612647565b915050611401565b505050919050565b33301461147357600080fd5b60035481603282118015906114885750818111155b801561149357508015155b801561149e57508115155b6114a757600080fd5b60048390556040518381527fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a9060200160405180910390a1505050565b3360008181526002602052604090205460ff1661150057600080fd5b60008281526020819052604090205482906001600160a01b031661152357600080fd5b60008381526001602090815260408083203380855292529091205484919060ff161561154e57600080fd5b6000858152600160208181526040808420338086529252808420805460ff1916909317909255905187927f4a504a94899432a9846e1aa406dceb1bcfd538bb839071d49d1e5e23f5be30ef91a36115a48561182b565b5050505050565b60006115b8848484611a94565b9050610f4e816114e4565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146116275760405162461bcd60e51b81526020600482015260096024820152681bdb9b1e481c1bdbdb60ba1b60448201526064016109a3565b6116318888611b87565b61163c858588611cbe565b600880546001600160a01b039485166001600160a01b03199182161790915560098054928516929091169190911790556007805491909216600160401b0268010000000000000000600160e01b03199091161790555050505050565b3330146116a457600080fd5b6001600160a01b038216600090815260026020526040902054829060ff166116cb57600080fd5b6001600160a01b038216600090815260026020526040902054829060ff16156116f357600080fd5b60005b60035481101561179157846001600160a01b03166003828154811061171d5761171d61268e565b6000918252602090912001546001600160a01b0316141561177f57836003828154811061174c5761174c61268e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611791565b8061178981612647565b9150506116f6565b506001600160a01b03808516600081815260026020526040808220805460ff1990811690915593871682528082208054909416600117909355915190917f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9091a26040516001600160a01b038416907ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d90600090a250505050565b3360008181526002602052604090205460ff1661184757600080fd5b60008281526001602090815260408083203380855292529091205483919060ff1661187157600080fd5b600084815260208190526040902060030154849060ff161561189257600080fd5b61189b85610e2b565b156115a457600085815260208190526040902060038101805460ff19166001908117909155815490820154600283018054611979936001600160a01b03169291906118e590612612565b90508460020180546118f690612612565b80601f016020809104026020016040519081016040528092919081815260200182805461192290612612565b801561196f5780601f106119445761010080835404028352916020019161196f565b820191906000526020600020905b81548152906001019060200180831161195257829003601f168201915b5050505050611d77565b156119ae5760405186907f33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed7590600090a26119e6565b60405186907f526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b7923690600090a260038101805460ff191690555b505050505050565b6000611a026007546001600160401b031690565b600654600160a01b90046001600160401b0316611a1f91906125b3565b826001600160401b031610611a355750816106d1565b5060006106d1565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611a8f908490611d9a565b505050565b6000836001600160a01b038116611aaa57600080fd5b600554604080516080810182526001600160a01b038881168252602080830189815283850189815260006060860181905287815280845295909520845181546001600160a01b03191694169390931783555160018301559251805194965091939092611b1d926002850192910190611fed565b50606091909101516003909101805460ff19169115159190911790556005805460019190600090611b4f9084906125b3565b909155505060405182907fc0ba8fe4b176c1714197d43b9cc6bcf797a4a7461c5fe8d0ef6e184ae7601e5190600090a2509392505050565b81518160328211158015611b9b5750818111155b8015611ba657508015155b8015611bb157508115155b611bba57600080fd5b60005b8451811015611ca15760026000868381518110611bdc57611bdc61268e565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16158015611c3c575060006001600160a01b0316858281518110611c2857611c2861268e565b60200260200101516001600160a01b031614155b611c4557600080fd5b600160026000878481518110611c5d57611c5d61268e565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580611c9981612647565b915050611bbd565b508351611cb5906003906020870190612071565b50505060045550565b6001600160a01b038316611d275760405162461bcd60e51b815260206004820152602a60248201527f56657374696e6757616c6c65743a2062656e6566696369617279206973207a65604482015269726f206164647265737360b01b60648201526084016109a3565b600680546001600160a01b03949094166001600160e01b031990941693909317600160a01b6001600160401b0393841602179092556007805467ffffffffffffffff191692909116919091179055565b6000806040516020840160008287838a8c6187965a03f198975050505050505050565b6000611def826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611e6c9092919063ffffffff16565b805190915015611a8f5780806020019051810190611e0d9190612359565b611a8f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109a3565b6060611e7b8484600085611e83565b949350505050565b606082471015611ee45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016109a3565b6001600160a01b0385163b611f3b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109a3565b600080866001600160a01b03168587604051611f579190612495565b60006040518083038185875af1925050503d8060008114611f94576040519150601f19603f3d011682016040523d82523d6000602084013e611f99565b606091505b5091509150611fa9828286611fb4565b979650505050505050565b60608315611fc3575081610f4e565b825115611fd35782518084602001fd5b8160405162461bcd60e51b81526004016109a39190612570565b828054611ff990612612565b90600052602060002090601f01602090048101928261201b5760008555612061565b82601f1061203457805160ff1916838001178555612061565b82800160010185558215612061579182015b82811115612061578251825591602001919060010190612046565b5061206d9291506120c6565b5090565b828054828255906000526020600020908101928215612061579160200282015b8281111561206157825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190612091565b5b8082111561206d57600081556001016120c7565b80356001600160a01b03811681146120f257600080fd5b919050565b80356001600160401b03811681146120f257600080fd5b60006020828403121561212057600080fd5b610f4e826120db565b6000806040838503121561213c57600080fd5b612145836120db565b9150612153602084016120db565b90509250929050565b60008060006060848603121561217157600080fd5b61217a846120db565b9250602080850135925060408501356001600160401b038082111561219e57600080fd5b818701915087601f8301126121b257600080fd5b8135818111156121c4576121c46126a4565b6121d6601f8201601f19168501612583565b915080825288848285010111156121ec57600080fd5b80848401858401376000848284010152508093505050509250925092565b6000806040838503121561221d57600080fd5b612226836120db565b9150612153602084016120f7565b600080600080600080600080610100898b03121561225157600080fd5b6001600160401b03808a35111561226757600080fd5b89358a018b601f82011261227a57600080fd5b80358281111561228c5761228c6126a4565b8060051b925061229e60208401612583565b80828252602082019150602084018f60208787010111156122be57600080fd5b600095505b838610156122e9576122d4816120db565b835260019590950194602092830192016122c3565b509b5050505060208a01359750612304905060408a016120f7565b955061231260608a016120db565b945061232060808a016120f7565b935061232e60a08a016120db565b925061233c60c08a016120db565b915061234a60e08a016120db565b90509295985092959890939650565b60006020828403121561236b57600080fd5b8151610f4e816126ba565b6000806040838503121561238957600080fd5b8235612394816126ba565b915060208301356123a4816126ba565b809150509250929050565b6000602082840312156123c157600080fd5b5035919050565b6000602082840312156123da57600080fd5b5051919050565b600080604083850312156123f457600080fd5b82359150612153602084016120db565b6000806000806080858703121561241a57600080fd5b84359350602085013592506040850135612433816126ba565b91506060850135612443816126ba565b939692955090935050565b60006020828403121561246057600080fd5b610f4e826120f7565b600081518084526124818160208601602086016125e2565b601f01601f19169290920160200192915050565b600082516124a78184602087016125e2565b9190910192915050565b60018060a01b03851681528360208201526080604082015260006124d86080830185612469565b9050821515606083015295945050505050565b6020808252825182820181905260009190848201906040850190845b8181101561252c5783516001600160a01b031683529284019291840191600101612507565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561252c57835183529284019291840191600101612554565b602081526000610f4e6020830184612469565b604051601f8201601f191681016001600160401b03811182821017156125ab576125ab6126a4565b604052919050565b600082198211156125c6576125c6612662565b500190565b6000828210156125dd576125dd612662565b500390565b60005b838110156125fd5781810151838201526020016125e5565b8381111561260c576000848401525b50505050565b600181811c9082168061262657607f821691505b60208210811415610fd557634e487b7160e01b600052602260045260246000fd5b600060001982141561265b5761265b612662565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b8015158114610c9257600080fdfea2646970667358221220ad5f1b47d2adf92bad4533ffe2cbf7d6d45660df712721af9b5b08a8d8a1354664736f6c63430008070033a264697066735822122081140cab24b2f20e9a5b523d33c6c2a7ee164454b8124f96173f9b1fbcb19e2964736f6c63430008070033a264697066735822122083966f1bf2e54ad35d555dfb0382060ad6b77a5f07635e8bb19f15134b060f3a64736f6c63430008070033

Deployed ByteCode

0x60806040523480156200001157600080fd5b5060043610620000465760003560e01c8063707f507c146200004b5780637749cf231462000064578063de7fe3e7146200007a575b600080fd5b620000626200005c3660046200087f565b6200010b565b005b6000546040519081526020015b60405180910390f35b620000916200008b36600462000899565b6200039f565b60405162000071919081516001600160a01b039081168252602080840151821690830152604080840151908301526060808401519083015260808084015182169083015260a0808401519091169082015260c0808301519082015260e0808301519082015261010091820151918101919091526101200190565b6000816040516200011c906200081b565b62000128919062000906565b604051809103906000f08015801562000145573d6000803e3d6000fd5b509050620001746060830135602084013560408501356200016d60a08701608088016200083b565b856200049d565b7fdf28fe625edaab14d82ac291ae937512fc672b0977357600f5f48a68209aa599620001a460208401846200083b565b8260208501356060860135620001c160a08801608089016200083b565b620001d360c0890160a08a016200083b565b604080516001600160a01b039788168152958716602087015285019390935260608401919091528316608083015290911660a082015260c0848101359082015260e0808501359082015261010080850135908201526101200160405180910390a1604080516101208101909152806200025060208501856200083b565b6001600160a01b03168152602001826001600160a01b0316815260200183602001358152602001836060013581526020018360800160208101906200029691906200083b565b6001600160a01b03168152602001620002b660c0850160a086016200083b565b6001600160a01b03908116825260c08581013560208085019190915260e080880135604080870191909152610100808a013560609788015260008054815260018086528382208a5181546001600160a01b0319908116918b16919091178255968b015191810180548816928a16929092179091559289015160028401559688015160038301556080880151600483018054861691881691909117905560a088015160058301805490951696169590951790925591850151600682015590840151600782015592015160089092019190915580549080620003968362000a8a565b91905055505050565b6200041360405180610120016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b5060009081526001602081815260409283902083516101208101855281546001600160a01b0390811682529382015484169281019290925260028101549382019390935260038301546060820152600483015482166080820152600583015490911660a0820152600682015460c0820152600782015460e082015260089091015461010082015290565b6000620004f3620004d385620004cc6064816014620004c58d670de0b6b3a764000062000514565b9062000514565b9062000529565b620004ec87620004cc8a670de0b6b3a764000062000514565b9062000537565b90506200050c6001600160a01b03841633848462000545565b505050505050565b600062000522828462000a39565b9392505050565b600062000522828462000a16565b6000620005228284620009fb565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052620005a1908590620005a7565b50505050565b6000620005fe826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620006899092919063ffffffff16565b8051909150156200068457808060200190518101906200061f91906200085b565b620006845760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084015b60405180910390fd5b505050565b60606200069a8484600085620006a2565b949350505050565b606082471015620007055760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016200067b565b6001600160a01b0385163b6200075e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016200067b565b600080866001600160a01b031685876040516200077c9190620008b3565b60006040518083038185875af1925050503d8060008114620007bb576040519150601f19603f3d011682016040523d82523d6000602084013e620007c0565b606091505b5091509150620007d2828286620007dd565b979650505050505050565b60608315620007ee57508162000522565b825115620007ff5782518084602001fd5b8160405162461bcd60e51b81526004016200067b9190620008d1565b6147a98062000ad883390190565b8035620008368162000abe565b919050565b6000602082840312156200084e57600080fd5b8135620005228162000abe565b6000602082840312156200086e57600080fd5b815180151581146200052257600080fd5b600061018082840312156200089357600080fd5b50919050565b600060208284031215620008ac57600080fd5b5035919050565b60008251620008c781846020870162000a5b565b9190910192915050565b6020815260008251806020840152620008f281604085016020870162000a5b565b601f01601f19169190910160400192915050565b610180810162000928826200091b8562000829565b6001600160a01b03169052565b602083013560208301526040830135604083015260608301356060830152620009546080840162000829565b6001600160a01b031660808301526200097060a0840162000829565b6001600160a01b031660a083015260c0838101359083015260e080840135908301526101008084013590830152610120620009ad81850162000829565b6001600160a01b031690830152610140620009ca84820162000829565b6001600160a01b031690830152610160620009e784820162000829565b6001600160a01b0316920191909152919050565b6000821982111562000a115762000a1162000aa8565b500190565b60008262000a3457634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161562000a565762000a5662000aa8565b500290565b60005b8381101562000a7857818101518382015260200162000a5e565b83811115620005a15750506000910152565b600060001982141562000aa15762000aa162000aa8565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811462000ad457600080fd5b5056fe60e06040527306677520c1449d9977e7a245f0797a65e7eff219608090815273b9eb39c42d0e9f4966d411bdfbfc71123594593660a05273a551a1683ff764a4f5ff143f57206067ff29fac560c0526200005e906011906003620002d2565b503480156200006c57600080fd5b50604051620047a9380380620047a98339810160408190526200008f9162000370565b60016000819055815181546001600160a01b039182166001600160a01b0319918216179092556020808401516002556080840151600380549184169185168217905560a0850151600480549190941694169390931782556040805163313ce56760e01b8152905163313ce567938281019392829003018186803b1580156200011657600080fd5b505afa1580156200012b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000151919062000442565b60ff166006556040810151601055610120810151600c80546001600160a01b03928316610100908102610100600160a81b031990921691909117909155610160830151600d80549184166001600160a01b0319928316179055610140840151600e8054919094169116179091556060820151600955810151600a5560e081015160c0820151106200023e5760405162461bcd60e51b815260206004820152602c60248201527f5374617274206e756d626572206d757374206265206c657373207468616e206660448201526b34b734b9b410373ab6b132b960a11b60648201526084015b60405180910390fd5b428160e0015111620002a95760405162461bcd60e51b815260206004820152602d60248201527f46696e697368206e756d626572206d757374206265206d6f7265207468616e2060448201526c63757272656e7420626c6f636b60981b606482015260840162000235565b60c081015160075560e001516008819055620151806012556301e13380601355601455620004a6565b8280548282559060005260206000209081019282156200032a579160200282015b828111156200032a57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190620002f3565b50620003389291506200033c565b5090565b5b808211156200033857600081556001016200033d565b80516001600160a01b03811681146200036b57600080fd5b919050565b600061018082840312156200038457600080fd5b6200038e6200046e565b620003998362000353565b8152602083015160208201526040830151604082015260608301516060820152620003c76080840162000353565b6080820152620003da60a0840162000353565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206200040f81850162000353565b908201526101406200042384820162000353565b908201526101606200043784820162000353565b908201529392505050565b6000602082840312156200045557600080fd5b815160ff811681146200046757600080fd5b9392505050565b60405161018081016001600160401b0381118282101715620004a057634e487b7160e01b600052604160045260246000fd5b60405290565b6142f380620004b66000396000f3fe6080604052600436106101405760003560e01c8063947a36fb116100b6578063d56b28891161006f578063d56b28891461031f578063d6df2e5814610349578063e0ee43a21461035f578063e6fd48bc14610375578063f7c618c11461038b578063ffdd5cf1146103ab57600080fd5b8063947a36fb1461027e5780639769f0b014610294578063be9a6555146102b4578063bef4876b146102ca578063c290d691146102df578063c8d88871146102ff57600080fd5b8063384711cc11610108578063384711cc146101ce57806343d7d321146101ee57806349c08238146102045780634b1a4c0c1461021a5780637ff9b596146102305780638da5cb5b1461024657600080fd5b80630fb5a6b4146101455780631726cbc81461016e578063191655871461018e5780631b9265b8146101b05780632382f645146101b8575b600080fd5b34801561015157600080fd5b5061015b60135481565b6040519081526020015b60405180910390f35b34801561017a57600080fd5b5061015b6101893660046117bb565b6103e6565b34801561019a57600080fd5b506101ae6101a93660046117bb565b61041b565b005b6101ae610518565b3480156101c457600080fd5b5061015b600a5481565b3480156101da57600080fd5b5061015b6101e93660046117bb565b61078d565b3480156101fa57600080fd5b5061015b60085481565b34801561021057600080fd5b5061015b60065481565b34801561022657600080fd5b5061015b600b5481565b34801561023c57600080fd5b5061015b60025481565b34801561025257600080fd5b50600154610266906001600160a01b031681565b6040516001600160a01b039091168152602001610165565b34801561028a57600080fd5b5061015b60125481565b3480156102a057600080fd5b50600354610266906001600160a01b031681565b3480156102c057600080fd5b5061015b60145481565b3480156102d657600080fd5b506101ae61085d565b3480156102eb57600080fd5b506101ae6102fa366004611817565b61091d565b34801561030b57600080fd5b5061026661031a366004611817565b610a9f565b34801561032b57600080fd5b50600c546103399060ff1681565b6040519015158152602001610165565b34801561035557600080fd5b5061015b60055481565b34801561036b57600080fd5b5061015b60095481565b34801561038157600080fd5b5061015b60075481565b34801561039757600080fd5b50600454610266906001600160a01b031681565b3480156103b757600080fd5b506103cb6103c63660046117bb565b610ac9565b60408051938452602084019290925290820152606001610165565b6001600160a01b0381166000908152601560205260408120600101546104159061040f8461078d565b90610b27565b92915050565b6000610426826103e6565b90506000811161048f5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e56657374696e67202372656c656173653a206e6f7468696e6720746044820152686f2072656c6561736560b81b60648201526084015b60405180910390fd5b6001600160a01b038216600090815260156020526040902060018101546104b69083610b3a565b600182015580546104c79083610b27565b81556003546104e0906001600160a01b03168484610b46565b6040518281527ffb81f9b30d73d830c3544b34d827c08142579ee75710b490bab0b3995468c5659060200160405180910390a1505050565b6002600054141561053b5760405162461bcd60e51b8152600401610486906119a1565b6002600055600c546004546001600160a01b0390811661010090920416146105965760405162461bcd60e51b815260206004820152600e60248201526d7061795245493a4e6f742052656960901b6044820152606401610486565b6007544210156105dd5760405162461bcd60e51b81526020600482015260126024820152711c185e5491524e939bdd081cdd185c9d195960721b6044820152606401610486565b600854421061061d5760405162461bcd60e51b815260206004820152600c60248201526b1c185e5491524e915b99195960a21b6044820152606401610486565b600c5460ff16156106625760405162461bcd60e51b815260206004820152600f60248201526e1c185e5491524e919a5b9a5cda1959608a1b6044820152606401610486565b34600061066e82610bae565b905080600a5410156106925760405162461bcd60e51b81526004016104869061195d565b600954600b546106a29084610b3a565b111561071157600c805460ff19166001179055600b5460095433916108fc916106d6916106cf9190610b27565b8590610b27565b6040518115909202916000818181858888f193505050501580156106fe573d6000803e3d6000fd5b50600b5460095461070e91610b27565b91505b600b5461071e9083610b3a565b600b5561072a82610bae565b90506107363382610bcf565b600c5460ff161561074957610749610cf9565b604080518381526020810183905233917fba7a32849fb0a371567222ea0cb62b2055fead07c17efb43d99728b10f09d699910160405180910390a250506001600055565b6001600160a01b038116600090815260156020908152604080832081518083019092528054808352600190910154928201839052909183906107d0908390610b3a565b90504260145411156107e757506000949350505050565b6013546014546107f691610b3a565b421061080457949350505050565b600061082760125461082160145442610b2790919063ffffffff16565b90611354565b9050600061084260125460135461135490919063ffffffff16565b9050610852816108218585611360565b979650505050505050565b600260005414156108805760405162461bcd60e51b8152600401610486906119a1565b600260005560085442116108c85760405162461bcd60e51b815260206004820152600f60248201526e1c185e4e939bdd081cdd185c9d1959608a1b6044820152606401610486565b600c5460ff161561090e5760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e48199a5b9a5cda195960821b6044820152606401610486565b610916610cf9565b6001600055565b600260005414156109405760405162461bcd60e51b8152600401610486906119a1565b60026000556007544210156109895760405162461bcd60e51b815260206004820152600f60248201526e1c185e4e939bdd081cdd185c9d1959608a1b6044820152606401610486565b60085442106109c65760405162461bcd60e51b81526020600482015260096024820152681c185e4e995b99195960ba1b6044820152606401610486565b600c5460ff1615610a0b5760405162461bcd60e51b815260206004820152600f60248201526e1c185e5491524e919a5b9a5cda1959608a1b6044820152606401610486565b6000610a1682610bae565b905080600a541015610a3a5760405162461bcd60e51b81526004016104869061195d565b600954600b54610a4a9084610b3a565b10610a6e57600c805460ff19166001179055600b54600954610a6b91610b27565b91505b600b54610a7b9083610b3a565b600b55600454610a96906001600160a01b031633308561136c565b61072a82610bae565b60118181548110610aaf57600080fd5b6000918252602090912001546001600160a01b0316905081565b6001600160a01b0381166000908152601560209081526040808320815180830190925280548083526001909101549282018390528392839291610b0c91906119d8565b610b15866103e6565b60209092015190969195509350915050565b6000610b338284611b1c565b9392505050565b6000610b3382846119d8565b6040516001600160a01b038316602482015260448101829052610ba990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526113aa565b505050565b6000610415600254610821600654600a610bc89190611a55565b8590611360565b600060125411610c475760405162461bcd60e51b815260206004820152603c60248201527f546f6b656e56657374696e67202363726561746556657374696e673a20696e7460448201527f657276616c206d7573742062652067726561746572207468616e2030000000006064820152608401610486565b6012546013541015610ccf5760405162461bcd60e51b8152602060048201526044602482018190527f546f6b656e56657374696e67202363726561746556657374696e673a20696e74908201527f657276616c2063616e6e6f7420626520626967676572207468616e20647572616064820152633a34b7b760e11b608482015260a401610486565b6001600160a01b03821660009081526015602052604090208054610cf39083610b3a565b90555050565b6001546004546003546040516bffffffffffffffffffffffff19606094851b8116602083015292841b83166034820152921b166048820152600090605c01604051602081830303815290604052805190602001209050600060405180602001610d61906117ae565b601f1982820381018352601f9091011660405290506000610d8381848461147c565b600c546004549192506000916001600160a01b03908116610100909204161415610ffb5760004790506000610ddc601054610821600654600a610dc69190611a55565b610dd66064610821886014611360565b90611360565b600d54600354919250610dfc916001600160a01b03908116911683611586565b600d546000906001600160a01b031663f305d719610e206064610821876014611360565b60035460405160e084901b6001600160e01b03191681526001600160a01b039182166004820152602481018790526000604482018190526064820152908916608482015267ffffffffffffffff421660a482015260c4016060604051808303818588803b158015610e9057600080fd5b505af1158015610ea4573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610ec99190611849565b600e54600c5460035460405163e6a4390560e01b81526001600160a01b0361010090930483166004820152908216602482015292955016925063e6a43905915060440160206040518083038186803b158015610f2457600080fd5b505afa158015610f38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5c91906117d8565b600154604080516001600160a01b03808a168252909216602083015281018390529094507f6443c245157515cfcdd90c76a3e200a6736156f16241f7237ff1810282f349bb9060600160405180910390a16001600160a01b0385166108fc610fca6064610821876050611360565b6040518115909202916000818181858888f19350505050158015610ff2573d6000803e3d6000fd5b505050506112c8565b600480546040516370a0823160e01b815230928101929092526000916001600160a01b03909116906370a082319060240160206040518083038186803b15801561104457600080fd5b505afa158015611058573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107c9190611830565b90506000611098601054610821600654600a610dc69190611a55565b600d546004549192506110b8916001600160a01b03908116911684611586565b600d546003546110d5916001600160a01b03918216911683611586565b600d546004546003546000926001600160a01b039081169263e8e337009290821691166111086064610821896014611360565b6040516001600160e01b031960e086901b1681526001600160a01b039384166004820152918316602483015260448201526064810186905260006084820181905260a482015290881660c482015267ffffffffffffffff421660e482015261010401606060405180830381600087803b15801561118457600080fd5b505af1158015611198573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111bc9190611849565b600e546004805460035460405163e6a4390560e01b81526001600160a01b0392831693810193909352811660248301529295509116925063e6a43905915060440160206040518083038186803b15801561121557600080fd5b505afa158015611229573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124d91906117d8565b9350611276856112636064610821876050611360565b6004546001600160a01b03169190610b46565b600154604080516001600160a01b038089168252909216602083015281018290527f6443c245157515cfcdd90c76a3e200a6736156f16241f7237ff1810282f349bb9060600160405180910390a15050505b60015460048054600c5460405163cf5bf23f60e01b81526001600160a01b038088169563cf5bf23f9561131c956011956002956301e1338095948516944294938116938d9361010090049091169101611893565b600060405180830381600087803b15801561133657600080fd5b505af115801561134a573d6000803e3d6000fd5b5050505050505050565b6000610b3382846119f0565b6000610b338284611afd565b6040516001600160a01b03808516602483015283166044820152606481018290526113a49085906323b872dd60e01b90608401610b72565b50505050565b60006113ff826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166116aa9092919063ffffffff16565b805190915015610ba9578080602001905181019061141d91906117f5565b610ba95760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610486565b600080844710156114cf5760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610486565b825161151d5760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610486565b8383516020850187f590506001600160a01b03811661157e5760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610486565b949350505050565b80158061160f5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b1580156115d557600080fd5b505afa1580156115e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160d9190611830565b155b61167a5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610486565b6040516001600160a01b038316602482015260448101829052610ba990849063095ea7b360e01b90606401610b72565b606061157e8484600085856001600160a01b0385163b61170c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610486565b600080866001600160a01b031685876040516117289190611877565b60006040518083038185875af1925050503d8060008114611765576040519150601f19603f3d011682016040523d82523d6000602084013e61176a565b606091505b509150915061085282828660608315611784575081610b33565b8251156117945782518084602001fd5b8160405162461bcd60e51b8152600401610486919061192a565b61273080611b8e83390190565b6000602082840312156117cd57600080fd5b8135610b3381611b75565b6000602082840312156117ea57600080fd5b8151610b3381611b75565b60006020828403121561180757600080fd5b81518015158114610b3357600080fd5b60006020828403121561182957600080fd5b5035919050565b60006020828403121561184257600080fd5b5051919050565b60008060006060848603121561185e57600080fd5b8351925060208401519150604084015190509250925092565b60008251611889818460208701611b33565b9190910192915050565b610100808252895490820181905260008a815260208082209192610120850192845b828110156118da5781546001600160a01b0316855293830193600191820191016118b5565b5050508301999099525067ffffffffffffffff96871660408201526001600160a01b03958616606082015293909516608084015290831660a0830152821660c0820152911660e090910152919050565b6020815260008251806020840152611949816040850160208701611b33565b601f01601f19169190910160400192915050565b60208082526024908201527f7061795245493a207065724d61784469737472696275746564546f6b656e416d6040820152631bdd5b9d60e21b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600082198211156119eb576119eb611b5f565b500190565b600082611a0d57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115611a4d578160001904821115611a3357611a33611b5f565b80851615611a4057918102915b93841c9390800290611a17565b509250929050565b6000610b338383600082611a6b57506001610415565b81611a7857506000610415565b8160018114611a8e5760028114611a9857611ab4565b6001915050610415565b60ff841115611aa957611aa9611b5f565b50506001821b610415565b5060208310610133831016604e8410600b8410161715611ad7575081810a610415565b611ae18383611a12565b8060001904821115611af557611af5611b5f565b029392505050565b6000816000190483118215151615611b1757611b17611b5f565b500290565b600082821015611b2e57611b2e611b5f565b500390565b60005b83811015611b4e578181015183820152602001611b36565b838111156113a45750506000910152565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b0381168114611b8a57600080fd5b5056fe60a060405234801561001057600080fd5b5033606081901b6080526126fe61003260003960006115ce01526126fe6000f3fe6080604052600436106101dc5760003560e01c80639ace38c211610102578063c642747411610095578063dc8452cd11610064578063dc8452cd14610625578063e20056e61461063b578063ecd0c0c31461065b578063ee22610b1461067b57610220565b8063c6427474146105a9578063cf5bf23f146105c9578063d6c3179d146105e9578063d74f8edd1461061057610220565b8063b77bf600116100d1578063b77bf6001461052e578063ba51a6df14610544578063be9a655514610564578063c01a8c841461058957610220565b80639ace38c21461048f578063a0e67e2b146104bf578063a8abe69a146104e1578063b5dc40c31461050e57610220565b806337bdc99b1161017a5780637065cb48116101495780637065cb481461040f578063784547a71461042f578063810ec23b1461044f5780638b51d13f1461046f57610220565b806337bdc99b1461039c57806338af3eed146103bc57806343ad92d5146103da57806354741525146103ef57610220565b8063173825d9116101b6578063173825d9146102e157806320ea8d86146103015780632f54bf6e146103215780633411c81c1461036157610220565b8063025e7c27146102585780630a17b06b146102955780630fb5a6b4146102c357610220565b3661022057341561021e5760405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c906020015b60405180910390a25b005b341561021e5760405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90602001610215565b34801561026457600080fd5b506102786102733660046123af565b61069b565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102a157600080fd5b506102b56102b036600461244e565b6106c5565b60405190815260200161028c565b3480156102cf57600080fd5b506007546001600160401b03166102b5565b3480156102ed57600080fd5b5061021e6102fc36600461210e565b6106d7565b34801561030d57600080fd5b5061021e61031c3660046123af565b61088e565b34801561032d57600080fd5b5061035161033c36600461210e565b60026020526000908152604090205460ff1681565b604051901515815260200161028c565b34801561036d57600080fd5b5061035161037c3660046123e1565b600160209081526000928352604080842090915290825290205460ff1681565b3480156103a857600080fd5b5061021e6103b73660046123af565b610944565b3480156103c857600080fd5b506006546001600160a01b0316610278565b3480156103e657600080fd5b5061021e610bec565b3480156103fb57600080fd5b506102b561040a366004612376565b610c95565b34801561041b57600080fd5b5061021e61042a36600461210e565b610d12565b34801561043b57600080fd5b5061035161044a3660046123af565b610e2b565b34801561045b57600080fd5b506102b561046a36600461220a565b610eca565b34801561047b57600080fd5b506102b561048a3660046123af565b610f55565b34801561049b57600080fd5b506104af6104aa3660046123af565b610fdb565b60405161028c94939291906124b1565b3480156104cb57600080fd5b506104d4611099565b60405161028c91906124eb565b3480156104ed57600080fd5b506105016104fc366004612404565b6110fb565b60405161028c9190612538565b34801561051a57600080fd5b506104d46105293660046123af565b611291565b34801561053a57600080fd5b506102b560055481565b34801561055057600080fd5b5061021e61055f3660046123af565b611467565b34801561057057600080fd5b50600654600160a01b90046001600160401b03166102b5565b34801561059557600080fd5b5061021e6105a43660046123af565b6114e4565b3480156105b557600080fd5b506102b56105c436600461215c565b6115ab565b3480156105d557600080fd5b5061021e6105e4366004612234565b6115c3565b3480156105f557600080fd5b5060075461027890600160401b90046001600160a01b031681565b34801561061c57600080fd5b506102b5603281565b34801561063157600080fd5b506102b560045481565b34801561064757600080fd5b5061021e610656366004612129565b611698565b34801561066757600080fd5b50600854610278906001600160a01b031681565b34801561068757600080fd5b5061021e6106963660046123af565b61182b565b600381815481106106ab57600080fd5b6000918252602090912001546001600160a01b0316905081565b60006106d147836119ee565b92915050565b3330146106e357600080fd5b6001600160a01b038116600090815260026020526040902054819060ff1661070a57600080fd5b6001600160a01b0382166000908152600260205260408120805460ff191690555b60035461073a906001906125cb565b81101561080a57826001600160a01b03166003828154811061075e5761075e61268e565b6000918252602090912001546001600160a01b031614156107f85760038054610789906001906125cb565b815481106107995761079961268e565b600091825260209091200154600380546001600160a01b0390921691839081106107c5576107c561268e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061080a565b8061080281612647565b91505061072b565b50600380548061081c5761081c612678565b600082815260209020810160001990810180546001600160a01b031916905501905560035460045411156108565760035461085690611467565b6040516001600160a01b038316907f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9090600090a25050565b3360008181526002602052604090205460ff166108aa57600080fd5b60008281526001602090815260408083203380855292529091205483919060ff166108d457600080fd5b600084815260208190526040902060030154849060ff16156108f557600080fd5b6000858152600160209081526040808320338085529252808320805460ff191690555187927ff6a317157440607f36269043eb55f1287a5a19ba2216afeab88cd46cbcfb88e991a35050505050565b33301461095057600080fd5b60004261096d6006546001600160401b03600160a01b9091041690565b106109ac5760405162461bcd60e51b81526004016109a390602080825260049082015263656e642160e01b604082015260600190565b60405180910390fd5b6009546008546001600160a01b0390811691161415610a4d57504780821115610a0d5760405162461bcd60e51b815260206004820152601360248201527230b6b7bab73a10363a103130b630b731b2a7b360691b60448201526064016109a3565b6006546040516001600160a01b039091169083156108fc029084906000818181858888f19350505050158015610a47573d6000803e3d6000fd5b50610bb5565b6008546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015610a9057600080fd5b505afa158015610aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac891906123c8565b905080821115610b105760405162461bcd60e51b815260206004820152601360248201527230b6b7bab73a10363a103130b630b731b2a7b360691b60448201526064016109a3565b6008546001600160a01b031663a9059cbb610b336006546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381600087803b158015610b7b57600080fd5b505af1158015610b8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb39190612359565b505b6040518281527fda9d4e5f101b8b9b1c5b76d0c5a9f7923571acfc02376aa076b75a8c080c956b9060200160405180910390a15050565b333014610bf857600080fd5b600754600090610c1890600160401b90046001600160a01b031642610eca565b600754604051828152919250600160401b90046001600160a01b0316907fc0e523490dd523c33b1878c9eb14ff46991e3f5b2cd33710918618f2a39cba1b9060200160405180910390a2600754610c92906001600160a01b03600160401b90910416610c8c6006546001600160a01b031690565b83611a3d565b50565b6000805b600554811015610d0b57838015610cc2575060008181526020819052604090206003015460ff16155b80610ce65750828015610ce6575060008181526020819052604090206003015460ff165b15610cf957610cf66001836125b3565b91505b80610d0381612647565b915050610c99565b5092915050565b333014610d1e57600080fd5b6001600160a01b038116600090815260026020526040902054819060ff1615610d4657600080fd5b816001600160a01b038116610d5a57600080fd5b600354610d689060016125b3565b60045460328211158015610d7c5750818111155b8015610d8757508015155b8015610d9257508115155b610d9b57600080fd5b6001600160a01b038516600081815260026020526040808220805460ff1916600190811790915560038054918201815583527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b03191684179055517ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d9190a25050505050565b600080805b600354811015610ec05760008481526001602052604081206003805491929184908110610e5f57610e5f61268e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615610e9a57610e976001836125b3565b91505b600454821415610eae575060019392505050565b80610eb881612647565b915050610e30565b5060009392505050565b6040516370a0823160e01b8152306004820152600090610f4e906001600160a01b038516906370a082319060240160206040518083038186803b158015610f1057600080fd5b505afa158015610f24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4891906123c8565b836119ee565b9392505050565b6000805b600354811015610fd55760008381526001602052604081206003805491929184908110610f8857610f8861268e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1615610fc357610fc06001836125b3565b91505b80610fcd81612647565b915050610f59565b50919050565b6000602081905290815260409020805460018201546002830180546001600160a01b0390931693919261100d90612612565b80601f016020809104026020016040519081016040528092919081815260200182805461103990612612565b80156110865780601f1061105b57610100808354040283529160200191611086565b820191906000526020600020905b81548152906001019060200180831161106957829003601f168201915b5050506003909301549192505060ff1684565b606060038054806020026020016040519081016040528092919081815260200182805480156110f157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116110d3575b5050505050905090565b606060006005546001600160401b03811115611119576111196126a4565b604051908082528060200260200182016040528015611142578160200160208202803683370190505b5090506000805b6005548110156111d957858015611172575060008181526020819052604090206003015460ff16155b806111965750848015611196575060008181526020819052604090206003015460ff165b156111c757808383815181106111ae576111ae61268e565b60209081029190910101526111c46001836125b3565b91505b806111d181612647565b915050611149565b6111e388886125cb565b6001600160401b038111156111fa576111fa6126a4565b604051908082528060200260200182016040528015611223578160200160208202803683370190505b5093508790505b86811015611286578281815181106112445761124461268e565b602002602001015184898361125991906125cb565b815181106112695761126961268e565b60209081029190910101528061127e81612647565b91505061122a565b505050949350505050565b6003546060906000906001600160401b038111156112b1576112b16126a4565b6040519080825280602002602001820160405280156112da578160200160208202803683370190505b5090506000805b6003548110156113b857600085815260016020526040812060038054919291849081106113105761131061268e565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff16156113a657600381815481106113505761135061268e565b9060005260206000200160009054906101000a90046001600160a01b03168383815181106113805761138061268e565b6001600160a01b03909216602092830291909101909101526113a36001836125b3565b91505b806113b081612647565b9150506112e1565b816001600160401b038111156113d0576113d06126a4565b6040519080825280602002602001820160405280156113f9578160200160208202803683370190505b509350600090505b8181101561145f5782818151811061141b5761141b61268e565b60200260200101518482815181106114355761143561268e565b6001600160a01b03909216602092830291909101909101528061145781612647565b915050611401565b505050919050565b33301461147357600080fd5b60035481603282118015906114885750818111155b801561149357508015155b801561149e57508115155b6114a757600080fd5b60048390556040518381527fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a9060200160405180910390a1505050565b3360008181526002602052604090205460ff1661150057600080fd5b60008281526020819052604090205482906001600160a01b031661152357600080fd5b60008381526001602090815260408083203380855292529091205484919060ff161561154e57600080fd5b6000858152600160208181526040808420338086529252808420805460ff1916909317909255905187927f4a504a94899432a9846e1aa406dceb1bcfd538bb839071d49d1e5e23f5be30ef91a36115a48561182b565b5050505050565b60006115b8848484611a94565b9050610f4e816114e4565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146116275760405162461bcd60e51b81526020600482015260096024820152681bdb9b1e481c1bdbdb60ba1b60448201526064016109a3565b6116318888611b87565b61163c858588611cbe565b600880546001600160a01b039485166001600160a01b03199182161790915560098054928516929091169190911790556007805491909216600160401b0268010000000000000000600160e01b03199091161790555050505050565b3330146116a457600080fd5b6001600160a01b038216600090815260026020526040902054829060ff166116cb57600080fd5b6001600160a01b038216600090815260026020526040902054829060ff16156116f357600080fd5b60005b60035481101561179157846001600160a01b03166003828154811061171d5761171d61268e565b6000918252602090912001546001600160a01b0316141561177f57836003828154811061174c5761174c61268e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611791565b8061178981612647565b9150506116f6565b506001600160a01b03808516600081815260026020526040808220805460ff1990811690915593871682528082208054909416600117909355915190917f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9091a26040516001600160a01b038416907ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d90600090a250505050565b3360008181526002602052604090205460ff1661184757600080fd5b60008281526001602090815260408083203380855292529091205483919060ff1661187157600080fd5b600084815260208190526040902060030154849060ff161561189257600080fd5b61189b85610e2b565b156115a457600085815260208190526040902060038101805460ff19166001908117909155815490820154600283018054611979936001600160a01b03169291906118e590612612565b90508460020180546118f690612612565b80601f016020809104026020016040519081016040528092919081815260200182805461192290612612565b801561196f5780601f106119445761010080835404028352916020019161196f565b820191906000526020600020905b81548152906001019060200180831161195257829003601f168201915b5050505050611d77565b156119ae5760405186907f33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed7590600090a26119e6565b60405186907f526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b7923690600090a260038101805460ff191690555b505050505050565b6000611a026007546001600160401b031690565b600654600160a01b90046001600160401b0316611a1f91906125b3565b826001600160401b031610611a355750816106d1565b5060006106d1565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611a8f908490611d9a565b505050565b6000836001600160a01b038116611aaa57600080fd5b600554604080516080810182526001600160a01b038881168252602080830189815283850189815260006060860181905287815280845295909520845181546001600160a01b03191694169390931783555160018301559251805194965091939092611b1d926002850192910190611fed565b50606091909101516003909101805460ff19169115159190911790556005805460019190600090611b4f9084906125b3565b909155505060405182907fc0ba8fe4b176c1714197d43b9cc6bcf797a4a7461c5fe8d0ef6e184ae7601e5190600090a2509392505050565b81518160328211158015611b9b5750818111155b8015611ba657508015155b8015611bb157508115155b611bba57600080fd5b60005b8451811015611ca15760026000868381518110611bdc57611bdc61268e565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16158015611c3c575060006001600160a01b0316858281518110611c2857611c2861268e565b60200260200101516001600160a01b031614155b611c4557600080fd5b600160026000878481518110611c5d57611c5d61268e565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580611c9981612647565b915050611bbd565b508351611cb5906003906020870190612071565b50505060045550565b6001600160a01b038316611d275760405162461bcd60e51b815260206004820152602a60248201527f56657374696e6757616c6c65743a2062656e6566696369617279206973207a65604482015269726f206164647265737360b01b60648201526084016109a3565b600680546001600160a01b03949094166001600160e01b031990941693909317600160a01b6001600160401b0393841602179092556007805467ffffffffffffffff191692909116919091179055565b6000806040516020840160008287838a8c6187965a03f198975050505050505050565b6000611def826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611e6c9092919063ffffffff16565b805190915015611a8f5780806020019051810190611e0d9190612359565b611a8f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109a3565b6060611e7b8484600085611e83565b949350505050565b606082471015611ee45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016109a3565b6001600160a01b0385163b611f3b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109a3565b600080866001600160a01b03168587604051611f579190612495565b60006040518083038185875af1925050503d8060008114611f94576040519150601f19603f3d011682016040523d82523d6000602084013e611f99565b606091505b5091509150611fa9828286611fb4565b979650505050505050565b60608315611fc3575081610f4e565b825115611fd35782518084602001fd5b8160405162461bcd60e51b81526004016109a39190612570565b828054611ff990612612565b90600052602060002090601f01602090048101928261201b5760008555612061565b82601f1061203457805160ff1916838001178555612061565b82800160010185558215612061579182015b82811115612061578251825591602001919060010190612046565b5061206d9291506120c6565b5090565b828054828255906000526020600020908101928215612061579160200282015b8281111561206157825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190612091565b5b8082111561206d57600081556001016120c7565b80356001600160a01b03811681146120f257600080fd5b919050565b80356001600160401b03811681146120f257600080fd5b60006020828403121561212057600080fd5b610f4e826120db565b6000806040838503121561213c57600080fd5b612145836120db565b9150612153602084016120db565b90509250929050565b60008060006060848603121561217157600080fd5b61217a846120db565b9250602080850135925060408501356001600160401b038082111561219e57600080fd5b818701915087601f8301126121b257600080fd5b8135818111156121c4576121c46126a4565b6121d6601f8201601f19168501612583565b915080825288848285010111156121ec57600080fd5b80848401858401376000848284010152508093505050509250925092565b6000806040838503121561221d57600080fd5b612226836120db565b9150612153602084016120f7565b600080600080600080600080610100898b03121561225157600080fd5b6001600160401b03808a35111561226757600080fd5b89358a018b601f82011261227a57600080fd5b80358281111561228c5761228c6126a4565b8060051b925061229e60208401612583565b80828252602082019150602084018f60208787010111156122be57600080fd5b600095505b838610156122e9576122d4816120db565b835260019590950194602092830192016122c3565b509b5050505060208a01359750612304905060408a016120f7565b955061231260608a016120db565b945061232060808a016120f7565b935061232e60a08a016120db565b925061233c60c08a016120db565b915061234a60e08a016120db565b90509295985092959890939650565b60006020828403121561236b57600080fd5b8151610f4e816126ba565b6000806040838503121561238957600080fd5b8235612394816126ba565b915060208301356123a4816126ba565b809150509250929050565b6000602082840312156123c157600080fd5b5035919050565b6000602082840312156123da57600080fd5b5051919050565b600080604083850312156123f457600080fd5b82359150612153602084016120db565b6000806000806080858703121561241a57600080fd5b84359350602085013592506040850135612433816126ba565b91506060850135612443816126ba565b939692955090935050565b60006020828403121561246057600080fd5b610f4e826120f7565b600081518084526124818160208601602086016125e2565b601f01601f19169290920160200192915050565b600082516124a78184602087016125e2565b9190910192915050565b60018060a01b03851681528360208201526080604082015260006124d86080830185612469565b9050821515606083015295945050505050565b6020808252825182820181905260009190848201906040850190845b8181101561252c5783516001600160a01b031683529284019291840191600101612507565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561252c57835183529284019291840191600101612554565b602081526000610f4e6020830184612469565b604051601f8201601f191681016001600160401b03811182821017156125ab576125ab6126a4565b604052919050565b600082198211156125c6576125c6612662565b500190565b6000828210156125dd576125dd612662565b500390565b60005b838110156125fd5781810151838201526020016125e5565b8381111561260c576000848401525b50505050565b600181811c9082168061262657607f821691505b60208210811415610fd557634e487b7160e01b600052602260045260246000fd5b600060001982141561265b5761265b612662565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b8015158114610c9257600080fdfea2646970667358221220ad5f1b47d2adf92bad4533ffe2cbf7d6d45660df712721af9b5b08a8d8a1354664736f6c63430008070033a264697066735822122081140cab24b2f20e9a5b523d33c6c2a7ee164454b8124f96173f9b1fbcb19e2964736f6c63430008070033a264697066735822122083966f1bf2e54ad35d555dfb0382060ad6b77a5f07635e8bb19f15134b060f3a64736f6c63430008070033