false
false
0

Contract Address Details

0x9c16739A99E3E48FaDB4F8224a1BbaE62b326D1C

Contract Name
ICO
Creator
0xc9bea9–b71014 at 0x85a172–613312
Balance
2,052 CLO
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
16289876
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
ICO




Optimization enabled
true
Compiler version
v0.8.17+commit.8df45f5f




Optimization runs
200
EVM Version
default




Verified at
2024-09-26T15:32:13.518699Z

Contract source code

// SPDX-License-Identifier: No License (None)

pragma solidity 0.8.17;



/**
 * @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() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

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

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}

abstract contract IERC223Recipient { 
/**
 * @dev Standard ERC223 function that will handle incoming token transfers.
 *
 * @param _from  Token sender address.
 * @param _value Amount of tokens.
 * @param _data  Transaction metadata.
 */
    function tokenReceived(address _from, uint _value, bytes memory _data) external virtual;
}

abstract contract MinterSetup {
    bool public setup_mode = true;
    mapping (address => bool) public minters;
    
    modifier onlyMinter()
    {
        require(minters[msg.sender], "Only minter is allowed to do this");
        _;
    }
    
    modifier onlySetupMode()
    {
        require(setup_mode, "This is only allowed in setup mode");
        _;
    }
}


/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC223 {
    /**
     * @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 Returns the amount of tokens owned by `account`.
     */
    function decimals() external view returns (uint8);

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

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

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

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

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

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


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

/**
 * @dev Implementation of the {IERC223} interface by @Dexaran. This contract
 * is intended to be backwards compatible with {IERC20} and {transferFrom},
 * {approve}, {increaseAllowance}, {decreaseAllowance} functions were
 * implemented for compatibility purposes.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 */
contract ERC223 is IERC223, MinterSetup {
    using Address for address;

    mapping (address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory new_name, string memory new_symbol) {
        _name = new_name;
        _symbol = new_symbol;
        _decimals = 18;
    }
    
    function standard() public pure returns (string memory)
    {
        return "erc223";
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender] - amount;
        _balances[recipient] = _balances[recipient] + amount;
        
        if(recipient.isContract())
        {
            IERC223Recipient(recipient).tokenReceived(sender, amount, data);
        }
        emit Transfer(sender, recipient, amount);
        emit TransferData(data);
    }
    
    function _transferFrom(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC223: transfer from the zero address");
        require(recipient != address(0), "ERC223: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);
        
        _balances[sender] = _balances[sender] - amount;
        _balances[recipient] = _balances[recipient] + amount;
        emit Transfer(sender, recipient, amount);
    }

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

        _beforeTokenTransfer(address(0), account, amount);

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

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

        _beforeTokenTransfer(account, address(0), amount);

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

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

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

    /**
     * @dev Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}


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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */

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

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

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0) && newOwner != address(this), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}


// GnG default ERC223 token.
contract GnGToken is ERC223("Games and Goblins token", "GnG"), Ownable {
    function rescueERC20(address token, address to) external onlyOwner {
        uint256 value = IERC223(token).balanceOf(address(this));
        IERC223(token).transfer(to, value);
    }
    
    // @notice Creates `_amount` token to `_to`. Must only be called by the owner (MasterChef).
    function mint(address _to, uint256 _amount) public onlyMinter {
        _mint(_to, _amount);
    }
    
    // An event thats emitted when assign a minter
    event AssignMinter(address minter, bool status);

    constructor() {
        address msgSender = msg.sender;
        _owner = msg.sender;
        _mint(msg.sender, 120000000 * 10 ** 18);
        emit OwnershipTransferred(address(0), msgSender);
    }
    
    function assignMinter(address _minter, bool _status) public onlyOwner onlySetupMode
    {
        minters[_minter] = _status;
        emit AssignMinter(_minter, _status);
    }
    
    function disableSetup() public onlyOwner onlySetupMode
    {
        setup_mode = false;
    }

    function getChainId() internal view returns (uint) {
        uint256 chainId;
        assembly { chainId := chainid() }
        return chainId;
    }
}

// This contract is a Test Pricefeed. It always returns fixed values
// but its ABI is similar to the real PriceFeed
// deploy on Callisto mainnet.
contract PriceFeed
{
    // returns token price in USD with 18 decimals
    function getPrice(address token) external view returns(uint256 price)
    {
        if(token==0x0000000000000000000000000000000000000001) return 3187227770000000; // CLO
        
        if(token==0xeb5B7d171d00e4Df2b3185e1e27f9f1A447200eF) return 9604863230000000; // SOY
        
        if(token==0x84a8509CbAa982A35fFbc3cd7c1eBbe9534b6C60) return 4756345080000000; // CLOE
    }
}


contract ICO is IERC223Recipient, Ownable, ReentrancyGuard
{
    bool    public claiming_enabled = true;
    uint256 public vesting_allocation;
    string  public contractName = "NOT INITIALIZED";
    uint256 public min_purchase;  // Minimum amount of GNG tokens that a user must purchase.
    address public GnGToken_address;
    uint256 public start_timestamp;
    uint256 public end_timestamp;
    address public priceFeed = 0x9bFc3046ea26f8B09D3E85bd22AEc96C80D957e3; // Price Feed oracle. Address is valid for CLO mainnet.
    uint256 public tokenPricePer10000; // Price of 10000 GNG tokens in USD
                                       // value 300 would mean that 1 GNG = 0.03 USD.

    //address public admin = msg.sender; // This address can execute SETUP function of the contract and modify acceptable pairs
                                       // it cannot access funds however.

    uint256 public vesting_period_duration   = 2592000; // 30 days in seconds.

    uint256 public instant_delivery          = 200;     // % that will be delivered instantly upon completing the deposit
                                                        // to ICO contract. The value will be divided by 1000
                                                        // 200 is 20%. (200/1000 = 0.2);

    //uint256 public vesting_period_percentage = 200;     // % that will become available for claiming at each Vesting Period. Will be divided by 1000.
    uint256 public vesting_periods_total     = 6;       // A total number of vesting periods. After that much rewards were claimed no vesting will be paid.

    struct Purchase
    {
        uint256 amountGNG;
        uint256 vesting_timestamp;
        uint256 amount_per_period;
        uint256 claims_count;
    }

    mapping (address => Purchase) public purchases;


    // This modifier prevents purchases that can be made before or after the ICO dates of the contract.
    // NOTE! this modifier allows the code of the function to execute first,
    //       therefore `owner` of the ICO contract will be able to deposit ERC223 GNG to the contract
    //       before the `ICO start date` and the `tokenReceived()` function will be invoked
    //       but it will end execution with `return` prior to the execution of the modifier code.
    modifier ICOstarted()
    {
        _;
        require(block.timestamp >= start_timestamp && block.timestamp <= end_timestamp, "Incorrect timing");
    }

    struct asset
    {
        // uint256 rate; // Determines how much GnG tokens a user will receive per 1000 "asset tokens" deposited.
        // bool native_currency; // true for CLO, false for tokens.


        address contract_address; // For tokens - address of the "asset token" contract.
                                  // For CLO - 0x0000000000000000000000000000000000000001
        string name;  // Name of the accepted pair, for convenience purposes only.
    }

    mapping (uint256 => asset) public assets; // ID => asset_struct; ID = 0 is for native currency of the chain.
    mapping (address => uint256) public asset_index;  // address of token contract => ID of asset.

    constructor() {
        _owner = msg.sender;
        assets[0].name = "Native";
        assets[0].contract_address = 0x0000000000000000000000000000000000000001;
    }

    function _finalisePayment(uint256 _reward_amount, address _buyer) internal
    {
        uint256 _instant_delivery           = _reward_amount * instant_delivery / 1000;

        purchases[_buyer].amountGNG         += (_reward_amount - _instant_delivery); // Increment by _reward_amount because it can be not the first purchase
                                                                                     // from this address.
                                                                                     // Save this values for recognition reasons only
                                                                                     // to record "initial vesting" amount of each user.
        purchases[_buyer].vesting_timestamp = end_timestamp;
        purchases[_buyer].amount_per_period += (_reward_amount - _instant_delivery) / vesting_periods_total;
        vesting_allocation += (_reward_amount - _instant_delivery);

        IERC223(GnGToken_address).transfer(_buyer, _instant_delivery);
    }

    function claim(address _receiver) public
    {
        require(claiming_enabled, "ICO: Claiming is disabled by the owner.");
        require(purchases[_receiver].vesting_timestamp + vesting_period_duration < block.timestamp, "ICO: No vesting reward available for claiming.");
        require(purchases[_receiver].claims_count < vesting_periods_total, "ICO: Total vesting reward is already claimed.");
        uint256 _num_periods  = (block.timestamp - purchases[_receiver].vesting_timestamp) / vesting_period_duration;
        purchases[_receiver].vesting_timestamp += (_num_periods * vesting_period_duration);

        if(purchases[_receiver].claims_count + _num_periods > vesting_periods_total)
        {
            _num_periods = vesting_periods_total - purchases[_receiver].claims_count;
            purchases[_receiver].claims_count = vesting_periods_total;
        }
        else
        {
            purchases[_receiver].claims_count += _num_periods;
        }

        IERC223(GnGToken_address).transfer(_receiver, purchases[_receiver].amount_per_period * _num_periods);
    }

    // This function accepts NATIVE CURRENCY (CLO on Callisto chain),
    // this function is used to purchase GNG tokens via CLO deposit.
    receive() external payable ICOstarted() nonReentrant()
    {
        uint256 _GNG_balance = IERC223(GnGToken_address).balanceOf(address(this));
        uint256 _price       = PriceFeed(priceFeed).getPrice(0x0000000000000000000000000000000000000001);

        require(_price != 0, "ICO: Price Feed error");
        require(_GNG_balance - vesting_allocation > 1e18, "ICO: There are less than 1 GNG token in the contract. ICO is ended.");

        require(msg.value >= 1e18, "ICO: Min CLO deposit criteria is not met");

        uint256 _refund_amount = 0;
        // User is buying GnG token and paying with a native currency.
        //uint256 _reward = assets[0].rate * msg.value / 1000; // Old calculation function for manual price update version.

        // `PriceFeedData/1e18 * msg.value / 1e18` ==>> This is value that was paid in USD
        // `USD value / tokenPricePer10000 * 10000 * 1e18` ==>> this is final value of the tokens that will be paid respecting decimals
        // since both PriceFeedData and GNG token have 18 decimals we will simply remove `/1e18` and `*1e18` from the equation.
        uint256 _reward = _price * msg.value / tokenPricePer10000 * 10000 /1e18;

        // Check edge cases
        if(_reward > _GNG_balance - vesting_allocation)
        {
            uint256 _old_reward = _reward;
            _reward = _GNG_balance - vesting_allocation;
            uint256 _reward_overflow = _old_reward - _reward;
            
            _refund_amount = (_reward_overflow * tokenPricePer10000 / 10000 ) * 1e18 / _price ;
        }

        require(_reward >= min_purchase, "ICO: Minimum purchase criteria is not met");
        //IERC223(GnGToken_address).transfer(msg.sender, _reward);

        _finalisePayment(_reward, msg.sender);

        if(_refund_amount > 0)
        {
            payable(msg.sender).transfer(_refund_amount);
        }
    }

    function buy(address _token_contract, // Address of the contract of the token that will be deposited as the payment.
                 uint256 _value_to_deposit)          // How much tokens will be used to pay for acquiring tokens from ICO
                                          // IMPORTANT! This is not the amount of tokens that the user will receive,
                                          //            this is the amount of token that the user will PAY.
                                          //            The amount must be >= approved amount.
                 external ICOstarted() nonReentrant()
    {
        uint256 _GNG_balance = IERC223(GnGToken_address).balanceOf(address(this));
        uint256 _price        = PriceFeed(priceFeed).getPrice(_token_contract);

        require(_price != 0, "ICO: Price Feed does not contain info about this token.");
        require(_GNG_balance - vesting_allocation > 1e18, "ICO: There are less than 1 GNG token in the contract. ICO is ended.");
        require(asset_index[_token_contract] != 0, "ICO: Invalid asset deposit.");

        require(_value_to_deposit >= 1e18, "ICO: Min ERC20 deposit criteria is not met");

        uint256 _refund_amount = 0;

        // PriceFeedData * _value_to_deposit / decimals ==>> 
        uint256 _reward = _price * _value_to_deposit / tokenPricePer10000 * 10000 /1e18;

        // Check edge cases
        if(_reward > _GNG_balance - vesting_allocation)
        {
            uint256 _old_reward = _reward;
            _reward = _GNG_balance - vesting_allocation;
            uint256 _reward_overflow = _old_reward - _reward;

            //_refund_amount = _reward_overflow * 1000 / assets[asset_index[_token_contract]].rate; // Old calculation function

            ///                200 * 1e18      / 10000 * 250                 / PriceFeed * 1e18                               * 1e18
            _refund_amount = (_reward_overflow * tokenPricePer10000 / 10000 ) * 1e18 / _price;
        }


        IERC223(_token_contract).transferFrom(msg.sender, address(this), (_value_to_deposit - _refund_amount) );

        require(_reward >= min_purchase, "ICO: Minimum purchase criteria is not met");
        //IERC223(GnGToken_address).transfer(msg.sender, _reward);
        
        _finalisePayment(_reward, msg.sender);
    }

    function tokenReceived(address _from, uint _value, bytes memory _data) external override ICOstarted() nonReentrant()
    {
        // Incoming transaction of a ERC223 token is handled here
        // here `msg.sender` is the address of the token contract which is being deposited
        //      `msg.value` = 0
        //      `_from` is the address of the user who initiated the transfer
        //      `_value` is the amount of ERC223 tokens being deposited.

        // Owner can deposit GNG token to the ICO contract and this function will be invoked.

        require(_value >= 1e18, "ICO: Min ERC223 deposit criteria is not met");

        uint256 _refund_amount = 0;
        if(msg.sender == GnGToken_address && _from == owner())
        {
            // Deposit of GnG token by the owner. Do nothing and accept the deposit.
            // Stop execution preventing the execution of the ICOstarted() modifier.
            return;
        }
        if(asset_index[msg.sender] != 0)
        {
            uint256 _GNG_balance = IERC223(GnGToken_address).balanceOf(address(this));
            uint256 _price         = PriceFeed(priceFeed).getPrice(msg.sender);

            require(_price != 0, "ICO: Price Feed does not contain info about this token.");
            require(_GNG_balance - vesting_allocation > 1e18, "ICO: There are less than 1 GNG token in the contract. ICO is ended.");
            // User is buying GnG token and paying with a token from "acceptable tokens list".
            //uint256 _reward = assets[asset_index[msg.sender]].rate * _value / 1000; // Old calculation function.
            uint256 _reward = _price * _value / tokenPricePer10000 * 10000 /1e18;

            // Check edge cases
            if(_reward > _GNG_balance - vesting_allocation)
                {
                uint256 _old_reward = _reward;
                _reward = _GNG_balance - vesting_allocation;
                uint256 _reward_overflow = _old_reward - _reward;

                //_refund_amount = (_reward_overflow / 10000 * tokenPricePer10000) / PriceFeed(priceFeed).getPrice(msg.sender) * 1e18;

                _refund_amount = (_reward_overflow * tokenPricePer10000 / 10000 ) * 1e18 / _price ;
            }

            require(_reward >= min_purchase, "ICO: Minimum purchase criteria is not met");
            //IERC223(GnGToken_address).transfer(_from, _reward);

            _finalisePayment(_reward, _from);

            if(_refund_amount > 0)
            {
                IERC223(msg.sender).transfer(_from, _refund_amount);
            }
        }
        else
        {
            // User is depositing a token which is not in "acceptable tokens list"
            // Revert transaction and stop the execution.
            revert();
        }
    }

    // Function that returns info about acceptable payment options
    // _id = 0 is for native currency (CLO).
    function get_depositable_asset(uint256 _id) external view returns (string memory name, uint256 rate, address token_contract)
    {
        return (assets[_id].name, PriceFeed(priceFeed).getPrice(assets[_id].contract_address), assets[_id].contract_address);
    }

    // This function serves the purpose of prediction of the reward that a user can acquire by depositing 
    // `_amount_of_payment` quantity of tokens `_token_address` to the contract
    function get_reward(uint256 _amount_of_payment, address _token_address) external view returns (uint256 reward, string memory name)
    {
        ///               3176591470000000   /1e18                           * 200 * 1e18         /  200 * 10000    
        uint256 _reward = PriceFeed(priceFeed).getPrice(_token_address) * _amount_of_payment * 10000 / tokenPricePer10000/ 1e18;
        return (_reward, assets[asset_index[_token_address]].name);
    }

    function modify_asset(uint256 _id, address _token_contract, string memory _name) external onlyOwner
    {
        require (_token_contract != address(0));
        assets[_id].contract_address = _token_contract;
        assets[_id].name = _name;
        asset_index[_token_contract] = _id;
    }

    // Special emergency function to rescue stuck ERC20 tokens that were accidentally deposited.
    function ERC20Rescue(address erc20token) public onlyOwner
    {
        IERC223(erc20token).transfer(owner(), IERC223(erc20token).balanceOf(address(this)));
    }

    // Function that allows owner to withdraw tokens.
    function withdraw(uint256 _id) public onlyOwner
    {
        if(_id == 0)
        {
            // Withdrawing native currency.
            payable(owner()).transfer(address(this).balance);
        }
        else
        {
            // Withdrawing a token.
            IERC223( assets[_id].contract_address ).transfer(owner(), IERC223( assets[_id].contract_address ).balanceOf( address(this) ));
        }
    }

    // Function that allows owner to withdraw tokens.
    function withdrawGNG(uint256 _amount) public onlyOwner
    {
        IERC223(GnGToken_address).transfer(owner(), _amount );
    }

    function setup_contract(address _GNG, uint256 _min_purchase, uint256 _start_UNIX, uint256 _end_UNIX, address _priceFeed, uint256 _targetPrice, string calldata _name) public onlyOwner
    {
        require(_GNG       != address(0), "Invalid GNG address");
        require(_priceFeed != address(0), "Invalid PriceFeed address");

        GnGToken_address   = _GNG;
        start_timestamp    = _start_UNIX;
        end_timestamp      = _end_UNIX;
        min_purchase       = _min_purchase;
        priceFeed          = _priceFeed;
        contractName       = _name;
        tokenPricePer10000 = _targetPrice;
    }

    function setup_vesting(uint256 _vesting_period, uint256 _instant_delivery, uint256 _num_periods) public onlyOwner
    {
        vesting_period_duration   = _vesting_period;
        instant_delivery          = _instant_delivery;
        vesting_periods_total     = _num_periods;
    }

    // Emergency function that allows the owner of the contract to call any code
    // from any other "template contract" on behalf of the ICO contract.
    function delegateCall(address _to, bytes calldata _data) external onlyOwner
    {
        (bool success, bytes memory data) = _to.delegatecall(_data);
    }

    function set_claiming(bool _claiming_enabled) public onlyOwner
    {
        claiming_enabled = _claiming_enabled;
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"ERC20Rescue","inputs":[{"type":"address","name":"erc20token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"GnGToken_address","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"asset_index","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"contract_address","internalType":"address"},{"type":"string","name":"name","internalType":"string"}],"name":"assets","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"buy","inputs":[{"type":"address","name":"_token_contract","internalType":"address"},{"type":"uint256","name":"_value_to_deposit","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[{"type":"address","name":"_receiver","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"claiming_enabled","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"contractName","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"delegateCall","inputs":[{"type":"address","name":"_to","internalType":"address"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"end_timestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"name","internalType":"string"},{"type":"uint256","name":"rate","internalType":"uint256"},{"type":"address","name":"token_contract","internalType":"address"}],"name":"get_depositable_asset","inputs":[{"type":"uint256","name":"_id","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"reward","internalType":"uint256"},{"type":"string","name":"name","internalType":"string"}],"name":"get_reward","inputs":[{"type":"uint256","name":"_amount_of_payment","internalType":"uint256"},{"type":"address","name":"_token_address","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"instant_delivery","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"min_purchase","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"modify_asset","inputs":[{"type":"uint256","name":"_id","internalType":"uint256"},{"type":"address","name":"_token_contract","internalType":"address"},{"type":"string","name":"_name","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"priceFeed","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountGNG","internalType":"uint256"},{"type":"uint256","name":"vesting_timestamp","internalType":"uint256"},{"type":"uint256","name":"amount_per_period","internalType":"uint256"},{"type":"uint256","name":"claims_count","internalType":"uint256"}],"name":"purchases","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set_claiming","inputs":[{"type":"bool","name":"_claiming_enabled","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setup_contract","inputs":[{"type":"address","name":"_GNG","internalType":"address"},{"type":"uint256","name":"_min_purchase","internalType":"uint256"},{"type":"uint256","name":"_start_UNIX","internalType":"uint256"},{"type":"uint256","name":"_end_UNIX","internalType":"uint256"},{"type":"address","name":"_priceFeed","internalType":"address"},{"type":"uint256","name":"_targetPrice","internalType":"uint256"},{"type":"string","name":"_name","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setup_vesting","inputs":[{"type":"uint256","name":"_vesting_period","internalType":"uint256"},{"type":"uint256","name":"_instant_delivery","internalType":"uint256"},{"type":"uint256","name":"_num_periods","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"start_timestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenPricePer10000","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"tokenReceived","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"uint256","name":"_value","internalType":"uint256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"vesting_allocation","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"vesting_period_duration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"vesting_periods_total","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"_id","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawGNG","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

Verify & Publish
0x6002805460ff1916600117905560c0604052600f60809081526e1393d5081253925512505312569151608a1b60a0526004906200003d9082620001d7565b50600980546001600160a01b031916739bfc3046ea26f8b09d3e85bd22aec96c80d957e317905562278d00600b5560c8600c556006600d553480156200008257600080fd5b5060018055600080546001600160a01b031916331781556040805180820190915260068152654e617469766560d01b602080830191909152918052600f9091527ff4803e074bd026baaf6ed2e288c9515f68c72fb7216eebdd7cae1718a53ec37690620000f09082620001d7565b5060008052600f6020527ff4803e074bd026baaf6ed2e288c9515f68c72fb7216eebdd7cae1718a53ec37580546001600160a01b0319166001179055620002a3565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200015d57607f821691505b6020821081036200017e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001d257600081815260208120601f850160051c81016020861015620001ad5750805b601f850160051c820191505b81811015620001ce57828155600101620001b9565b5050505b505050565b81516001600160401b03811115620001f357620001f362000132565b6200020b8162000204845462000148565b8462000184565b602080601f8311600181146200024357600084156200022a5750858301515b600019600386901b1c1916600185901b178555620001ce565b600085815260208120601f198616915b82811015620002745788860151825594840194600190910190840162000253565b5085821015620002935787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6128ab80620002b36000396000f3fe6080604052600436106101dc5760003560e01c806375d0c0dc11610102578063b68094fd11610095578063cf35bdd011610064578063cf35bdd0146108bc578063d001b888146108ea578063f2fde38b1461090a578063f598fc1f1461092a57600080fd5b8063b68094fd14610850578063c0b3a90114610870578063c86817f914610886578063cce7ec131461089c57600080fd5b8063876ac3eb116100d1578063876ac3eb146107ce5780638943ec02146107e45780638da5cb5b14610804578063b3fdbee81461082257600080fd5b806375d0c0dc14610707578063773498d114610729578063773fa6241461073f578063842a77d31461076c57600080fd5b80635fcf99b91161017a5780636649238f116101495780636649238f146106845780636b5a1c72146106a4578063715018a6146106ba578063741bef1a146106cf57600080fd5b80635fcf99b9146106045780636117c5911461062457806361a64beb1461064e57806363ebef761461066e57600080fd5b80634320e30c116101b65780634320e30c146105805780635697acc0146105a057806356e7b7aa146105c45780635abea018146105e457600080fd5b80631e83409a146105085780632e1a7d4d1461052857806342a70af41461054857600080fd5b36610503576101e9610940565b6006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610232573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102569190612010565b6009546040516341976e0960e01b8152600160048201529192506000916001600160a01b03909116906341976e0990602401602060405180830381865afa1580156102a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c99190612010565b9050806000036103185760405162461bcd60e51b815260206004820152601560248201527424a1a79d10283934b1b2902332b2b21032b93937b960591b60448201526064015b60405180910390fd5b670de0b6b3a76400006003548361032f919061203f565b1161034c5760405162461bcd60e51b815260040161030f90612058565b670de0b6b3a76400003410156103b55760405162461bcd60e51b815260206004820152602860248201527f49434f3a204d696e20434c4f206465706f736974206372697465726961206973604482015267081b9bdd081b595d60c21b606482015260840161030f565b600080670de0b6b3a7640000600a5434856103d091906120c1565b6103da91906120d8565b6103e6906127106120c1565b6103f091906120d8565b905060035484610400919061203f565b811115610463576003548190610416908661203f565b91506000610424838361203f565b905084612710600a548361043891906120c1565b61044291906120d8565b61045490670de0b6b3a76400006120c1565b61045e91906120d8565b935050505b6005548110156104855760405162461bcd60e51b815260040161030f906120fa565b61048f8133610999565b81156104c457604051339083156108fc029084906000818181858888f193505050501580156104c2573d6000803e3d6000fd5b505b505050506104d160018055565b60075442101580156104e557506008544211155b6105015760405162461bcd60e51b815260040161030f90612143565b005b600080fd5b34801561051457600080fd5b50610501610523366004612189565b610af3565b34801561053457600080fd5b506105016105433660046121ab565b610e35565b34801561055457600080fd5b506105686105633660046121ab565b610fc1565b6040516105779392919061220a565b60405180910390f35b34801561058c57600080fd5b5061050161059b3660046122c9565b6110fc565b3480156105ac57600080fd5b506105b6600d5481565b604051908152602001610577565b3480156105d057600080fd5b506105016105df366004612376565b611189565b3480156105f057600080fd5b506105016105ff3660046123c9565b61121a565b34801561061057600080fd5b5061050161061f366004612189565b61133f565b34801561063057600080fd5b5060025461063e9060ff1681565b6040519015158152602001610577565b34801561065a57600080fd5b506105016106693660046121ab565b6113b6565b34801561067a57600080fd5b506105b660075481565b34801561069057600080fd5b5061050161069f366004612462565b611436565b3480156106b057600080fd5b506105b660055481565b3480156106c657600080fd5b50610501611473565b3480156106db57600080fd5b506009546106ef906001600160a01b031681565b6040516001600160a01b039091168152602001610577565b34801561071357600080fd5b5061071c6114e7565b604051610577919061247f565b34801561073557600080fd5b506105b6600b5481565b34801561074b57600080fd5b506105b661075a366004612189565b60106020526000908152604090205481565b34801561077857600080fd5b506107ae610787366004612189565b600e6020526000908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610577565b3480156107da57600080fd5b506105b660085481565b3480156107f057600080fd5b506105016107ff366004612492565b611575565b34801561081057600080fd5b506000546001600160a01b03166106ef565b34801561082e57600080fd5b5061084261083d3660046124d3565b6118f8565b6040516105779291906124ff565b34801561085c57600080fd5b506006546106ef906001600160a01b031681565b34801561087c57600080fd5b506105b6600a5481565b34801561089257600080fd5b506105b6600c5481565b3480156108a857600080fd5b506105016108b7366004612520565b611a6c565b3480156108c857600080fd5b506108dc6108d73660046121ab565b611e28565b60405161057792919061254a565b3480156108f657600080fd5b5061050161090536600461256e565b611ed7565b34801561091657600080fd5b50610501610925366004612189565b611f0f565b34801561093657600080fd5b506105b660035481565b6002600154036109925760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161030f565b6002600155565b60006103e8600c54846109ac91906120c1565b6109b691906120d8565b90506109c2818461203f565b6001600160a01b0383166000908152600e6020526040812080549091906109ea90849061259a565b90915550506008546001600160a01b0383166000908152600e6020526040902060010155600d54610a1b828561203f565b610a2591906120d8565b6001600160a01b0383166000908152600e602052604081206002018054909190610a5090849061259a565b90915550610a609050818461203f565b60036000828254610a71919061259a565b909155505060065460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015610ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aed91906125ad565b50505050565b60025460ff16610b555760405162461bcd60e51b815260206004820152602760248201527f49434f3a20436c61696d696e672069732064697361626c6564206279207468656044820152661037bbb732b91760c91b606482015260840161030f565b600b546001600160a01b0382166000908152600e60205260409020600101544291610b7f9161259a565b10610be35760405162461bcd60e51b815260206004820152602e60248201527f49434f3a204e6f2076657374696e672072657761726420617661696c61626c6560448201526d103337b91031b630b4b6b4b7339760911b606482015260840161030f565b600d546001600160a01b0382166000908152600e602052604090206003015410610c655760405162461bcd60e51b815260206004820152602d60248201527f49434f3a20546f74616c2076657374696e672072657761726420697320616c7260448201526c32b0b23c9031b630b4b6b2b21760991b606482015260840161030f565b600b546001600160a01b0382166000908152600e6020526040812060010154909190610c91904261203f565b610c9b91906120d8565b9050600b5481610cab91906120c1565b6001600160a01b0383166000908152600e602052604081206001018054909190610cd690849061259a565b9091555050600d546001600160a01b0383166000908152600e6020526040902060030154610d0590839061259a565b1115610d5a576001600160a01b0382166000908152600e6020526040902060030154600d54610d34919061203f565b600d546001600160a01b0384166000908152600e60205260409020600301559050610d8b565b6001600160a01b0382166000908152600e602052604081206003018054839290610d8590849061259a565b90915550505b6006546001600160a01b038381166000908152600e602052604090206002015491169063a9059cbb908490610dc19085906120c1565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3091906125ad565b505050565b6000546001600160a01b03163314610e5f5760405162461bcd60e51b815260040161030f906125ca565b80600003610ea557600080546040516001600160a01b03909116914780156108fc02929091818181858888f19350505050158015610ea1573d6000803e3d6000fd5b5050565b6000818152600f60205260409020546001600160a01b031663a9059cbb610ed46000546001600160a01b031690565b6000848152600f6020526040908190205490516370a0823160e01b81523060048201526001600160a01b03909116906370a08231906024015b602060405180830381865afa158015610f2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4e9190612010565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044015b6020604051808303816000875af1158015610f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea191906125ad565b50565b6000818152600f6020526040808220600954815492516341976e0960e01b81526001600160a01b0393841660048201526060949384936001019216906341976e0990602401602060405180830381865afa158015611023573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110479190612010565b6000868152600f602052604090205482546001600160a01b0390911690839061106f906125ff565b80601f016020809104026020016040519081016040528092919081815260200182805461109b906125ff565b80156110e85780601f106110bd576101008083540402835291602001916110e8565b820191906000526020600020905b8154815290600101906020018083116110cb57829003601f168201915b505050505092509250925092509193909250565b6000546001600160a01b031633146111265760405162461bcd60e51b815260040161030f906125ca565b6001600160a01b03821661113957600080fd5b6000838152600f6020526040902080546001600160a01b0319166001600160a01b03841617815560010161116d8282612687565b50506001600160a01b0316600090815260106020526040902055565b6000546001600160a01b031633146111b35760405162461bcd60e51b815260040161030f906125ca565b600080846001600160a01b031684846040516111d0929190612747565b600060405180830381855af49150503d806000811461120b576040519150601f19603f3d011682016040523d82523d6000602084013e611210565b606091505b5050505050505050565b6000546001600160a01b031633146112445760405162461bcd60e51b815260040161030f906125ca565b6001600160a01b0388166112905760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420474e47206164647265737360681b604482015260640161030f565b6001600160a01b0384166112e65760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420507269636546656564206164647265737300000000000000604482015260640161030f565b600680546001600160a01b03808b166001600160a01b03199283161790925560078890556008879055600589905560098054928716929091169190911790556004611332828483612757565b505050600a555050505050565b6000546001600160a01b031633146113695760405162461bcd60e51b815260040161030f906125ca565b806001600160a01b031663a9059cbb61138a6000546001600160a01b031690565b6040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401610f0d565b6000546001600160a01b031633146113e05760405162461bcd60e51b815260040161030f906125ca565b6006546001600160a01b031663a9059cbb6114036000546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101849052604401610f7b565b6000546001600160a01b031633146114605760405162461bcd60e51b815260040161030f906125ca565b6002805460ff1916911515919091179055565b6000546001600160a01b0316331461149d5760405162461bcd60e51b815260040161030f906125ca565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600480546114f4906125ff565b80601f0160208091040260200160405190810160405280929190818152602001828054611520906125ff565b801561156d5780601f106115425761010080835404028352916020019161156d565b820191906000526020600020905b81548152906001019060200180831161155057829003601f168201915b505050505081565b61157d610940565b670de0b6b3a76400008210156115e95760405162461bcd60e51b815260206004820152602b60248201527f49434f3a204d696e20455243323233206465706f73697420637269746572696160448201526a081a5cc81b9bdd081b595d60aa1b606482015260840161030f565b6006546000906001600160a01b03163314801561161357506000546001600160a01b038581169116145b1561161e57506118bf565b3360009081526010602052604090205415610503576006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561167c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a09190612010565b6009546040516341976e0960e01b81523360048201529192506000916001600160a01b03909116906341976e0990602401602060405180830381865afa1580156116ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117129190612010565b9050806000036117345760405162461bcd60e51b815260040161030f90612818565b670de0b6b3a76400006003548361174b919061203f565b116117685760405162461bcd60e51b815260040161030f90612058565b6000670de0b6b3a7640000600a54878461178291906120c1565b61178c91906120d8565b611798906127106120c1565b6117a291906120d8565b9050600354836117b2919061203f565b8111156118155760035481906117c8908561203f565b915060006117d6838361203f565b905083612710600a54836117ea91906120c1565b6117f491906120d8565b61180690670de0b6b3a76400006120c1565b61181091906120d8565b955050505b6005548110156118375760405162461bcd60e51b815260040161030f906120fa565b6118418188610999565b83156118ba5760405163a9059cbb60e01b81526001600160a01b038816600482015260248101859052339063a9059cbb906044016020604051808303816000875af1158015611894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b891906125ad565b505b505050505b6118c860018055565b60075442101580156118dc57506008544211155b610e305760405162461bcd60e51b815260040161030f90612143565b600a546009546040516341976e0960e01b81526001600160a01b0384811660048301526000936060938593670de0b6b3a764000093899216906341976e0990602401602060405180830381865afa158015611957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197b9190612010565b61198591906120c1565b611991906127106120c1565b61199b91906120d8565b6119a591906120d8565b6001600160a01b0385166000908152601060209081526040808320548352600f90915290206001018054919250829181906119df906125ff565b80601f0160208091040260200160405190810160405280929190818152602001828054611a0b906125ff565b8015611a585780601f10611a2d57610100808354040283529160200191611a58565b820191906000526020600020905b815481529060010190602001808311611a3b57829003601f168201915b5050505050905092509250505b9250929050565b611a74610940565b6006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611abd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae19190612010565b6009546040516341976e0960e01b81526001600160a01b038681166004830152929350600092909116906341976e0990602401602060405180830381865afa158015611b31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b559190612010565b905080600003611b775760405162461bcd60e51b815260040161030f90612818565b670de0b6b3a764000060035483611b8e919061203f565b11611bab5760405162461bcd60e51b815260040161030f90612058565b6001600160a01b0384166000908152601060205260408120549003611c125760405162461bcd60e51b815260206004820152601b60248201527f49434f3a20496e76616c6964206173736574206465706f7369742e0000000000604482015260640161030f565b670de0b6b3a7640000831015611c7d5760405162461bcd60e51b815260206004820152602a60248201527f49434f3a204d696e204552433230206465706f736974206372697465726961206044820152691a5cc81b9bdd081b595d60b21b606482015260840161030f565b600080670de0b6b3a7640000600a548685611c9891906120c1565b611ca291906120d8565b611cae906127106120c1565b611cb891906120d8565b905060035484611cc8919061203f565b811115611d2b576003548190611cde908661203f565b91506000611cec838361203f565b905084612710600a5483611d0091906120c1565b611d0a91906120d8565b611d1c90670de0b6b3a76400006120c1565b611d2691906120d8565b935050505b6001600160a01b0386166323b872dd3330611d46868a61203f565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015611d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbe91906125ad565b50600554811015611de15760405162461bcd60e51b815260040161030f906120fa565b611deb8133610999565b50505050611df860018055565b6007544210158015611e0c57506008544211155b610ea15760405162461bcd60e51b815260040161030f90612143565b600f60205260009081526040902080546001820180546001600160a01b039092169291611e54906125ff565b80601f0160208091040260200160405190810160405280929190818152602001828054611e80906125ff565b8015611ecd5780601f10611ea257610100808354040283529160200191611ecd565b820191906000526020600020905b815481529060010190602001808311611eb057829003601f168201915b5050505050905082565b6000546001600160a01b03163314611f015760405162461bcd60e51b815260040161030f906125ca565b600b92909255600c55600d55565b6000546001600160a01b03163314611f395760405162461bcd60e51b815260040161030f906125ca565b6001600160a01b03811615801590611f5a57506001600160a01b0381163014155b611fb55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161030f565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60006020828403121561202257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561205257612052612029565b92915050565b60208082526043908201527f49434f3a20546865726520617265206c657373207468616e203120474e47207460408201527f6f6b656e20696e2074686520636f6e74726163742e2049434f20697320656e6460608201526232b21760e91b608082015260a00190565b808202811582820484141761205257612052612029565b6000826120f557634e487b7160e01b600052601260045260246000fd5b500490565b60208082526029908201527f49434f3a204d696e696d756d20707572636861736520637269746572696120696040820152681cc81b9bdd081b595d60ba1b606082015260800190565b60208082526010908201526f496e636f72726563742074696d696e6760801b604082015260600190565b80356001600160a01b038116811461218457600080fd5b919050565b60006020828403121561219b57600080fd5b6121a48261216d565b9392505050565b6000602082840312156121bd57600080fd5b5035919050565b6000815180845260005b818110156121ea576020818501810151868301820152016121ce565b506000602082860101526020601f19601f83011685010191505092915050565b60608152600061221d60608301866121c4565b6020830194909452506001600160a01b0391909116604090910152919050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff8084111561226e5761226e61223d565b604051601f8501601f19908116603f011681019082821181831017156122965761229661223d565b816040528093508581528686860111156122af57600080fd5b858560208301376000602087830101525050509392505050565b6000806000606084860312156122de57600080fd5b833592506122ee6020850161216d565b9150604084013567ffffffffffffffff81111561230a57600080fd5b8401601f8101861361231b57600080fd5b61232a86823560208401612253565b9150509250925092565b60008083601f84011261234657600080fd5b50813567ffffffffffffffff81111561235e57600080fd5b602083019150836020828501011115611a6557600080fd5b60008060006040848603121561238b57600080fd5b6123948461216d565b9250602084013567ffffffffffffffff8111156123b057600080fd5b6123bc86828701612334565b9497909650939450505050565b60008060008060008060008060e0898b0312156123e557600080fd5b6123ee8961216d565b975060208901359650604089013595506060890135945061241160808a0161216d565b935060a0890135925060c089013567ffffffffffffffff81111561243457600080fd5b6124408b828c01612334565b999c989b5096995094979396929594505050565b8015158114610fbe57600080fd5b60006020828403121561247457600080fd5b81356121a481612454565b6020815260006121a460208301846121c4565b6000806000606084860312156124a757600080fd5b6124b08461216d565b925060208401359150604084013567ffffffffffffffff81111561230a57600080fd5b600080604083850312156124e657600080fd5b823591506124f66020840161216d565b90509250929050565b82815260406020820152600061251860408301846121c4565b949350505050565b6000806040838503121561253357600080fd5b61253c8361216d565b946020939093013593505050565b6001600160a01b0383168152604060208201819052600090612518908301846121c4565b60008060006060848603121561258357600080fd5b505081359360208301359350604090920135919050565b8082018082111561205257612052612029565b6000602082840312156125bf57600080fd5b81516121a481612454565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600181811c9082168061261357607f821691505b60208210810361263357634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610e3057600081815260208120601f850160051c810160208610156126605750805b601f850160051c820191505b8181101561267f5782815560010161266c565b505050505050565b815167ffffffffffffffff8111156126a1576126a161223d565b6126b5816126af84546125ff565b84612639565b602080601f8311600181146126ea57600084156126d25750858301515b600019600386901b1c1916600185901b17855561267f565b600085815260208120601f198616915b82811015612719578886015182559484019460019091019084016126fa565b50858210156127375787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8183823760009101908152919050565b67ffffffffffffffff83111561276f5761276f61223d565b6127838361277d83546125ff565b83612639565b6000601f8411600181146127b7576000851561279f5750838201355b600019600387901b1c1916600186901b178355612811565b600083815260209020601f19861690835b828110156127e857868501358255602094850194600190920191016127c8565b50868210156128055760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60208082526037908201527f49434f3a205072696365204665656420646f6573206e6f7420636f6e7461696e60408201527f20696e666f2061626f7574207468697320746f6b656e2e00000000000000000060608201526080019056fea2646970667358221220f7c49159acd071ca791b2358380b303a37bce07fd0cb1fddd769c8766ef7880964736f6c63430008110033

Deployed ByteCode

0x6080604052600436106101dc5760003560e01c806375d0c0dc11610102578063b68094fd11610095578063cf35bdd011610064578063cf35bdd0146108bc578063d001b888146108ea578063f2fde38b1461090a578063f598fc1f1461092a57600080fd5b8063b68094fd14610850578063c0b3a90114610870578063c86817f914610886578063cce7ec131461089c57600080fd5b8063876ac3eb116100d1578063876ac3eb146107ce5780638943ec02146107e45780638da5cb5b14610804578063b3fdbee81461082257600080fd5b806375d0c0dc14610707578063773498d114610729578063773fa6241461073f578063842a77d31461076c57600080fd5b80635fcf99b91161017a5780636649238f116101495780636649238f146106845780636b5a1c72146106a4578063715018a6146106ba578063741bef1a146106cf57600080fd5b80635fcf99b9146106045780636117c5911461062457806361a64beb1461064e57806363ebef761461066e57600080fd5b80634320e30c116101b65780634320e30c146105805780635697acc0146105a057806356e7b7aa146105c45780635abea018146105e457600080fd5b80631e83409a146105085780632e1a7d4d1461052857806342a70af41461054857600080fd5b36610503576101e9610940565b6006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610232573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102569190612010565b6009546040516341976e0960e01b8152600160048201529192506000916001600160a01b03909116906341976e0990602401602060405180830381865afa1580156102a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c99190612010565b9050806000036103185760405162461bcd60e51b815260206004820152601560248201527424a1a79d10283934b1b2902332b2b21032b93937b960591b60448201526064015b60405180910390fd5b670de0b6b3a76400006003548361032f919061203f565b1161034c5760405162461bcd60e51b815260040161030f90612058565b670de0b6b3a76400003410156103b55760405162461bcd60e51b815260206004820152602860248201527f49434f3a204d696e20434c4f206465706f736974206372697465726961206973604482015267081b9bdd081b595d60c21b606482015260840161030f565b600080670de0b6b3a7640000600a5434856103d091906120c1565b6103da91906120d8565b6103e6906127106120c1565b6103f091906120d8565b905060035484610400919061203f565b811115610463576003548190610416908661203f565b91506000610424838361203f565b905084612710600a548361043891906120c1565b61044291906120d8565b61045490670de0b6b3a76400006120c1565b61045e91906120d8565b935050505b6005548110156104855760405162461bcd60e51b815260040161030f906120fa565b61048f8133610999565b81156104c457604051339083156108fc029084906000818181858888f193505050501580156104c2573d6000803e3d6000fd5b505b505050506104d160018055565b60075442101580156104e557506008544211155b6105015760405162461bcd60e51b815260040161030f90612143565b005b600080fd5b34801561051457600080fd5b50610501610523366004612189565b610af3565b34801561053457600080fd5b506105016105433660046121ab565b610e35565b34801561055457600080fd5b506105686105633660046121ab565b610fc1565b6040516105779392919061220a565b60405180910390f35b34801561058c57600080fd5b5061050161059b3660046122c9565b6110fc565b3480156105ac57600080fd5b506105b6600d5481565b604051908152602001610577565b3480156105d057600080fd5b506105016105df366004612376565b611189565b3480156105f057600080fd5b506105016105ff3660046123c9565b61121a565b34801561061057600080fd5b5061050161061f366004612189565b61133f565b34801561063057600080fd5b5060025461063e9060ff1681565b6040519015158152602001610577565b34801561065a57600080fd5b506105016106693660046121ab565b6113b6565b34801561067a57600080fd5b506105b660075481565b34801561069057600080fd5b5061050161069f366004612462565b611436565b3480156106b057600080fd5b506105b660055481565b3480156106c657600080fd5b50610501611473565b3480156106db57600080fd5b506009546106ef906001600160a01b031681565b6040516001600160a01b039091168152602001610577565b34801561071357600080fd5b5061071c6114e7565b604051610577919061247f565b34801561073557600080fd5b506105b6600b5481565b34801561074b57600080fd5b506105b661075a366004612189565b60106020526000908152604090205481565b34801561077857600080fd5b506107ae610787366004612189565b600e6020526000908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610577565b3480156107da57600080fd5b506105b660085481565b3480156107f057600080fd5b506105016107ff366004612492565b611575565b34801561081057600080fd5b506000546001600160a01b03166106ef565b34801561082e57600080fd5b5061084261083d3660046124d3565b6118f8565b6040516105779291906124ff565b34801561085c57600080fd5b506006546106ef906001600160a01b031681565b34801561087c57600080fd5b506105b6600a5481565b34801561089257600080fd5b506105b6600c5481565b3480156108a857600080fd5b506105016108b7366004612520565b611a6c565b3480156108c857600080fd5b506108dc6108d73660046121ab565b611e28565b60405161057792919061254a565b3480156108f657600080fd5b5061050161090536600461256e565b611ed7565b34801561091657600080fd5b50610501610925366004612189565b611f0f565b34801561093657600080fd5b506105b660035481565b6002600154036109925760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161030f565b6002600155565b60006103e8600c54846109ac91906120c1565b6109b691906120d8565b90506109c2818461203f565b6001600160a01b0383166000908152600e6020526040812080549091906109ea90849061259a565b90915550506008546001600160a01b0383166000908152600e6020526040902060010155600d54610a1b828561203f565b610a2591906120d8565b6001600160a01b0383166000908152600e602052604081206002018054909190610a5090849061259a565b90915550610a609050818461203f565b60036000828254610a71919061259a565b909155505060065460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015610ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aed91906125ad565b50505050565b60025460ff16610b555760405162461bcd60e51b815260206004820152602760248201527f49434f3a20436c61696d696e672069732064697361626c6564206279207468656044820152661037bbb732b91760c91b606482015260840161030f565b600b546001600160a01b0382166000908152600e60205260409020600101544291610b7f9161259a565b10610be35760405162461bcd60e51b815260206004820152602e60248201527f49434f3a204e6f2076657374696e672072657761726420617661696c61626c6560448201526d103337b91031b630b4b6b4b7339760911b606482015260840161030f565b600d546001600160a01b0382166000908152600e602052604090206003015410610c655760405162461bcd60e51b815260206004820152602d60248201527f49434f3a20546f74616c2076657374696e672072657761726420697320616c7260448201526c32b0b23c9031b630b4b6b2b21760991b606482015260840161030f565b600b546001600160a01b0382166000908152600e6020526040812060010154909190610c91904261203f565b610c9b91906120d8565b9050600b5481610cab91906120c1565b6001600160a01b0383166000908152600e602052604081206001018054909190610cd690849061259a565b9091555050600d546001600160a01b0383166000908152600e6020526040902060030154610d0590839061259a565b1115610d5a576001600160a01b0382166000908152600e6020526040902060030154600d54610d34919061203f565b600d546001600160a01b0384166000908152600e60205260409020600301559050610d8b565b6001600160a01b0382166000908152600e602052604081206003018054839290610d8590849061259a565b90915550505b6006546001600160a01b038381166000908152600e602052604090206002015491169063a9059cbb908490610dc19085906120c1565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3091906125ad565b505050565b6000546001600160a01b03163314610e5f5760405162461bcd60e51b815260040161030f906125ca565b80600003610ea557600080546040516001600160a01b03909116914780156108fc02929091818181858888f19350505050158015610ea1573d6000803e3d6000fd5b5050565b6000818152600f60205260409020546001600160a01b031663a9059cbb610ed46000546001600160a01b031690565b6000848152600f6020526040908190205490516370a0823160e01b81523060048201526001600160a01b03909116906370a08231906024015b602060405180830381865afa158015610f2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4e9190612010565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044015b6020604051808303816000875af1158015610f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea191906125ad565b50565b6000818152600f6020526040808220600954815492516341976e0960e01b81526001600160a01b0393841660048201526060949384936001019216906341976e0990602401602060405180830381865afa158015611023573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110479190612010565b6000868152600f602052604090205482546001600160a01b0390911690839061106f906125ff565b80601f016020809104026020016040519081016040528092919081815260200182805461109b906125ff565b80156110e85780601f106110bd576101008083540402835291602001916110e8565b820191906000526020600020905b8154815290600101906020018083116110cb57829003601f168201915b505050505092509250925092509193909250565b6000546001600160a01b031633146111265760405162461bcd60e51b815260040161030f906125ca565b6001600160a01b03821661113957600080fd5b6000838152600f6020526040902080546001600160a01b0319166001600160a01b03841617815560010161116d8282612687565b50506001600160a01b0316600090815260106020526040902055565b6000546001600160a01b031633146111b35760405162461bcd60e51b815260040161030f906125ca565b600080846001600160a01b031684846040516111d0929190612747565b600060405180830381855af49150503d806000811461120b576040519150601f19603f3d011682016040523d82523d6000602084013e611210565b606091505b5050505050505050565b6000546001600160a01b031633146112445760405162461bcd60e51b815260040161030f906125ca565b6001600160a01b0388166112905760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420474e47206164647265737360681b604482015260640161030f565b6001600160a01b0384166112e65760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420507269636546656564206164647265737300000000000000604482015260640161030f565b600680546001600160a01b03808b166001600160a01b03199283161790925560078890556008879055600589905560098054928716929091169190911790556004611332828483612757565b505050600a555050505050565b6000546001600160a01b031633146113695760405162461bcd60e51b815260040161030f906125ca565b806001600160a01b031663a9059cbb61138a6000546001600160a01b031690565b6040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401610f0d565b6000546001600160a01b031633146113e05760405162461bcd60e51b815260040161030f906125ca565b6006546001600160a01b031663a9059cbb6114036000546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101849052604401610f7b565b6000546001600160a01b031633146114605760405162461bcd60e51b815260040161030f906125ca565b6002805460ff1916911515919091179055565b6000546001600160a01b0316331461149d5760405162461bcd60e51b815260040161030f906125ca565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600480546114f4906125ff565b80601f0160208091040260200160405190810160405280929190818152602001828054611520906125ff565b801561156d5780601f106115425761010080835404028352916020019161156d565b820191906000526020600020905b81548152906001019060200180831161155057829003601f168201915b505050505081565b61157d610940565b670de0b6b3a76400008210156115e95760405162461bcd60e51b815260206004820152602b60248201527f49434f3a204d696e20455243323233206465706f73697420637269746572696160448201526a081a5cc81b9bdd081b595d60aa1b606482015260840161030f565b6006546000906001600160a01b03163314801561161357506000546001600160a01b038581169116145b1561161e57506118bf565b3360009081526010602052604090205415610503576006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561167c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a09190612010565b6009546040516341976e0960e01b81523360048201529192506000916001600160a01b03909116906341976e0990602401602060405180830381865afa1580156116ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117129190612010565b9050806000036117345760405162461bcd60e51b815260040161030f90612818565b670de0b6b3a76400006003548361174b919061203f565b116117685760405162461bcd60e51b815260040161030f90612058565b6000670de0b6b3a7640000600a54878461178291906120c1565b61178c91906120d8565b611798906127106120c1565b6117a291906120d8565b9050600354836117b2919061203f565b8111156118155760035481906117c8908561203f565b915060006117d6838361203f565b905083612710600a54836117ea91906120c1565b6117f491906120d8565b61180690670de0b6b3a76400006120c1565b61181091906120d8565b955050505b6005548110156118375760405162461bcd60e51b815260040161030f906120fa565b6118418188610999565b83156118ba5760405163a9059cbb60e01b81526001600160a01b038816600482015260248101859052339063a9059cbb906044016020604051808303816000875af1158015611894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b891906125ad565b505b505050505b6118c860018055565b60075442101580156118dc57506008544211155b610e305760405162461bcd60e51b815260040161030f90612143565b600a546009546040516341976e0960e01b81526001600160a01b0384811660048301526000936060938593670de0b6b3a764000093899216906341976e0990602401602060405180830381865afa158015611957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197b9190612010565b61198591906120c1565b611991906127106120c1565b61199b91906120d8565b6119a591906120d8565b6001600160a01b0385166000908152601060209081526040808320548352600f90915290206001018054919250829181906119df906125ff565b80601f0160208091040260200160405190810160405280929190818152602001828054611a0b906125ff565b8015611a585780601f10611a2d57610100808354040283529160200191611a58565b820191906000526020600020905b815481529060010190602001808311611a3b57829003601f168201915b5050505050905092509250505b9250929050565b611a74610940565b6006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611abd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae19190612010565b6009546040516341976e0960e01b81526001600160a01b038681166004830152929350600092909116906341976e0990602401602060405180830381865afa158015611b31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b559190612010565b905080600003611b775760405162461bcd60e51b815260040161030f90612818565b670de0b6b3a764000060035483611b8e919061203f565b11611bab5760405162461bcd60e51b815260040161030f90612058565b6001600160a01b0384166000908152601060205260408120549003611c125760405162461bcd60e51b815260206004820152601b60248201527f49434f3a20496e76616c6964206173736574206465706f7369742e0000000000604482015260640161030f565b670de0b6b3a7640000831015611c7d5760405162461bcd60e51b815260206004820152602a60248201527f49434f3a204d696e204552433230206465706f736974206372697465726961206044820152691a5cc81b9bdd081b595d60b21b606482015260840161030f565b600080670de0b6b3a7640000600a548685611c9891906120c1565b611ca291906120d8565b611cae906127106120c1565b611cb891906120d8565b905060035484611cc8919061203f565b811115611d2b576003548190611cde908661203f565b91506000611cec838361203f565b905084612710600a5483611d0091906120c1565b611d0a91906120d8565b611d1c90670de0b6b3a76400006120c1565b611d2691906120d8565b935050505b6001600160a01b0386166323b872dd3330611d46868a61203f565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015611d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbe91906125ad565b50600554811015611de15760405162461bcd60e51b815260040161030f906120fa565b611deb8133610999565b50505050611df860018055565b6007544210158015611e0c57506008544211155b610ea15760405162461bcd60e51b815260040161030f90612143565b600f60205260009081526040902080546001820180546001600160a01b039092169291611e54906125ff565b80601f0160208091040260200160405190810160405280929190818152602001828054611e80906125ff565b8015611ecd5780601f10611ea257610100808354040283529160200191611ecd565b820191906000526020600020905b815481529060010190602001808311611eb057829003601f168201915b5050505050905082565b6000546001600160a01b03163314611f015760405162461bcd60e51b815260040161030f906125ca565b600b92909255600c55600d55565b6000546001600160a01b03163314611f395760405162461bcd60e51b815260040161030f906125ca565b6001600160a01b03811615801590611f5a57506001600160a01b0381163014155b611fb55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161030f565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60006020828403121561202257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561205257612052612029565b92915050565b60208082526043908201527f49434f3a20546865726520617265206c657373207468616e203120474e47207460408201527f6f6b656e20696e2074686520636f6e74726163742e2049434f20697320656e6460608201526232b21760e91b608082015260a00190565b808202811582820484141761205257612052612029565b6000826120f557634e487b7160e01b600052601260045260246000fd5b500490565b60208082526029908201527f49434f3a204d696e696d756d20707572636861736520637269746572696120696040820152681cc81b9bdd081b595d60ba1b606082015260800190565b60208082526010908201526f496e636f72726563742074696d696e6760801b604082015260600190565b80356001600160a01b038116811461218457600080fd5b919050565b60006020828403121561219b57600080fd5b6121a48261216d565b9392505050565b6000602082840312156121bd57600080fd5b5035919050565b6000815180845260005b818110156121ea576020818501810151868301820152016121ce565b506000602082860101526020601f19601f83011685010191505092915050565b60608152600061221d60608301866121c4565b6020830194909452506001600160a01b0391909116604090910152919050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff8084111561226e5761226e61223d565b604051601f8501601f19908116603f011681019082821181831017156122965761229661223d565b816040528093508581528686860111156122af57600080fd5b858560208301376000602087830101525050509392505050565b6000806000606084860312156122de57600080fd5b833592506122ee6020850161216d565b9150604084013567ffffffffffffffff81111561230a57600080fd5b8401601f8101861361231b57600080fd5b61232a86823560208401612253565b9150509250925092565b60008083601f84011261234657600080fd5b50813567ffffffffffffffff81111561235e57600080fd5b602083019150836020828501011115611a6557600080fd5b60008060006040848603121561238b57600080fd5b6123948461216d565b9250602084013567ffffffffffffffff8111156123b057600080fd5b6123bc86828701612334565b9497909650939450505050565b60008060008060008060008060e0898b0312156123e557600080fd5b6123ee8961216d565b975060208901359650604089013595506060890135945061241160808a0161216d565b935060a0890135925060c089013567ffffffffffffffff81111561243457600080fd5b6124408b828c01612334565b999c989b5096995094979396929594505050565b8015158114610fbe57600080fd5b60006020828403121561247457600080fd5b81356121a481612454565b6020815260006121a460208301846121c4565b6000806000606084860312156124a757600080fd5b6124b08461216d565b925060208401359150604084013567ffffffffffffffff81111561230a57600080fd5b600080604083850312156124e657600080fd5b823591506124f66020840161216d565b90509250929050565b82815260406020820152600061251860408301846121c4565b949350505050565b6000806040838503121561253357600080fd5b61253c8361216d565b946020939093013593505050565b6001600160a01b0383168152604060208201819052600090612518908301846121c4565b60008060006060848603121561258357600080fd5b505081359360208301359350604090920135919050565b8082018082111561205257612052612029565b6000602082840312156125bf57600080fd5b81516121a481612454565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600181811c9082168061261357607f821691505b60208210810361263357634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610e3057600081815260208120601f850160051c810160208610156126605750805b601f850160051c820191505b8181101561267f5782815560010161266c565b505050505050565b815167ffffffffffffffff8111156126a1576126a161223d565b6126b5816126af84546125ff565b84612639565b602080601f8311600181146126ea57600084156126d25750858301515b600019600386901b1c1916600185901b17855561267f565b600085815260208120601f198616915b82811015612719578886015182559484019460019091019084016126fa565b50858210156127375787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8183823760009101908152919050565b67ffffffffffffffff83111561276f5761276f61223d565b6127838361277d83546125ff565b83612639565b6000601f8411600181146127b7576000851561279f5750838201355b600019600387901b1c1916600186901b178355612811565b600083815260209020601f19861690835b828110156127e857868501358255602094850194600190920191016127c8565b50868210156128055760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60208082526037908201527f49434f3a205072696365204665656420646f6573206e6f7420636f6e7461696e60408201527f20696e666f2061626f7574207468697320746f6b656e2e00000000000000000060608201526080019056fea2646970667358221220f7c49159acd071ca791b2358380b303a37bce07fd0cb1fddd769c8766ef7880964736f6c63430008110033