false
true

Contract Address Details

0x4750f7759a3A83Df2f3c597e92658b86F45Db1B9

Contract Name
GPADFactory
Creator
0x8687d8–47bc82 at 0x76a4ca–1b5dea
Balance
0
Tokens
Fetching tokens...
Transactions
1 Transactions
Transfers
0 Transfers
Gas Used
47,261
Last Balance Update
32249156
Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB 0x3f566c3c5917e7e1667743d97b857b26c0a53d57.
All metadata displayed below is from that contract. In order to verify current contract, click Verify & Publish button
Verify & Publish
Contract name:
GPADFactory




Optimization enabled
true
Compiler version
v0.8.18+commit.87f61d96




Optimization runs
200
Verified at
2025-04-12T07:35:57.786311Z

contracts/GPAD/GPADFactory.sol

Sol2uml
new
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./GPADPool.sol";

contract GPADFactory is Ownable {
    using SafeMath for uint256;
    using SafeERC20 for ERC20Burnable;
    using SafeERC20 for ERC20;
    using SafeERC20 for IERC20;

    // === State Variables ===
    ERC20Burnable public feeToken;
    address public feeWallet;
    uint256 public feeAmount;
    uint256 public burnPercent; // Use this state only if your token is ERC20Burnable and has burnFrom method
    uint256 public divider;

    address[] public idoPools;

    // === Error Definitions ===
    error InvalidAddress(string message);

    // === Events ===
    event IDOCreated(
        address indexed owner,
        address gpadPool,
        address indexed idoToken,
        string tokenURI
    );

    event IDOCreatedByHelper(
        address indexed owner,
        address gpadPool,
        address indexed idoToken,
        string tokenURI,
        uint256 idoTokenAmount,     // IDO token exact amount
        uint256 lpTokenAmount      // LP token exact amount
    );

    event TokenFeeUpdated(address newFeeToken);
    event FeeAmountUpdated(uint256 newFeeAmount);
    event BurnPercentUpdated(uint256 newBurnPercent, uint256 divider);
    event FeeWalletUpdated(address newFeeWallet);

    event GPADPoolInitialized(
        address indexed gpadPool,
        address indexed idoToken,
        GPADPool.FinInfo finInfo,
        GPADPool.Timestamps timestamps,
        GPADPool.DEXInfo dexInfo,
        string metadataURL
    );

    /**
     * @dev Constructor
     * @param _feeToken Token used for fee payment
     * @param _feeAmount Amount of tokens to charge as fee
     * @param _burnPercent Percentage of fee tokens to burn
     */
    constructor(
        ERC20Burnable _feeToken,
        uint256 _feeAmount,
        uint256 _burnPercent
    ){
        feeToken = _feeToken;
        feeAmount = _feeAmount;
        burnPercent = _burnPercent;
        divider = 100;
    }

    /**
     * @dev Get all IDO pools created by this factory
     * @return Array of pool addresses
     */
    function getIdoPools() public view returns (address[] memory) {
      return idoPools;
    }

    /**
     * @dev Set new fee token
     * @param _newFeeToken Address of new fee token
     */
    function setFeeToken(address _newFeeToken) external onlyOwner {
        _validateContractAddress(_newFeeToken, "New address is not a token");
        feeToken = ERC20Burnable(_newFeeToken);

        emit TokenFeeUpdated(_newFeeToken);
    }

    /**
     * @dev Set new fee amount
     * @param _newFeeAmount New fee amount to charge
     */
    function setFeeAmount(uint256 _newFeeAmount) external onlyOwner {
        feeAmount = _newFeeAmount;

        emit FeeAmountUpdated(_newFeeAmount);
    }

    /**
     * @dev Set new fee wallet
     * @param _newFeeWallet Address of new fee wallet
     */
    function setFeeWallet(address _newFeeWallet) external onlyOwner {
        feeWallet = _newFeeWallet;

        emit FeeWalletUpdated(_newFeeWallet);
    }

    /**
     * @dev Set new burn percentage
     * @param _newBurnPercent New percentage of fee to burn
     * @param _newDivider New divider for percentage calculation
     */
    function setBurnPercent(uint256 _newBurnPercent, uint256 _newDivider)
        external
        onlyOwner
    {
        require(_newBurnPercent <= _newDivider, "Burn percent must be less than divider");
        burnPercent = _newBurnPercent;
        divider = _newDivider;

        emit BurnPercentUpdated(_newBurnPercent, _newDivider);
    }

    /**
     * @dev Handle fee collection and burning
     */
    function handleFees() internal {
       if(feeAmount > 0) {
           if (burnPercent > 0) {
               uint256 burnAmount = feeAmount.mul(burnPercent).div(divider);
               uint256 transferAmount = feeAmount.sub(burnAmount);
               
               if (transferAmount > 0) {
                   feeToken.safeTransferFrom(msg.sender, feeWallet, transferAmount);
               }
               
               if (burnAmount > 0) {
                   feeToken.burnFrom(msg.sender, burnAmount);
               }
           } else {
               feeToken.safeTransferFrom(msg.sender, feeWallet, feeAmount);
           }
       }
    }

    /**
     * @dev Create a new GPAD Pool
     * @param _idoToken Token to be distributed in the IDO
     * @param _finInfo Financial parameters of the IDO (note: lpInterestRate will be ignored)
     * @param _timestamps Timestamp parameters (start and end)
     * @param _dexInfo DEX configuration information
     * @param _metadataURL URL to IDO metadata
     * @param idoTokenAmount Amount of tokens allocated for IDO
     * @param lpTokenAmount Amount of tokens allocated for liquidity
     * @return gpadPoolAddress Address of created pool
     */
    function createIDOPool(
        ERC20 _idoToken,
        GPADPool.FinInfo memory _finInfo,
        GPADPool.Timestamps memory _timestamps,
        GPADPool.DEXInfo memory _dexInfo,
        string memory _metadataURL,
        uint256 idoTokenAmount,
        uint256 lpTokenAmount
    ) external returns (address gpadPoolAddress) {
        // Note: lpInterestRate in _finInfo will be ignored as all ETH goes to liquidity
        GPADPool gpadPool = new GPADPool(
            _idoToken,
            _finInfo,
            _timestamps,
            _dexInfo,
            _metadataURL
        );

        // Trigger initialized event
        emit GPADPoolInitialized(
            address(gpadPool),
            address(_idoToken),
            _finInfo,
            _timestamps,
            _dexInfo,
            _metadataURL
        );

        // Use exact token amount
        uint256 transferAmount = idoTokenAmount + lpTokenAmount;

        // Transfer ownership
        gpadPool.transferOwnership(msg.sender);
        
        // Set pool address
        gpadPoolAddress = address(gpadPool);

        // Transfer token to pool
        _idoToken.safeTransferFrom(
            msg.sender,
            gpadPoolAddress,
            transferAmount
        );

        // Record pool address
        idoPools.push(gpadPoolAddress);

        // Trigger event
        emit IDOCreatedByHelper(
            msg.sender,
            gpadPoolAddress,
            address(_idoToken),
            _metadataURL,
            idoTokenAmount, 
            lpTokenAmount
        );

        handleFees();

        return gpadPoolAddress;
    }

    /**
     * @dev Calculate token amount based on ETH amount and token price
     * @param ethAmount Amount of ETH
     * @param tokenPrice Price of token in ETH
     * @param decimals Token decimals
     * @return Token amount
     */
    function getTokenAmount(
        uint256 ethAmount,
        uint256 tokenPrice,
        uint8 decimals
    ) internal pure returns (uint256) {
        return (ethAmount / tokenPrice) * (10**decimals);
    }

    /**
     * @dev Validate if address is a contract
     * @param _addr Address to check
     * @param errorMsg Error message to return if validation fails
     */
    function _validateContractAddress(address _addr, string memory errorMsg) private view {
        if (_addr == address(0)) revert InvalidAddress("Zero address");
        if (!isContract(_addr)) revert InvalidAddress(errorMsg);
    }

    /**
     * @dev Check if address contains contract code
     * @param _addr Address to check
     * @return Whether address is a contract
     */
    function isContract(address _addr) private view returns (bool) {
        uint32 size;
        assembly {
            size := extcodesize(_addr)
        }
        return (size > 0);
    }

    /**
     * @dev Recover any tokens or ETH sent to this contract
     * @param _tokenAddress Address of token to recover (zero address for ETH)
     * @param _amount Amount to recover (0 for all available balance)
     */
    function recoverFunds(address _tokenAddress, uint256 _amount) external onlyOwner {
        if (_tokenAddress == address(0)) {
            // Recover ETH
            uint256 balance = address(this).balance;
            uint256 amountToRecover = _amount == 0 ? balance : (_amount < balance ? _amount : balance);
            if (amountToRecover > 0) {
                (bool success,) = payable(owner()).call{value: amountToRecover}("");
                require(success, "ETH transfer failed");
            }
        } else {
            // Recover tokens
            IERC20 token = IERC20(_tokenAddress);
            uint256 balance = token.balanceOf(address(this));
            uint256 amountToRecover = _amount == 0 ? balance : (_amount < balance ? _amount : balance);
            if (amountToRecover > 0) {
                token.safeTransfer(owner(), amountToRecover);
            }
        }
    }

    /**
     * @dev Receive ETH
     */
    receive() external payable {}
}
        

@openzeppelin/contracts/access/Ownable.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @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.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "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 {
        _setOwner(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), "Ownable: new owner is the zero address");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
          

@openzeppelin/contracts/security/ReentrancyGuard.sol

// SPDX-License-Identifier: MIT

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

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

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

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

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

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override 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 this function is
     * overridden;
     *
     * 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 virtual override returns (uint8) {
        return 18;
    }

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

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

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

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

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        unchecked {
            _approve(sender, _msgSender(), currentAllowance - 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(_msgSender(), spender, _allowances[_msgSender()][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) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(_msgSender(), spender, currentAllowance - subtractedValue);
        }

        return true;
    }

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

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[sender] = senderBalance - amount;
        }
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);

        _afterTokenTransfer(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:
     *
     * - `account` 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);

        _afterTokenTransfer(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);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This 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 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 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 Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been 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 _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}
          

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

// SPDX-License-Identifier: MIT

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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

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

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

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

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

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

@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../ERC20.sol";
import "../../../utils/Context.sol";

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys `amount` tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 amount) public virtual {
        _burn(_msgSender(), amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, deducting from the caller's
     * allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `amount`.
     */
    function burnFrom(address account, uint256 amount) public virtual {
        uint256 currentAllowance = allowance(account, _msgSender());
        require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance");
        unchecked {
            _approve(account, _msgSender(), currentAllowance - amount);
        }
        _burn(account, amount);
    }
}
          

@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}
          

@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

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

@openzeppelin/contracts/utils/Address.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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);
            }
        }
    }
}
          

@openzeppelin/contracts/utils/Context.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}
          

@openzeppelin/contracts/utils/math/Math.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}
          

@openzeppelin/contracts/utils/math/SafeMath.sol

// SPDX-License-Identifier: MIT

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 no longer needed starting with Solidity 0.8. 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;
        }
    }
}
          

contracts/GPAD/GPADPool.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "./IUniswapV2Router02.sol";
import "./IUniswapV2Factory.sol";

contract GPADPool is Ownable, ReentrancyGuard {
    using SafeMath for uint256;
    using SafeERC20 for ERC20;
    using SafeERC20 for IERC20;

    // Fixed burn address for LP tokens
    address private constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

    struct FinInfo {
        uint256 tokenPrice;      // Price of one token in WEI for IDO
        uint256 softCap;         // Minimum ETH amount to consider IDO successful
        uint256 hardCap;         // Maximum ETH amount to raise in IDO
        uint256 minEthPayment;   // Minimum ETH amount per user
        uint256 maxEthPayment;   // Maximum ETH amount per user
        uint256 listingPrice;    // Price of one token in WEI for listing
    }

    struct Timestamps {
        uint256 startTimestamp;  // When IDO starts
        uint256 endTimestamp;    // When IDO ends
    }

    struct DEXInfo {
        address router;          // DEX router address
        address factory;         // DEX factory address
        address weth;            // WETH token address
    }

    struct UserInfo {
        uint debt;               // Tokens owed to user
        uint total;              // Total tokens allocated to user
        uint totalInvestedETH;   // Total ETH invested by user
    }

    ERC20 public idoToken;    // Token being sold in IDO
    uint256 public decimals;     // Token decimals
    string public metadataURL;   // Project metadata URL

    FinInfo public finInfo;      // Financial parameters
    Timestamps public timestamps; // Time parameters
    DEXInfo public dexInfo;      // DEX parameters

    uint256 public totalInvestedETH;      // Total ETH raised
    uint256 public tokensForDistribution; // Total tokens for users
    uint256 public distributedTokens;     // Tokens already claimed

    bool public distributed = false;      // Whether liquidity has been added

    mapping(address => UserInfo) public userInfo; // User participation info

    // Events
    event TokensDebt(
        address indexed holder,
        uint256 ethAmount,
        uint256 tokenAmount
    );

    event TokensWithdrawn(address indexed holder, uint256 amount);

    event LPBurned(
        address indexed token,
        address indexed pairedToken,
        uint256 ethAmount,
        uint256 tokenAmount,
        address burnAddress,
        uint256 liquidity
    );

    event EmergencyWithdraw(address indexed recipient, uint256 amount);

    /**
     * @dev Constructor - simplified parameters
     * @param _idoToken Token to be distributed in the IDO
     * @param _finInfo Financial parameters of the IDO
     * @param _timestamps Timestamp parameters for IDO
     * @param _dexInfo DEX configuration information
     * @param _metadataURL URL to IDO metadata
     */
    constructor(
        ERC20 _idoToken,
        FinInfo memory _finInfo,
        Timestamps memory _timestamps,
        DEXInfo memory _dexInfo,
        string memory _metadataURL
    ) {
        idoToken = _idoToken;
        decimals = idoToken.decimals();
        
        finInfo = _finInfo;
        setTimestamps(_timestamps);
        dexInfo = _dexInfo;
        setMetadataURL(_metadataURL);
    }

    /**
     * @dev Set timestamps for the IDO pool
     * @param _timestamps Timestamp structure with start and end times
     */
    function setTimestamps(Timestamps memory _timestamps) internal {
        require(
            _timestamps.startTimestamp < _timestamps.endTimestamp,
            "Start timestamp must be less than finish timestamp"
        );
        require(
            _timestamps.endTimestamp > block.timestamp,
            "Finish timestamp must be more than current block"
        );

        timestamps = _timestamps;
    }

    /**
     * @dev Set metadata URL for the IDO
     * @param _metadataURL URL to IDO metadata
     */
    function setMetadataURL(string memory _metadataURL) public {
        metadataURL = _metadataURL;
    }

    /**
     * @dev Allow users to invest ETH in the IDO
     */
    function pay() payable external {
        // Control participation state only by time
        require(block.timestamp >= timestamps.startTimestamp, "Not started");
        require(block.timestamp < timestamps.endTimestamp, "Ended");

        require(msg.value >= finInfo.minEthPayment, "Less than min amount");
        require(msg.value <= finInfo.maxEthPayment, "More than max amount");
        require(totalInvestedETH.add(msg.value) <= finInfo.hardCap, "Overfilled");

        UserInfo storage user = userInfo[msg.sender];
        require(user.totalInvestedETH.add(msg.value) <= finInfo.maxEthPayment, "More than max amount");

        uint256 tokenAmount = getTokenAmount(msg.value, finInfo.tokenPrice);

        totalInvestedETH = totalInvestedETH.add(msg.value);
        tokensForDistribution = tokensForDistribution.add(tokenAmount);
        user.totalInvestedETH = user.totalInvestedETH.add(msg.value);
        user.total = user.total.add(tokenAmount);
        user.debt = user.debt.add(tokenAmount);

        emit TokensDebt(msg.sender, msg.value, tokenAmount);
    }

    /**
     * @dev Allow users to refund if soft cap not reached
     */
    function refund() external nonReentrant {
        require(block.timestamp > timestamps.endTimestamp, "IDO pool has not ended");
        require(totalInvestedETH < finInfo.softCap, "IDO pool has reached soft cap");

        UserInfo storage user = userInfo[msg.sender];

        uint256 _amount = user.totalInvestedETH;
        require(_amount > 0, "You have no investment");

        // update global state
        totalInvestedETH = totalInvestedETH.sub(_amount);
        tokensForDistribution = tokensForDistribution.sub(user.total);
        
        // update user state
        user.debt = 0;
        user.totalInvestedETH = 0;
        user.total = 0;

        // transfer ETH
        (bool success, ) = msg.sender.call{value: _amount}("");
        require(success, "Transfer failed");
    }

    /**
     * @dev Allow admin to claim tokens for a user
     * @param _user Address of user to process claim for
     */
    function claimFor(address _user) external nonReentrant {    
        proccessClaim(_user);
    }

    /**
     * @dev Allow users to claim their tokens
     */
    function claim() external nonReentrant {
        proccessClaim(msg.sender);
    }

    /**
     * @dev Process token claims for a specified address
     * @param _receiver Address to receive tokens
     */
    function proccessClaim(address _receiver) internal {
        require(block.timestamp > timestamps.endTimestamp, "IDO pool has not ended");
        require(totalInvestedETH >= finInfo.softCap, "IDO pool did not reach soft cap");
        require(distributed, "IDO pool has not been distributed");
        UserInfo storage user = userInfo[_receiver];

        uint256 _amount = user.debt;
        require(_amount > 0, "You do not have debt tokens");

        user.debt = 0;
        distributedTokens = distributedTokens.add(_amount);
        idoToken.safeTransfer(_receiver, _amount);
        
        emit TokensWithdrawn(_receiver, _amount);
    }

    /**
     * @dev Withdraw ETH and create liquidity - All LP tokens are burned
     * All collected ETH is used for liquidity, no funds are sent to owner
     */
    function withdrawETH() external payable nonReentrant {
        require(block.timestamp > timestamps.endTimestamp, "IDO pool has not ended");
        require(totalInvestedETH >= finInfo.softCap, "Soft cap not reached");
        require(!distributed, "Already distributed");

        uint256 balance = address(this).balance;
        require(balance > 0, "No ETH to create liquidity");

        // Use all ETH for liquidity
        uint256 ethForLP = balance;
        
        // Calculate token amount needed at listing price
        uint256 tokenAmount = getTokenAmount(ethForLP, finInfo.listingPrice);
        
        // Ensure we have enough tokens
        require(idoToken.balanceOf(address(this)) >= tokenAmount, "Insufficient token balance");

        // Add liquidity - all LP tokens are sent directly to burn address
        IUniswapV2Router02 uniswapRouter = IUniswapV2Router02(dexInfo.router);
        idoToken.approve(address(uniswapRouter), tokenAmount);
        
        // Record balance before adding liquidity to optimize gas usage
        uint256 preBalance = address(this).balance;
        
        // Add all ETH to liquidity
        (uint amountToken, uint amountETH, uint liquidity) = uniswapRouter.addLiquidityETH{value: ethForLP}(
            address(idoToken),
            tokenAmount,
            0, // slippage is unavoidable
            0, // slippage is unavoidable
            BURN_ADDRESS, // Send LP tokens directly to burn address
            block.timestamp + 360
        );
        
        // Emit LP burned event
        emit LPBurned(
            address(idoToken),
            dexInfo.weth,
            amountETH,
            amountToken,
            BURN_ADDRESS,
            liquidity
        );

        distributed = true;
    }

    /**
     * @dev Withdraw tokens that were not sold during the IDO
     */
    function withdrawNotSoldTokens() external onlyOwner {
        require(distributed, "Withdraw allowed after distributed");

        uint256 balance = getNotSoldToken();
        require(balance > 0, "No unsold tokens");
        idoToken.safeTransfer(msg.sender, balance);
    }

    /**
     * @dev Get the amount of tokens that were not sold during the IDO
     * @return Amount of unsold tokens
     */
    function getNotSoldToken() public view returns(uint256) {
        uint256 balance = idoToken.balanceOf(address(this));
        return balance.add(distributedTokens).sub(tokensForDistribution);
    }

    /**
     * @dev Refund tokens to owner if soft cap not reached
     */
    function refundTokens() external onlyOwner {
        require(block.timestamp > timestamps.endTimestamp, "IDO pool has not ended");
        require(totalInvestedETH < finInfo.softCap, "IDO pool has reached soft cap");

        uint256 balance = idoToken.balanceOf(address(this));
        require(balance > 0, "No tokens to refund");
        idoToken.safeTransfer(msg.sender, balance);
    }

    /**
     * @dev Calculate token amount based on ETH amount and price
     * @param ethAmount Amount of ETH
     * @param oneTokenInWei Price of one token in WEI
     * @return Amount of tokens
     */
    function getTokenAmount(uint256 ethAmount, uint256 oneTokenInWei)
        internal
        view
        returns (uint256)
    {
        require(oneTokenInWei > 0, "Token price cannot be zero");
        return (ethAmount / oneTokenInWei) * 10**decimals;
    }


    /**
     * @dev Recover any tokens or ETH from this contract
     * @param _tokenAddress Address of token to recover (zero address for ETH)
     * @param _amount Amount to recover (0 for all available balance)
     */
    function recoverFunds(address _tokenAddress, uint256 _amount) external onlyOwner nonReentrant {
        if (_tokenAddress == address(0)) {
            // Recover ETH
            uint256 balance = address(this).balance;
            uint256 amountToRecover = _amount == 0 ? balance : (_amount < balance ? _amount : balance);
            require(amountToRecover > 0, "No ETH to recover");
            
            (bool success,) = payable(owner()).call{value: amountToRecover}("");
            require(success, "ETH transfer failed");
        } else if (_tokenAddress == address(idoToken)) {
            // Recover reward tokens with special handling
            require(distributed || block.timestamp > timestamps.endTimestamp && totalInvestedETH < finInfo.softCap, 
                    "Can only recover reward tokens after distribution or failed IDO");
            
            uint256 balance = idoToken.balanceOf(address(this));
            uint256 availableBalance = block.timestamp > timestamps.endTimestamp && totalInvestedETH < finInfo.softCap ? 
                                      balance : getNotSoldToken();
            
            uint256 amountToRecover = _amount == 0 ? availableBalance : (_amount < availableBalance ? _amount : availableBalance);
            require(amountToRecover > 0, "No tokens available to recover");
            
            idoToken.safeTransfer(owner(), amountToRecover);
        } else {
            // Recover other tokens
            IERC20 token = IERC20(_tokenAddress);
            uint256 balance = token.balanceOf(address(this));
            uint256 amountToRecover = _amount == 0 ? balance : (_amount < balance ? _amount : balance);
            require(amountToRecover > 0, "No tokens to recover");
            
            token.safeTransfer(owner(), amountToRecover);
        }
    }
}
          

contracts/GPAD/IUniswapV2Factory.sol

pragma solidity >=0.5.0;

interface IUniswapV2Factory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint);

    function feeTo() external view returns (address);
    function feeToSetter() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function allPairs(uint) external view returns (address pair);
    function allPairsLength() external view returns (uint);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;
    function setFeeToSetter(address) external;
}
          

contracts/GPAD/IUniswapV2Router01.sol

pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    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);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
          

contracts/GPAD/IUniswapV2Router02.sol

pragma solidity >=0.6.2;

import './IUniswapV2Router01.sol';

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}
          

Compiler Settings

{"viaIR":true,"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"bytecodeHash":"none"},"libraries":{},"evmVersion":"london"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_feeToken","internalType":"contract ERC20Burnable"},{"type":"uint256","name":"_feeAmount","internalType":"uint256"},{"type":"uint256","name":"_burnPercent","internalType":"uint256"}]},{"type":"error","name":"InvalidAddress","inputs":[{"type":"string","name":"message","internalType":"string"}]},{"type":"event","name":"BurnPercentUpdated","inputs":[{"type":"uint256","name":"newBurnPercent","internalType":"uint256","indexed":false},{"type":"uint256","name":"divider","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FeeAmountUpdated","inputs":[{"type":"uint256","name":"newFeeAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FeeWalletUpdated","inputs":[{"type":"address","name":"newFeeWallet","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"GPADPoolInitialized","inputs":[{"type":"address","name":"gpadPool","internalType":"address","indexed":true},{"type":"address","name":"idoToken","internalType":"address","indexed":true},{"type":"tuple","name":"finInfo","internalType":"struct GPADPool.FinInfo","indexed":false,"components":[{"type":"uint256","name":"tokenPrice","internalType":"uint256"},{"type":"uint256","name":"softCap","internalType":"uint256"},{"type":"uint256","name":"hardCap","internalType":"uint256"},{"type":"uint256","name":"minEthPayment","internalType":"uint256"},{"type":"uint256","name":"maxEthPayment","internalType":"uint256"},{"type":"uint256","name":"listingPrice","internalType":"uint256"}]},{"type":"tuple","name":"timestamps","internalType":"struct GPADPool.Timestamps","indexed":false,"components":[{"type":"uint256","name":"startTimestamp","internalType":"uint256"},{"type":"uint256","name":"endTimestamp","internalType":"uint256"}]},{"type":"tuple","name":"dexInfo","internalType":"struct GPADPool.DEXInfo","indexed":false,"components":[{"type":"address","name":"router","internalType":"address"},{"type":"address","name":"factory","internalType":"address"},{"type":"address","name":"weth","internalType":"address"}]},{"type":"string","name":"metadataURL","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"IDOCreated","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"gpadPool","internalType":"address","indexed":false},{"type":"address","name":"idoToken","internalType":"address","indexed":true},{"type":"string","name":"tokenURI","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"IDOCreatedByHelper","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"gpadPool","internalType":"address","indexed":false},{"type":"address","name":"idoToken","internalType":"address","indexed":true},{"type":"string","name":"tokenURI","internalType":"string","indexed":false},{"type":"uint256","name":"idoTokenAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"lpTokenAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"TokenFeeUpdated","inputs":[{"type":"address","name":"newFeeToken","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"burnPercent","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":"gpadPoolAddress","internalType":"address"}],"name":"createIDOPool","inputs":[{"type":"address","name":"_idoToken","internalType":"contract ERC20"},{"type":"tuple","name":"_finInfo","internalType":"struct GPADPool.FinInfo","components":[{"type":"uint256","name":"tokenPrice","internalType":"uint256"},{"type":"uint256","name":"softCap","internalType":"uint256"},{"type":"uint256","name":"hardCap","internalType":"uint256"},{"type":"uint256","name":"minEthPayment","internalType":"uint256"},{"type":"uint256","name":"maxEthPayment","internalType":"uint256"},{"type":"uint256","name":"listingPrice","internalType":"uint256"}]},{"type":"tuple","name":"_timestamps","internalType":"struct GPADPool.Timestamps","components":[{"type":"uint256","name":"startTimestamp","internalType":"uint256"},{"type":"uint256","name":"endTimestamp","internalType":"uint256"}]},{"type":"tuple","name":"_dexInfo","internalType":"struct GPADPool.DEXInfo","components":[{"type":"address","name":"router","internalType":"address"},{"type":"address","name":"factory","internalType":"address"},{"type":"address","name":"weth","internalType":"address"}]},{"type":"string","name":"_metadataURL","internalType":"string"},{"type":"uint256","name":"idoTokenAmount","internalType":"uint256"},{"type":"uint256","name":"lpTokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"divider","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"feeAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ERC20Burnable"}],"name":"feeToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeWallet","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getIdoPools","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"idoPools","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recoverFunds","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBurnPercent","inputs":[{"type":"uint256","name":"_newBurnPercent","internalType":"uint256"},{"type":"uint256","name":"_newDivider","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeAmount","inputs":[{"type":"uint256","name":"_newFeeAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeToken","inputs":[{"type":"address","name":"_newFeeToken","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeWallet","inputs":[{"type":"address","name":"_newFeeWallet","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

Verify & Publish
0x6080346100be57601f61374538819003918201601f19168301916001600160401b038311848410176100c3578084926060946040528339810103126100be5780516001600160a01b0391828216918290036100be57604060208201519101519160005460018060a01b0319903382821617600055604051953391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a36001541617600155600355600455606460055561366b90816100da8239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608060405260043610156200001d575b36156200001b57600080fd5b005b60003560e01c806303807ee5146200013c5780630fa3b5cc146200013657806315cce2241462000130578063378efa37146200012a578063586097541462000124578063647846a5146200011e57806369e1540414620001185780636a1860e214620001125780636b392680146200010c5780637104c9fd1462000106578063715018a614620001005780638da5cb5b14620000fa5780638dc1299114620000f457806390d49b9d14620000ee578063f25f4b5614620000e85763f2fde38b036200000f5762000aa4565b62000a79565b620009f6565b62000930565b62000905565b620008a2565b62000844565b620007e7565b62000715565b620006f5565b620006ca565b62000552565b62000532565b62000401565b62000322565b62000153565b60009103126200014e57565b600080fd5b346200014e5760003660031901126200014e576020600454604051908152f35b6001600160a01b038116036200014e57565b634e487b7160e01b600052604160045260246000fd5b60c0810190811067ffffffffffffffff821117620001b857604052565b62000185565b67ffffffffffffffff8111620001b857604052565b6040810190811067ffffffffffffffff821117620001b857604052565b90601f8019910116810190811067ffffffffffffffff821117620001b857604052565b60409060e31901126200014e57604051906040820182811067ffffffffffffffff821117620001b85760405260e4358252610104356020830152565b6060906101231901126200014e57604051906060820182811067ffffffffffffffff821117620001b85760405281610124356200028c8162000173565b8152610144356200029d8162000173565b602082015260406101643591620002b48362000173565b0152565b67ffffffffffffffff8111620001b857601f01601f191660200190565b81601f820112156200014e57803590620002ef82620002b8565b92620002ff6040519485620001f0565b828452602083830101116200014e57816000926020809301838601378301015290565b346200014e576101e03660031901126200014e57600435620003448162000173565b60c03660231901126200014e576040516200035f816200019b565b602435815260443560208201526064356040820152608435606082015260a435608082015260c43560a0820152620003973662000213565b90620003a3366200024f565b92610184359267ffffffffffffffff84116200014e57620003fd94620003d2620003e3953690600401620002d5565b916101c435946101a4359462000e5d565b6040516001600160a01b0390911681529081906020820190565b0390f35b346200014e5760203660031901126200014e57600435620004228162000173565b6000546001600160a01b03906200043d908216331462000b47565b604051906200044c82620001d3565b601a82527f4e65772061646472657373206973206e6f74206120746f6b656e00000000000060208301528216908115620004fd57823b63ffffffff1615620004da57600180546001600160a01b0319166001600160a01b0384161790557f9e892f555b0a5cac6c8cc33c82ebb9308207bd16dfdca9d0289b96d7e4186c8a620004d584620003e3565b0390a1005b604051630b0f5aa160e11b8152908190620004f9906004830162001199565b0390fd5b604051630b0f5aa160e11b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606490fd5b346200014e5760003660031901126200014e576020600554604051908152f35b346200014e5760403660031901126200014e57600435620005738162000173565b600080549091602435916001600160a01b03908116916200059633841462000b47565b1690816200061657505047908015600014620005fd57505b8181620005ba57505080f35b808080620005fa94620005e7620005db620005db845460018060a01b031690565b6001600160a01b031690565b5af1620005f362001164565b5062001351565b80f35b90808210156200060e5750620005ae565b9050620005ae565b6040516370a0823160e01b81523060048201529192909190602082602481875afa918215620006c45785926200068d575b5080620006725750905b816200065e575b50505080f35b620006699262001394565b38808062000658565b90808210156200068557505b9062000651565b90506200067e565b620006b491925060203d8111620006bc575b620006ab8183620001f0565b81019062001341565b903862000647565b503d6200069f565b62000cd0565b346200014e5760003660031901126200014e576001546040516001600160a01b039091168152602090f35b346200014e5760003660031901126200014e576020600354604051908152f35b346200014e57600080600319360112620007e45760405180916006549081835260208093018092600683527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90835b818110620007c657505050846200077d910385620001f0565b60405193838594850191818652518092526040850193925b828110620007a557505050500390f35b83516001600160a01b03168552869550938101939281019260010162000795565b82546001600160a01b03168452928601926001928301920162000764565b80fd5b346200014e5760203660031901126200014e577fbb128cd9921d003aff00ed910fe24b1655b2bf1f4a2090cc3523f61bdc17231660206004356200083760018060a01b0360005416331462000b47565b80600355604051908152a1005b346200014e5760203660031901126200014e576004356006548110156200014e5760066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01546040516001600160a01b039091168152602090f35b346200014e57600080600319360112620007e457805481906001600160a01b03811690620008d233831462000b47565b6001600160a01b03191682557f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b346200014e5760003660031901126200014e576000546040516001600160a01b039091168152602090f35b346200014e5760403660031901126200014e576004356024356200096060018060a01b0360005416331462000b47565b808211620009a257816040917fb62d69c6ddf4f4bd443dca17ea7405d8018efb872e82e77bb8ef13b5be2f2e9c936004558060055582519182526020820152a1005b60405162461bcd60e51b815260206004820152602660248201527f4275726e2070657263656e74206d757374206265206c657373207468616e206460448201526534bb34b232b960d11b6064820152608490fd5b346200014e5760203660031901126200014e577f29acee77dafcfa0143d74a7ea236018f3a6e1fa71e27fc59bbfbc6b8ca8edccd602060043562000a3a8162000173565b6000546001600160a01b03919062000a56908316331462000b47565b16806bffffffffffffffffffffffff60a01b6002541617600255604051908152a1005b346200014e5760003660031901126200014e576002546040516001600160a01b039091168152602090f35b346200014e5760203660031901126200014e5760043562000ac58162000173565b6000546001600160a01b039062000ae0908216331462000b47565b81161562000af3576200001b9062000b93565b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b1562000b4f57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3565b919082519283825260005b84811062000c07575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520162000be5565b9262000c8b9062000c7862000cba9462000ccd98979460018060a01b03168752602087019060a0809180518452602081015160208501526040810151604085015260608101516060850152608081015160808501520151910152565b805160e086015260200151610100850152565b80516001600160a01b039081166101208501526020820151811661014085015260409091015116610160830152565b6101a09081610180820152019062000bda565b90565b6040513d6000823e3d90fd5b919262000d3b62000ccd959462000d298562000d6a9560a0809180518452602081015160208501526040810151604085015260608101516060850152608081015160808501520151910152565b805160c08601526020015160e0850152565b80516001600160a01b039081166101008501526020820151811661012085015260409091015116610140830152565b6101809081610160820152019062000bda565b634e487b7160e01b600052601160045260246000fd5b9190820180921162000da157565b62000d7d565b60065468010000000000000000811015620001b857600181018060065581101562000e125760066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0180546001600160a01b0319166001600160a01b03909216919091179055565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0390911681526080602082018190529294939260609262000e539183019062000bda565b9460408201520152565b9591939492909560405161228580820182811067ffffffffffffffff821117620001b8578885898c8762000e99958897620013da893962000c1c565b03906000f0968715620006c45786957f6280933c1d06e26a4d5de0f4ae608636e94c4baf579e360d13e16c7b27302fc99162000eec60018060a01b03809b169a8b9516998a966040519485948562000cdc565b0390a362000efb818362000d93565b91853b156200014e5760405163f2fde38b60e01b815233600482015292600084602481838b5af1908115620006c4577fbb1e34963a7cf74028f70419838711c854e9716294c07397f076ff3ec10e04bb9462000f619262000f8d575b5087338862000fab565b62000f6c8662000da7565b62000f806040519283923396898562000e28565b0390a362000ccd620011f0565b8062000f9d62000fa492620001be565b8062000142565b3862000f57565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815260a081019181831067ffffffffffffffff841117620001b857620010079260405262001083565b565b908160209103126200014e575180151581036200014e5790565b156200102b57565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b6040516001600160a01b0391909116916200109e82620001d3565b6020928383527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656484840152803b156200111f5760008281928287620010f59796519301915af1620010ee62001164565b90620011ac565b805190816200110357505050565b8262001007936200111993830101910162001009565b62001023565b60405162461bcd60e51b815260048101859052601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b3d1562001194573d906200117882620002b8565b91620011886040519384620001f0565b82523d6000602084013e565b606090565b90602062000ccd92818152019062000bda565b90919015620011b9575090565b815115620011ca5750805190602001fd5b60405162461bcd60e51b815260206004820152908190620004f990602483019062000bda565b60035480620011fc5750565b60045415620012e1575060035462001231620012296200121f600454846200130c565b6005549062001320565b8092620012fe565b80620012a8575b508062001243575b50565b6001546200125a906001600160a01b0316620005db565b803b156200014e5760405163079cc67960e41b815233600482015260248101929092526000908290604490829084905af18015620006c4571562001240578062000f9d6200100792620001be565b600154620012da9190620012c5906001600160a01b0316620005db565b6002546001600160a01b031690339062000fab565b3862001238565b600154620010079190620012c5906001600160a01b0316620005db565b9190820391821162000da157565b8181029291811591840414171562000da157565b81156200132b570490565b634e487b7160e01b600052601260045260246000fd5b908160209103126200014e575190565b156200135957565b60405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606490fd5b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526200100791620013d3606483620001f0565b6200108356fe608060405234620005b05762002285803803809162000020826080620005b5565b6080396101a08112620005b0576080516001600160a01b0381168103620005b05760c0601f19830112620005b05760405160c081016001600160401b038111828210176200046c57604090815260a08051835260c051602084015260e05183830152610100516060840152610120516080840152610140519083015260df19840112620005b05760408051919082018083116001600160401b03909111176200046c5760408281019052610160518252610180516020830152606061011f19850112620005b057604051926001600160401b0360608501908111908511176200046c5760608401604052620001176101a0620005d9565b8452620001266101c0620005d9565b6020850152620001386101e0620005d9565b6040850152610200516001600160401b038111620005b05760808601609f82011215620005b0576080810151906001600160401b0382116200046c57604051966200018e601f8401601f191660200189620005b5565b82885260800160a08284010111620005b05760005b8281106200059757505060206000918701015260206000543360018060a01b0319821617600055600460405180948193339060018060a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3600180556013805460ff19169055600280546001600160a01b0319166001600160a01b0392909216918217905563313ce56760e01b82525afa9081156200058b5760009162000540575b509060ff60a09216600355805160055560208101516006556040810151600755606081015160085560808101516009550151600a55805160208201511115620004e057602081015142101562000482578051600b55602090810151600c558151600d80546001600160a01b039283166001600160a01b03199182161790915591830151600e8054918316918416919091179055604090920151600f805491909316911617905580516001600160401b0381116200046c57600454600181811c9116801562000461575b60208210146200044b57601f8111620003e1575b50602091601f821160011462000377579181926000926200036b575b50508160011b916000199060031b1c1916176004555b604051611c969081620005ef8239f35b01519050388062000345565b601f19821692600460005260206000209160005b858110620003c857508360019510620003ae575b505050811b016004556200035b565b015160001960f88460031b161c191690553880806200039f565b919260206001819286850151815501940192016200038b565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c8101916020841062000440575b601f0160051c01905b81811062000433575062000329565b6000815560010162000424565b90915081906200041b565b634e487b7160e01b600052602260045260246000fd5b90607f169062000315565b634e487b7160e01b600052604160045260246000fd5b60405162461bcd60e51b815260206004820152603060248201527f46696e6973682074696d657374616d70206d757374206265206d6f726520746860448201526f616e2063757272656e7420626c6f636b60801b6064820152608490fd5b60405162461bcd60e51b815260206004820152603260248201527f53746172742074696d657374616d70206d757374206265206c6573732074686160448201527106e2066696e6973682074696d657374616d760741b6064820152608490fd5b6020813d60201162000582575b816200055c60209383620005b5565b810103126200057e57519060ff821682036200057b575060ff6200024c565b80fd5b5080fd5b3d91506200054d565b6040513d6000823e3d90fd5b80602080928460800101015182828b01015201620001a3565b600080fd5b601f909101601f19168101906001600160401b038211908210176200046c57604052565b51906001600160a01b0382168203620005b05756fe6080604052600436101561001257600080fd5b60003560e01c806312d3675e146101975780631959a002146101925780631b9265b81461018d5780632dcc8c6614610188578063313ce56714610183578063491447a81461017e5780634b1a4c0c146101795780634e71d92d14610174578063586097541461016f578063586360ce1461016a578063590e1ae31461016557806362bea93f14610160578063710075091461015b578063715018a614610156578063747daec5146101515780638da5cb5b1461014c578063c6a0e27d14610147578063d6cd82bc14610142578063d8d2a56d1461013d578063ddeae03314610138578063e086e5ec14610133578063f2fde38b1461012e578063f84b903e146101295763fd46a1711461012457600080fd5b611013565b610ff0565b610f5a565b610c76565b610c41565b610c04565b610bdb565b610af8565b610acf565b610a5a565b6109df565b610926565b610903565b610861565b610843565b6105c3565b61058f565b610571565b610548565b61052a565b610445565b61024b565b6101fa565b346101df5760003660031901126101df5760c060055460065460075460085460095491600a5493604051958652602086015260408501526060840152608083015260a0820152f35b600080fd5b600435906001600160a01b03821682036101df57565b346101df5760203660031901126101df576001600160a01b0361021b6101e4565b16600052601460205260606040600020805490600260018201549101549060405192835260208301526040820152f35b60003660031901126101df57610265600b5442101561121e565b610272600c544210611258565b61028060085434101561128c565b60095461028f813411156112cf565b601054906102aa6102a03484611375565b6007541015611312565b336000908152601460205260409020906102d460028301916102cd348454611375565b11156112cf565b6102f36102ee6102e660055434611a98565b943490611375565b601055565b61030761030284601154611375565b601155565b610312348254611375565b905560018101610323838254611375565b9055610330828254611375565b905560408051348152602081019290925233917fb55d4ca2fc644ca3f8cdc9c907826e24acd68d2b2d4d73f48b8f2378dbaedf5d9190a2005b90600182811c92168015610399575b602083101461038357565b634e487b7160e01b600052602260045260246000fd5b91607f1691610378565b634e487b7160e01b600052604160045260246000fd5b6040810190811067ffffffffffffffff8211176103d557604052565b6103a3565b90601f8019910116810190811067ffffffffffffffff8211176103d557604052565b6020808252825181830181905290939260005b82811061043157505060409293506000838284010152601f8019910116010190565b81810186015184820160400152850161040f565b346101df5760008060031936011261052757604051908060045461046881610369565b808552916001918083169081156104fd57506001146104a2575b61049e85610492818703826103da565b604051918291826103fc565b0390f35b9250600483527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8284106104e55750505081016020016104928261049e610482565b805460208587018101919091529093019281016104ca565b86955061049e9693506020925061049294915060ff191682840152151560051b8201019293610482565b80fd5b346101df5760003660031901126101df576020600354604051908152f35b346101df5760003660031901126101df57600b54600c5460408051928352602083019190915290f35b346101df5760003660031901126101df576020601154604051908152f35b346101df5760003660031901126101df576105af60026001541415611382565b60026001556105bd336115c1565b60018055005b346101df5760403660031901126101df576105dc6101e4565b60243560018060a01b03600092818492835416916105fb338414611031565b61060a60026001541415611382565b600260015516908161068b575050808080610669944790801560001461067557505b610637811515611c07565b81546106599061064d906001600160a01b031681565b6001600160a01b031690565b5af16106636114a4565b50611c47565b61067260018055565b80f35b9080821015610684575061062c565b905061062c565b600254919250906106a69061064d906001600160a01b031681565b82036107c357505060135460ff1680156107aa575b6106c490611b49565b6002546106d9906001600160a01b031661064d565b6040516370a0823160e01b815230600482015291602083602481855afa80156107a55761073e938591610777575b50600c5442118061076a575b1561075b57905b806107435750905b61072d821515611bbb565b83546001600160a01b0316906116cf565b610669565b908082101561075457505b90610722565b905061074e565b506107646119e1565b9061071a565b5060105460065411610713565b610798915060203d811161079e575b61079081836103da565b81019061195f565b38610707565b503d610786565b61196e565b50600c54421180156106bb5750601054600654116106bb565b6040516370a0823160e01b815230600482015292602084602481865afa9081156107a55761073e948692610823575b508061080b5750915b610806831515611b06565b6116cf565b908082101561081c57505b916107fb565b9050610816565b61083c91925060203d811161079e5761079081836103da565b90386107f2565b346101df5760003660031901126101df576020601254604051908152f35b346101df576000806003193601126105275761088260026001541415611382565b6002600155610894600c5442116113ce565b610669818080806010546108ab6006548210611413565b3382526014602052816040812081600282016108d76102ee825480976108d282151561145f565b611512565b81601154936108ef6103026001830196875490611512565b555555335af16108fd6114a4565b506114d4565b346101df5760003660031901126101df57602061091e6119e1565b604051908152f35b346101df576000806003193601126105275761094c60018060a01b038254163314611031565b610959600c5442116113ce565b61096860105460065411611413565b60025461097d906001600160a01b031661064d565b6040516370a0823160e01b815230600482015290602082602481845afa9081156107a5576106729284926109bf575b506109b8821515611a56565b33906116cf565b6109d891925060203d811161079e5761079081836103da565b90386109ac565b346101df5760008060031936011261052757805481906001600160a01b03811690610a0b338314611031565b6001600160a01b03191682557f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b67ffffffffffffffff81116103d557601f01601f191660200190565b346101df5760203660031901126101df5760043567ffffffffffffffff81116101df57366023820112156101df578060040135610a9681610a3e565b90610aa460405192836103da565b80825236602482850101116101df576020816000926024610acd96018386013783010152611134565b005b346101df5760003660031901126101df576000546040516001600160a01b039091168152602090f35b346101df5760008060031936011261052757610b1e60018060a01b038254163314611031565b60ff6013541615610b8b57610b316119e1565b8015610b535760025461067291903390610806906001600160a01b031661064d565b60405162461bcd60e51b815260206004820152601060248201526f4e6f20756e736f6c6420746f6b656e7360801b6044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f576974686472617720616c6c6f77656420616674657220646973747269627574604482015261195960f21b6064820152608490fd5b346101df5760003660031901126101df576002546040516001600160a01b039091168152602090f35b346101df5760003660031901126101df57606060018060a01b0380600d54169080600e541690600f54169060405192835260208301526040820152f35b346101df5760203660031901126101df576105bd610c5d6101e4565b610c6c60026001541415611382565b60026001556115c1565b60008060031936011261052757610c9260026001541415611382565b6002600155610ca4600c5442116113ce565b610cb4601054600654111561188e565b610ccf610cca610cc660135460ff1690565b1590565b6118d1565b47610cdb811515611913565b610ce7600a5482611a98565b600254909190610cff906001600160a01b031661064d565b6040516370a0823160e01b815230600482015290916020918281602481875afa9081156107a557610d3b9186918891610f3d575b50101561197a565b600d546001600160a01b0394908590610d5590821661064d565b60405163095ea7b360e01b815291166001600160a01b038116600483015260248201839052909490919084908690818a816044810103925af19384156107a557610e1495606095610f0f575b5050600254610db8906001600160a01b031661064d565b92610dc242611361565b60405163f305d71960e01b81526001600160a01b0390951660048601526024850192909252600060448501819052606485015261dead608485015260a4840191909152919384928391829060c4820190565b03925af19182156107a5578384928594610eb6575b506002547f9511e219182d34f8b0080e8f348c16b0d3630ea7e2014b20f1ef78fdf3e0520b929190610ea190610e67906001600160a01b031661064d565b600f549096906001600160a01b03169284604051958695169816968460609194939260808201958252602082015261dead60408201520152565b0390a3610669600160ff196013541617601355565b9050610efd9193507f9511e219182d34f8b0080e8f348c16b0d3630ea7e2014b20f1ef78fdf3e0520b925060603d8111610f08575b610ef581836103da565b8101906119c6565b939092909190610e29565b503d610eeb565b81610f2e92903d10610f36575b610f2681836103da565b8101906117db565b503880610da1565b503d610f1c565b610f549150853d871161079e5761079081836103da565b38610d33565b346101df5760203660031901126101df57610f736101e4565b6000546001600160a01b0390610f8c9082163314611031565b811615610f9c57610acd9061107c565b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b346101df5760003660031901126101df57602060ff601354166040519015158152f35b346101df5760003660031901126101df576020601054604051908152f35b1561103857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3565b601f81116110cf575050565b600090600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906020601f850160051c8301941061112a575b601f0160051c01915b82811061111f57505050565b818155600101611113565b909250829061110a565b90815167ffffffffffffffff81116103d55761115a81611155600454610369565b6110c3565b602080601f8311600114611196575081929360009261118b575b50508160011b916000199060031b1c191617600455565b015190503880611174565b90601f198316946111c960046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b90565b926000905b8782106112065750508360019596106111ed575b505050811b01600455565b015160001960f88460031b161c191690553880806111e2565b806001859682949686015181550195019301906111ce565b1561122557565b60405162461bcd60e51b815260206004820152600b60248201526a139bdd081cdd185c9d195960aa1b6044820152606490fd5b1561125f57565b60405162461bcd60e51b8152602060048201526005602482015264115b99195960da1b6044820152606490fd5b1561129357565b60405162461bcd60e51b815260206004820152601460248201527313195cdcc81d1a185b881b5a5b88185b5bdd5b9d60621b6044820152606490fd5b156112d657565b60405162461bcd60e51b8152602060048201526014602482015273135bdc99481d1a185b881b585e08185b5bdd5b9d60621b6044820152606490fd5b1561131957565b60405162461bcd60e51b815260206004820152600a60248201526913dd995c999a5b1b195960b21b6044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b90610168820180921161137057565b61134b565b9190820180921161137057565b1561138957565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b156113d557565b60405162461bcd60e51b8152602060048201526016602482015275125113c81c1bdbdb081a185cc81b9bdd08195b99195960521b6044820152606490fd5b1561141a57565b60405162461bcd60e51b815260206004820152601d60248201527f49444f20706f6f6c20686173207265616368656420736f6674206361700000006044820152606490fd5b1561146657565b60405162461bcd60e51b8152602060048201526016602482015275165bdd481a185d99481b9bc81a5b9d995cdd1b595b9d60521b6044820152606490fd5b3d156114cf573d906114b582610a3e565b916114c360405193846103da565b82523d6000602084013e565b606090565b156114db57565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b9190820391821161137057565b1561152657565b60405162461bcd60e51b815260206004820152602160248201527f49444f20706f6f6c20686173206e6f74206265656e20646973747269627574656044820152601960fa1b6064820152608490fd5b1561157c57565b60405162461bcd60e51b815260206004820152601b60248201527f596f7520646f206e6f742068617665206465627420746f6b656e7300000000006044820152606490fd5b6115ce600c5442116113ce565b6010546006541161168a576115ed6115e860135460ff1690565b61151f565b6001600160a01b03811660009081526014602052604081208054927f6352c5382c4a4578e712449ca65e83cdb392d045dfcf1cad9615189db2da244b9261168592611639861515611575565b5561164e61164985601254611375565b601255565b60025461166b9085908390610806906001600160a01b031661064d565b6040519384526001600160a01b0316929081906020820190565b0390a2565b60405162461bcd60e51b815260206004820152601f60248201527f49444f20706f6f6c20646964206e6f7420726561636820736f667420636170006044820152606490fd5b60405163a9059cbb60e01b60208083019182526001600160a01b0394909416602483015260448083019590955293815291929061170d6064846103da565b60018060a01b03169060405192611723846103b9565b8484527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656485850152823b156117965761176f939260009283809351925af16117696114a4565b90611852565b8051908161177c57505050565b826117949361178f9383010191016117db565b6117f3565b565b60405162461bcd60e51b815260048101869052601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b908160209103126101df575180151581036101df5790565b156117fa57565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b9091901561185e575090565b81511561186e5750805190602001fd5b60405162461bcd60e51b815290819061188a90600483016103fc565b0390fd5b1561189557565b60405162461bcd60e51b815260206004820152601460248201527314dbd99d0818d85c081b9bdd081c995858da195960621b6044820152606490fd5b156118d857565b60405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e48191a5cdd1c9a589d5d1959606a1b6044820152606490fd5b1561191a57565b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2045544820746f20637265617465206c69717569646974790000000000006044820152606490fd5b908160209103126101df575190565b6040513d6000823e3d90fd5b1561198157565b60405162461bcd60e51b815260206004820152601a60248201527f496e73756666696369656e7420746f6b656e2062616c616e63650000000000006044820152606490fd5b908160609103126101df578051916040602083015192015190565b6002546040516370a0823160e01b815230600482015290602090829060249082906001600160a01b03165afa9081156107a557600091611a38575b5060125481018091116113705760115481039081116113705790565b611a50915060203d811161079e5761079081836103da565b38611a1c565b15611a5d57565b60405162461bcd60e51b8152602060048201526013602482015272139bc81d1bdad95b9cc81d1bc81c99599d5b99606a1b6044820152606490fd5b8115611ac15704600354604d811161137057600a0a908181029181830414901517156113705790565b60405162461bcd60e51b815260206004820152601a60248201527f546f6b656e2070726963652063616e6e6f74206265207a65726f0000000000006044820152606490fd5b15611b0d57565b60405162461bcd60e51b81526020600482015260146024820152732737903a37b5b2b739903a37903932b1b7bb32b960611b6044820152606490fd5b15611b5057565b60405162461bcd60e51b815260206004820152603f60248201527f43616e206f6e6c79207265636f7665722072657761726420746f6b656e73206160448201527f6674657220646973747269627574696f6e206f72206661696c65642049444f006064820152608490fd5b15611bc257565b60405162461bcd60e51b815260206004820152601e60248201527f4e6f20746f6b656e7320617661696c61626c6520746f207265636f76657200006044820152606490fd5b15611c0e57565b60405162461bcd60e51b815260206004820152601160248201527027379022aa24103a37903932b1b7bb32b960791b6044820152606490fd5b15611c4e57565b60405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606490fdfea164736f6c6343000812000aa164736f6c6343000812000a000000000000000000000000abccefb00528c9c792ac7c46997f0f6ee5dcdddd0000000000000000000000000000000000000000000422ca8b0a00a4250000000000000000000000000000000000000000000000000000000000000000000064

Deployed ByteCode

0x608060405260043610156200001d575b36156200001b57600080fd5b005b60003560e01c806303807ee5146200013c5780630fa3b5cc146200013657806315cce2241462000130578063378efa37146200012a578063586097541462000124578063647846a5146200011e57806369e1540414620001185780636a1860e214620001125780636b392680146200010c5780637104c9fd1462000106578063715018a614620001005780638da5cb5b14620000fa5780638dc1299114620000f457806390d49b9d14620000ee578063f25f4b5614620000e85763f2fde38b036200000f5762000aa4565b62000a79565b620009f6565b62000930565b62000905565b620008a2565b62000844565b620007e7565b62000715565b620006f5565b620006ca565b62000552565b62000532565b62000401565b62000322565b62000153565b60009103126200014e57565b600080fd5b346200014e5760003660031901126200014e576020600454604051908152f35b6001600160a01b038116036200014e57565b634e487b7160e01b600052604160045260246000fd5b60c0810190811067ffffffffffffffff821117620001b857604052565b62000185565b67ffffffffffffffff8111620001b857604052565b6040810190811067ffffffffffffffff821117620001b857604052565b90601f8019910116810190811067ffffffffffffffff821117620001b857604052565b60409060e31901126200014e57604051906040820182811067ffffffffffffffff821117620001b85760405260e4358252610104356020830152565b6060906101231901126200014e57604051906060820182811067ffffffffffffffff821117620001b85760405281610124356200028c8162000173565b8152610144356200029d8162000173565b602082015260406101643591620002b48362000173565b0152565b67ffffffffffffffff8111620001b857601f01601f191660200190565b81601f820112156200014e57803590620002ef82620002b8565b92620002ff6040519485620001f0565b828452602083830101116200014e57816000926020809301838601378301015290565b346200014e576101e03660031901126200014e57600435620003448162000173565b60c03660231901126200014e576040516200035f816200019b565b602435815260443560208201526064356040820152608435606082015260a435608082015260c43560a0820152620003973662000213565b90620003a3366200024f565b92610184359267ffffffffffffffff84116200014e57620003fd94620003d2620003e3953690600401620002d5565b916101c435946101a4359462000e5d565b6040516001600160a01b0390911681529081906020820190565b0390f35b346200014e5760203660031901126200014e57600435620004228162000173565b6000546001600160a01b03906200043d908216331462000b47565b604051906200044c82620001d3565b601a82527f4e65772061646472657373206973206e6f74206120746f6b656e00000000000060208301528216908115620004fd57823b63ffffffff1615620004da57600180546001600160a01b0319166001600160a01b0384161790557f9e892f555b0a5cac6c8cc33c82ebb9308207bd16dfdca9d0289b96d7e4186c8a620004d584620003e3565b0390a1005b604051630b0f5aa160e11b8152908190620004f9906004830162001199565b0390fd5b604051630b0f5aa160e11b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606490fd5b346200014e5760003660031901126200014e576020600554604051908152f35b346200014e5760403660031901126200014e57600435620005738162000173565b600080549091602435916001600160a01b03908116916200059633841462000b47565b1690816200061657505047908015600014620005fd57505b8181620005ba57505080f35b808080620005fa94620005e7620005db620005db845460018060a01b031690565b6001600160a01b031690565b5af1620005f362001164565b5062001351565b80f35b90808210156200060e5750620005ae565b9050620005ae565b6040516370a0823160e01b81523060048201529192909190602082602481875afa918215620006c45785926200068d575b5080620006725750905b816200065e575b50505080f35b620006699262001394565b38808062000658565b90808210156200068557505b9062000651565b90506200067e565b620006b491925060203d8111620006bc575b620006ab8183620001f0565b81019062001341565b903862000647565b503d6200069f565b62000cd0565b346200014e5760003660031901126200014e576001546040516001600160a01b039091168152602090f35b346200014e5760003660031901126200014e576020600354604051908152f35b346200014e57600080600319360112620007e45760405180916006549081835260208093018092600683527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90835b818110620007c657505050846200077d910385620001f0565b60405193838594850191818652518092526040850193925b828110620007a557505050500390f35b83516001600160a01b03168552869550938101939281019260010162000795565b82546001600160a01b03168452928601926001928301920162000764565b80fd5b346200014e5760203660031901126200014e577fbb128cd9921d003aff00ed910fe24b1655b2bf1f4a2090cc3523f61bdc17231660206004356200083760018060a01b0360005416331462000b47565b80600355604051908152a1005b346200014e5760203660031901126200014e576004356006548110156200014e5760066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01546040516001600160a01b039091168152602090f35b346200014e57600080600319360112620007e457805481906001600160a01b03811690620008d233831462000b47565b6001600160a01b03191682557f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b346200014e5760003660031901126200014e576000546040516001600160a01b039091168152602090f35b346200014e5760403660031901126200014e576004356024356200096060018060a01b0360005416331462000b47565b808211620009a257816040917fb62d69c6ddf4f4bd443dca17ea7405d8018efb872e82e77bb8ef13b5be2f2e9c936004558060055582519182526020820152a1005b60405162461bcd60e51b815260206004820152602660248201527f4275726e2070657263656e74206d757374206265206c657373207468616e206460448201526534bb34b232b960d11b6064820152608490fd5b346200014e5760203660031901126200014e577f29acee77dafcfa0143d74a7ea236018f3a6e1fa71e27fc59bbfbc6b8ca8edccd602060043562000a3a8162000173565b6000546001600160a01b03919062000a56908316331462000b47565b16806bffffffffffffffffffffffff60a01b6002541617600255604051908152a1005b346200014e5760003660031901126200014e576002546040516001600160a01b039091168152602090f35b346200014e5760203660031901126200014e5760043562000ac58162000173565b6000546001600160a01b039062000ae0908216331462000b47565b81161562000af3576200001b9062000b93565b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b1562000b4f57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3565b919082519283825260005b84811062000c07575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520162000be5565b9262000c8b9062000c7862000cba9462000ccd98979460018060a01b03168752602087019060a0809180518452602081015160208501526040810151604085015260608101516060850152608081015160808501520151910152565b805160e086015260200151610100850152565b80516001600160a01b039081166101208501526020820151811661014085015260409091015116610160830152565b6101a09081610180820152019062000bda565b90565b6040513d6000823e3d90fd5b919262000d3b62000ccd959462000d298562000d6a9560a0809180518452602081015160208501526040810151604085015260608101516060850152608081015160808501520151910152565b805160c08601526020015160e0850152565b80516001600160a01b039081166101008501526020820151811661012085015260409091015116610140830152565b6101809081610160820152019062000bda565b634e487b7160e01b600052601160045260246000fd5b9190820180921162000da157565b62000d7d565b60065468010000000000000000811015620001b857600181018060065581101562000e125760066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0180546001600160a01b0319166001600160a01b03909216919091179055565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0390911681526080602082018190529294939260609262000e539183019062000bda565b9460408201520152565b9591939492909560405161228580820182811067ffffffffffffffff821117620001b8578885898c8762000e99958897620013da893962000c1c565b03906000f0968715620006c45786957f6280933c1d06e26a4d5de0f4ae608636e94c4baf579e360d13e16c7b27302fc99162000eec60018060a01b03809b169a8b9516998a966040519485948562000cdc565b0390a362000efb818362000d93565b91853b156200014e5760405163f2fde38b60e01b815233600482015292600084602481838b5af1908115620006c4577fbb1e34963a7cf74028f70419838711c854e9716294c07397f076ff3ec10e04bb9462000f619262000f8d575b5087338862000fab565b62000f6c8662000da7565b62000f806040519283923396898562000e28565b0390a362000ccd620011f0565b8062000f9d62000fa492620001be565b8062000142565b3862000f57565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815260a081019181831067ffffffffffffffff841117620001b857620010079260405262001083565b565b908160209103126200014e575180151581036200014e5790565b156200102b57565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b6040516001600160a01b0391909116916200109e82620001d3565b6020928383527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656484840152803b156200111f5760008281928287620010f59796519301915af1620010ee62001164565b90620011ac565b805190816200110357505050565b8262001007936200111993830101910162001009565b62001023565b60405162461bcd60e51b815260048101859052601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b3d1562001194573d906200117882620002b8565b91620011886040519384620001f0565b82523d6000602084013e565b606090565b90602062000ccd92818152019062000bda565b90919015620011b9575090565b815115620011ca5750805190602001fd5b60405162461bcd60e51b815260206004820152908190620004f990602483019062000bda565b60035480620011fc5750565b60045415620012e1575060035462001231620012296200121f600454846200130c565b6005549062001320565b8092620012fe565b80620012a8575b508062001243575b50565b6001546200125a906001600160a01b0316620005db565b803b156200014e5760405163079cc67960e41b815233600482015260248101929092526000908290604490829084905af18015620006c4571562001240578062000f9d6200100792620001be565b600154620012da9190620012c5906001600160a01b0316620005db565b6002546001600160a01b031690339062000fab565b3862001238565b600154620010079190620012c5906001600160a01b0316620005db565b9190820391821162000da157565b8181029291811591840414171562000da157565b81156200132b570490565b634e487b7160e01b600052601260045260246000fd5b908160209103126200014e575190565b156200135957565b60405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606490fd5b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526200100791620013d3606483620001f0565b6200108356fe608060405234620005b05762002285803803809162000020826080620005b5565b6080396101a08112620005b0576080516001600160a01b0381168103620005b05760c0601f19830112620005b05760405160c081016001600160401b038111828210176200046c57604090815260a08051835260c051602084015260e05183830152610100516060840152610120516080840152610140519083015260df19840112620005b05760408051919082018083116001600160401b03909111176200046c5760408281019052610160518252610180516020830152606061011f19850112620005b057604051926001600160401b0360608501908111908511176200046c5760608401604052620001176101a0620005d9565b8452620001266101c0620005d9565b6020850152620001386101e0620005d9565b6040850152610200516001600160401b038111620005b05760808601609f82011215620005b0576080810151906001600160401b0382116200046c57604051966200018e601f8401601f191660200189620005b5565b82885260800160a08284010111620005b05760005b8281106200059757505060206000918701015260206000543360018060a01b0319821617600055600460405180948193339060018060a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3600180556013805460ff19169055600280546001600160a01b0319166001600160a01b0392909216918217905563313ce56760e01b82525afa9081156200058b5760009162000540575b509060ff60a09216600355805160055560208101516006556040810151600755606081015160085560808101516009550151600a55805160208201511115620004e057602081015142101562000482578051600b55602090810151600c558151600d80546001600160a01b039283166001600160a01b03199182161790915591830151600e8054918316918416919091179055604090920151600f805491909316911617905580516001600160401b0381116200046c57600454600181811c9116801562000461575b60208210146200044b57601f8111620003e1575b50602091601f821160011462000377579181926000926200036b575b50508160011b916000199060031b1c1916176004555b604051611c969081620005ef8239f35b01519050388062000345565b601f19821692600460005260206000209160005b858110620003c857508360019510620003ae575b505050811b016004556200035b565b015160001960f88460031b161c191690553880806200039f565b919260206001819286850151815501940192016200038b565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c8101916020841062000440575b601f0160051c01905b81811062000433575062000329565b6000815560010162000424565b90915081906200041b565b634e487b7160e01b600052602260045260246000fd5b90607f169062000315565b634e487b7160e01b600052604160045260246000fd5b60405162461bcd60e51b815260206004820152603060248201527f46696e6973682074696d657374616d70206d757374206265206d6f726520746860448201526f616e2063757272656e7420626c6f636b60801b6064820152608490fd5b60405162461bcd60e51b815260206004820152603260248201527f53746172742074696d657374616d70206d757374206265206c6573732074686160448201527106e2066696e6973682074696d657374616d760741b6064820152608490fd5b6020813d60201162000582575b816200055c60209383620005b5565b810103126200057e57519060ff821682036200057b575060ff6200024c565b80fd5b5080fd5b3d91506200054d565b6040513d6000823e3d90fd5b80602080928460800101015182828b01015201620001a3565b600080fd5b601f909101601f19168101906001600160401b038211908210176200046c57604052565b51906001600160a01b0382168203620005b05756fe6080604052600436101561001257600080fd5b60003560e01c806312d3675e146101975780631959a002146101925780631b9265b81461018d5780632dcc8c6614610188578063313ce56714610183578063491447a81461017e5780634b1a4c0c146101795780634e71d92d14610174578063586097541461016f578063586360ce1461016a578063590e1ae31461016557806362bea93f14610160578063710075091461015b578063715018a614610156578063747daec5146101515780638da5cb5b1461014c578063c6a0e27d14610147578063d6cd82bc14610142578063d8d2a56d1461013d578063ddeae03314610138578063e086e5ec14610133578063f2fde38b1461012e578063f84b903e146101295763fd46a1711461012457600080fd5b611013565b610ff0565b610f5a565b610c76565b610c41565b610c04565b610bdb565b610af8565b610acf565b610a5a565b6109df565b610926565b610903565b610861565b610843565b6105c3565b61058f565b610571565b610548565b61052a565b610445565b61024b565b6101fa565b346101df5760003660031901126101df5760c060055460065460075460085460095491600a5493604051958652602086015260408501526060840152608083015260a0820152f35b600080fd5b600435906001600160a01b03821682036101df57565b346101df5760203660031901126101df576001600160a01b0361021b6101e4565b16600052601460205260606040600020805490600260018201549101549060405192835260208301526040820152f35b60003660031901126101df57610265600b5442101561121e565b610272600c544210611258565b61028060085434101561128c565b60095461028f813411156112cf565b601054906102aa6102a03484611375565b6007541015611312565b336000908152601460205260409020906102d460028301916102cd348454611375565b11156112cf565b6102f36102ee6102e660055434611a98565b943490611375565b601055565b61030761030284601154611375565b601155565b610312348254611375565b905560018101610323838254611375565b9055610330828254611375565b905560408051348152602081019290925233917fb55d4ca2fc644ca3f8cdc9c907826e24acd68d2b2d4d73f48b8f2378dbaedf5d9190a2005b90600182811c92168015610399575b602083101461038357565b634e487b7160e01b600052602260045260246000fd5b91607f1691610378565b634e487b7160e01b600052604160045260246000fd5b6040810190811067ffffffffffffffff8211176103d557604052565b6103a3565b90601f8019910116810190811067ffffffffffffffff8211176103d557604052565b6020808252825181830181905290939260005b82811061043157505060409293506000838284010152601f8019910116010190565b81810186015184820160400152850161040f565b346101df5760008060031936011261052757604051908060045461046881610369565b808552916001918083169081156104fd57506001146104a2575b61049e85610492818703826103da565b604051918291826103fc565b0390f35b9250600483527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8284106104e55750505081016020016104928261049e610482565b805460208587018101919091529093019281016104ca565b86955061049e9693506020925061049294915060ff191682840152151560051b8201019293610482565b80fd5b346101df5760003660031901126101df576020600354604051908152f35b346101df5760003660031901126101df57600b54600c5460408051928352602083019190915290f35b346101df5760003660031901126101df576020601154604051908152f35b346101df5760003660031901126101df576105af60026001541415611382565b60026001556105bd336115c1565b60018055005b346101df5760403660031901126101df576105dc6101e4565b60243560018060a01b03600092818492835416916105fb338414611031565b61060a60026001541415611382565b600260015516908161068b575050808080610669944790801560001461067557505b610637811515611c07565b81546106599061064d906001600160a01b031681565b6001600160a01b031690565b5af16106636114a4565b50611c47565b61067260018055565b80f35b9080821015610684575061062c565b905061062c565b600254919250906106a69061064d906001600160a01b031681565b82036107c357505060135460ff1680156107aa575b6106c490611b49565b6002546106d9906001600160a01b031661064d565b6040516370a0823160e01b815230600482015291602083602481855afa80156107a55761073e938591610777575b50600c5442118061076a575b1561075b57905b806107435750905b61072d821515611bbb565b83546001600160a01b0316906116cf565b610669565b908082101561075457505b90610722565b905061074e565b506107646119e1565b9061071a565b5060105460065411610713565b610798915060203d811161079e575b61079081836103da565b81019061195f565b38610707565b503d610786565b61196e565b50600c54421180156106bb5750601054600654116106bb565b6040516370a0823160e01b815230600482015292602084602481865afa9081156107a55761073e948692610823575b508061080b5750915b610806831515611b06565b6116cf565b908082101561081c57505b916107fb565b9050610816565b61083c91925060203d811161079e5761079081836103da565b90386107f2565b346101df5760003660031901126101df576020601254604051908152f35b346101df576000806003193601126105275761088260026001541415611382565b6002600155610894600c5442116113ce565b610669818080806010546108ab6006548210611413565b3382526014602052816040812081600282016108d76102ee825480976108d282151561145f565b611512565b81601154936108ef6103026001830196875490611512565b555555335af16108fd6114a4565b506114d4565b346101df5760003660031901126101df57602061091e6119e1565b604051908152f35b346101df576000806003193601126105275761094c60018060a01b038254163314611031565b610959600c5442116113ce565b61096860105460065411611413565b60025461097d906001600160a01b031661064d565b6040516370a0823160e01b815230600482015290602082602481845afa9081156107a5576106729284926109bf575b506109b8821515611a56565b33906116cf565b6109d891925060203d811161079e5761079081836103da565b90386109ac565b346101df5760008060031936011261052757805481906001600160a01b03811690610a0b338314611031565b6001600160a01b03191682557f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b67ffffffffffffffff81116103d557601f01601f191660200190565b346101df5760203660031901126101df5760043567ffffffffffffffff81116101df57366023820112156101df578060040135610a9681610a3e565b90610aa460405192836103da565b80825236602482850101116101df576020816000926024610acd96018386013783010152611134565b005b346101df5760003660031901126101df576000546040516001600160a01b039091168152602090f35b346101df5760008060031936011261052757610b1e60018060a01b038254163314611031565b60ff6013541615610b8b57610b316119e1565b8015610b535760025461067291903390610806906001600160a01b031661064d565b60405162461bcd60e51b815260206004820152601060248201526f4e6f20756e736f6c6420746f6b656e7360801b6044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f576974686472617720616c6c6f77656420616674657220646973747269627574604482015261195960f21b6064820152608490fd5b346101df5760003660031901126101df576002546040516001600160a01b039091168152602090f35b346101df5760003660031901126101df57606060018060a01b0380600d54169080600e541690600f54169060405192835260208301526040820152f35b346101df5760203660031901126101df576105bd610c5d6101e4565b610c6c60026001541415611382565b60026001556115c1565b60008060031936011261052757610c9260026001541415611382565b6002600155610ca4600c5442116113ce565b610cb4601054600654111561188e565b610ccf610cca610cc660135460ff1690565b1590565b6118d1565b47610cdb811515611913565b610ce7600a5482611a98565b600254909190610cff906001600160a01b031661064d565b6040516370a0823160e01b815230600482015290916020918281602481875afa9081156107a557610d3b9186918891610f3d575b50101561197a565b600d546001600160a01b0394908590610d5590821661064d565b60405163095ea7b360e01b815291166001600160a01b038116600483015260248201839052909490919084908690818a816044810103925af19384156107a557610e1495606095610f0f575b5050600254610db8906001600160a01b031661064d565b92610dc242611361565b60405163f305d71960e01b81526001600160a01b0390951660048601526024850192909252600060448501819052606485015261dead608485015260a4840191909152919384928391829060c4820190565b03925af19182156107a5578384928594610eb6575b506002547f9511e219182d34f8b0080e8f348c16b0d3630ea7e2014b20f1ef78fdf3e0520b929190610ea190610e67906001600160a01b031661064d565b600f549096906001600160a01b03169284604051958695169816968460609194939260808201958252602082015261dead60408201520152565b0390a3610669600160ff196013541617601355565b9050610efd9193507f9511e219182d34f8b0080e8f348c16b0d3630ea7e2014b20f1ef78fdf3e0520b925060603d8111610f08575b610ef581836103da565b8101906119c6565b939092909190610e29565b503d610eeb565b81610f2e92903d10610f36575b610f2681836103da565b8101906117db565b503880610da1565b503d610f1c565b610f549150853d871161079e5761079081836103da565b38610d33565b346101df5760203660031901126101df57610f736101e4565b6000546001600160a01b0390610f8c9082163314611031565b811615610f9c57610acd9061107c565b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b346101df5760003660031901126101df57602060ff601354166040519015158152f35b346101df5760003660031901126101df576020601054604051908152f35b1561103857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3565b601f81116110cf575050565b600090600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906020601f850160051c8301941061112a575b601f0160051c01915b82811061111f57505050565b818155600101611113565b909250829061110a565b90815167ffffffffffffffff81116103d55761115a81611155600454610369565b6110c3565b602080601f8311600114611196575081929360009261118b575b50508160011b916000199060031b1c191617600455565b015190503880611174565b90601f198316946111c960046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b90565b926000905b8782106112065750508360019596106111ed575b505050811b01600455565b015160001960f88460031b161c191690553880806111e2565b806001859682949686015181550195019301906111ce565b1561122557565b60405162461bcd60e51b815260206004820152600b60248201526a139bdd081cdd185c9d195960aa1b6044820152606490fd5b1561125f57565b60405162461bcd60e51b8152602060048201526005602482015264115b99195960da1b6044820152606490fd5b1561129357565b60405162461bcd60e51b815260206004820152601460248201527313195cdcc81d1a185b881b5a5b88185b5bdd5b9d60621b6044820152606490fd5b156112d657565b60405162461bcd60e51b8152602060048201526014602482015273135bdc99481d1a185b881b585e08185b5bdd5b9d60621b6044820152606490fd5b1561131957565b60405162461bcd60e51b815260206004820152600a60248201526913dd995c999a5b1b195960b21b6044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b90610168820180921161137057565b61134b565b9190820180921161137057565b1561138957565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b156113d557565b60405162461bcd60e51b8152602060048201526016602482015275125113c81c1bdbdb081a185cc81b9bdd08195b99195960521b6044820152606490fd5b1561141a57565b60405162461bcd60e51b815260206004820152601d60248201527f49444f20706f6f6c20686173207265616368656420736f6674206361700000006044820152606490fd5b1561146657565b60405162461bcd60e51b8152602060048201526016602482015275165bdd481a185d99481b9bc81a5b9d995cdd1b595b9d60521b6044820152606490fd5b3d156114cf573d906114b582610a3e565b916114c360405193846103da565b82523d6000602084013e565b606090565b156114db57565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b9190820391821161137057565b1561152657565b60405162461bcd60e51b815260206004820152602160248201527f49444f20706f6f6c20686173206e6f74206265656e20646973747269627574656044820152601960fa1b6064820152608490fd5b1561157c57565b60405162461bcd60e51b815260206004820152601b60248201527f596f7520646f206e6f742068617665206465627420746f6b656e7300000000006044820152606490fd5b6115ce600c5442116113ce565b6010546006541161168a576115ed6115e860135460ff1690565b61151f565b6001600160a01b03811660009081526014602052604081208054927f6352c5382c4a4578e712449ca65e83cdb392d045dfcf1cad9615189db2da244b9261168592611639861515611575565b5561164e61164985601254611375565b601255565b60025461166b9085908390610806906001600160a01b031661064d565b6040519384526001600160a01b0316929081906020820190565b0390a2565b60405162461bcd60e51b815260206004820152601f60248201527f49444f20706f6f6c20646964206e6f7420726561636820736f667420636170006044820152606490fd5b60405163a9059cbb60e01b60208083019182526001600160a01b0394909416602483015260448083019590955293815291929061170d6064846103da565b60018060a01b03169060405192611723846103b9565b8484527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656485850152823b156117965761176f939260009283809351925af16117696114a4565b90611852565b8051908161177c57505050565b826117949361178f9383010191016117db565b6117f3565b565b60405162461bcd60e51b815260048101869052601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b908160209103126101df575180151581036101df5790565b156117fa57565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b9091901561185e575090565b81511561186e5750805190602001fd5b60405162461bcd60e51b815290819061188a90600483016103fc565b0390fd5b1561189557565b60405162461bcd60e51b815260206004820152601460248201527314dbd99d0818d85c081b9bdd081c995858da195960621b6044820152606490fd5b156118d857565b60405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e48191a5cdd1c9a589d5d1959606a1b6044820152606490fd5b1561191a57565b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2045544820746f20637265617465206c69717569646974790000000000006044820152606490fd5b908160209103126101df575190565b6040513d6000823e3d90fd5b1561198157565b60405162461bcd60e51b815260206004820152601a60248201527f496e73756666696369656e7420746f6b656e2062616c616e63650000000000006044820152606490fd5b908160609103126101df578051916040602083015192015190565b6002546040516370a0823160e01b815230600482015290602090829060249082906001600160a01b03165afa9081156107a557600091611a38575b5060125481018091116113705760115481039081116113705790565b611a50915060203d811161079e5761079081836103da565b38611a1c565b15611a5d57565b60405162461bcd60e51b8152602060048201526013602482015272139bc81d1bdad95b9cc81d1bc81c99599d5b99606a1b6044820152606490fd5b8115611ac15704600354604d811161137057600a0a908181029181830414901517156113705790565b60405162461bcd60e51b815260206004820152601a60248201527f546f6b656e2070726963652063616e6e6f74206265207a65726f0000000000006044820152606490fd5b15611b0d57565b60405162461bcd60e51b81526020600482015260146024820152732737903a37b5b2b739903a37903932b1b7bb32b960611b6044820152606490fd5b15611b5057565b60405162461bcd60e51b815260206004820152603f60248201527f43616e206f6e6c79207265636f7665722072657761726420746f6b656e73206160448201527f6674657220646973747269627574696f6e206f72206661696c65642049444f006064820152608490fd5b15611bc257565b60405162461bcd60e51b815260206004820152601e60248201527f4e6f20746f6b656e7320617661696c61626c6520746f207265636f76657200006044820152606490fd5b15611c0e57565b60405162461bcd60e51b815260206004820152601160248201527027379022aa24103a37903932b1b7bb32b960791b6044820152606490fd5b15611c4e57565b60405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606490fdfea164736f6c6343000812000aa164736f6c6343000812000a