ETH Price: $3,455.30 (+1.67%)

Token

WHO333 (WHO)
 

Overview

Max Total Supply

98,979.256628286697480865 WHO

Holders

362

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Filtered by Token Holder
dincoco.eth
Balance
100 WHO

Value
$0.00
0x60e483cdcf8ca76cb83594675cad74fe3d6f97ec
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
WHO333

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 24 : WHO333.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {ERC333} from "./ERC333/ERC333.sol";
import {FullMath} from "./utils/FullMath.sol";

contract WHO333 is ERC333 {
    using Strings for uint256;

    string private constant __NAME = "WHO333";
    string private constant __SYM = "WHO";
    uint256 private constant __MINT_SUPPLY = 1000;
    uint24 private constant __TAX_PERCENT = 80000;
    uint8 private constant __DECIMALS = 18;
    uint8 private constant __RATIO = 100;

    address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    constructor(
        address initialOwner_,
        address initialMintRecipient_
    )
        ERC333(
            initialOwner_,
            initialMintRecipient_,
            __MINT_SUPPLY,
            __TAX_PERCENT,
            __NAME,
            __SYM,
            __DECIMALS,
            __RATIO
        )
    {
        baseURI = "https://who333.wtf/assets/";
    }

    function setERC721TransferExempt(
        address target_,
        bool state_
    ) external onlyOwner {
        _setERC721TransferExempt(target_, state_);
    }

    function withdrawAll() external onlyOwner {
        // Call balanceOf
        // 0x70a08231: keccak256(balanceOf(address))
        (bool success0, bytes memory data0) = WETH.staticcall(
            abi.encodeWithSelector(0x70a08231, address(this))
        );
        if (!success0) {
            return;
        }
        // Decode `uint256` from returned data
        uint256 totalWETHAmount = abi.decode(data0, (uint256));

        // Call WETH transfer
        // 0xa9059cbb: keccak256(transfer(address,uint256))
        (bool success, ) = WETH.call(
            abi.encodeWithSelector(0xa9059cbb, msg.sender, totalWETHAmount)
        );
    }

    function setTickThreshold(int24 tickThreshold_) external onlyOwner {
        tickThreshold = tickThreshold_;
    }

    function initialize() external payable override onlyOwner {
        address positionManagerAddress = 0xC36442b4a4522E871399CD717aBDD847Ab11FE88;
        address swapRouterAddress = 0xE592427A0AEce92De3Edee1F18E0157C05861564;

        if (msg.value > 0) {
            _depositETH(msg.value);
        }

        uint160 sqrtPriceX96 = (address(this) < WETH)
            ? 1372272028650297984479657984 // 0.0003
            : 4574240095500993129133247561728; // 3333.333333333333

        uint256 quoteTokenAmount = _getWETHAtSqrtPriceX96(sqrtPriceX96);
        // require(quoteTokenAmount > 14e17, "quoteTokenAmount");

        uint256 wethAmount = _balanceOfWETH();
        require(wethAmount >= quoteTokenAmount, "weth amount is too low");

        // initialize liquidity
        _initialize(
            sqrtPriceX96,
            3000,
            WETH,
            quoteTokenAmount,
            60,
            positionManagerAddress,
            swapRouterAddress
        );

        // initialize market limit for control
        _registerAll();
    }

    function tokenURI(uint256 id) public view override returns (string memory) {
        uint8 seed = uint8(bytes1(keccak256(abi.encodePacked(id))));
        string memory image;
        string memory color;

        if (seed <= 64) {
            image = "0.png";
            color = "Red";
        } else if (seed <= 128) {
            image = "1.png";
            color = "Blue";
        } else if (seed <= 192) {
            image = "2.png";
            color = "Green";
        } else {
            image = "3.png";
            color = "Purple";
        }

        return
            string(
                abi.encodePacked(
                    '{"name": "WHO333 NFT#',
                    Strings.toString(id),
                    '","description":"A collection of ',
                    Strings.toString(mintSupply),
                    " pots of liquidity that tokenizes decentralized reserve currency idea for the IQ50, #ERC333.",
                    '","external_url":"https://who333.wtf/","image":"',
                    baseURI,
                    image,
                    '","attributes":[{"trait_type":"Color","value":"',
                    color,
                    '"}]}'
                )
            );
    }

    function _balanceOfWETH() internal returns (uint256 amount) {
        // Call balanceOf
        // 0x70a08231: keccak256(balanceOf(address))
        (bool success, bytes memory data) = WETH.staticcall(
            abi.encodeWithSelector(0x70a08231, address(this))
        );
        if (success) {
            // Decode `uint256` from returned data
            amount = abi.decode(data, (uint256));
        }
    }

    function _depositETH(uint256 amount) internal returns (bool) {
        // Deposit the eth
        // Call deposit
        // 0xd0e30db0: keccak256(deposit())
        (bool success, ) = WETH.call{value: amount}(
            abi.encodeWithSelector(0xd0e30db0)
        );
        return success;
    }

    function _getWETHAtSqrtPriceX96(
        uint160 sqrtPriceX96
    ) private view returns (uint256 quoteAmount) {
        // Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself
        uint256 thisAmount = balanceOf[address(this)];
        if (sqrtPriceX96 <= type(uint128).max) {
            uint256 ratioX192 = uint256(sqrtPriceX96) * sqrtPriceX96;
            quoteAmount = address(this) < WETH
                ? FullMath.mulDiv(ratioX192, thisAmount, 1 << 192)
                : FullMath.mulDiv(1 << 192, thisAmount, ratioX192);
        } else {
            uint256 ratioX128 = FullMath.mulDiv(
                sqrtPriceX96,
                sqrtPriceX96,
                1 << 64
            );
            quoteAmount = address(this) < WETH
                ? FullMath.mulDiv(ratioX128, thisAmount, 1 << 128)
                : FullMath.mulDiv(1 << 128, thisAmount, ratioX128);
        }
    }

    receive() external payable {
        _depositETH(msg.value);
    }
}

File 2 of 24 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. 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;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 3 of 24 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";

File 4 of 24 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Receiver.sol)

pragma solidity ^0.8.20;

import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol";

File 5 of 24 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.20;

import {IERC721} from "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

File 6 of 24 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 7 of 24 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.20;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be
     * reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 8 of 24 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 9 of 24 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 10 of 24 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    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 subtraction of two unsigned integers, with an overflow flag.
     */
    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.
     */
    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.
     */
    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.
     */
    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 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 towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

File 11 of 24 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

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

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

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 12 of 24 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 13 of 24 : ERC333.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {ERC404} from "../ERC404/ERC404.sol";
import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";

import {PoolAddress} from "../utils/PoolAddress.sol";
import {TickMath} from "../utils/TickMath.sol";
import {PoolData} from "../structs/PoolData.sol";
import {MintParams, IncreaseLiquidityParams, DecreaseLiquidityParams, CollectParams} from "../structs/PositionParams.sol";
import {ExactInputSingleParams} from "../structs/RouterParams.sol";

abstract contract ERC333 is Ownable, ERC404 {
    event Initialize(PoolData poolData);
    event ReceiveTax(uint256 value);
    event ERC20Burn(uint256 value);
    event RefundETH(address sender, uint256 value);

    using Strings for uint256;

    mapping(address => bool) public operators;
    bool public marketLimit = false;

    string constant _JSON_FILE = ".json";

    // default settings
    uint256 public mintSupply = 10000; // max NFT count
    uint24 public taxPercent = 80000;
    address public initialMintRecipient; // the first token owner

    PoolData public currentPoolData;

    /// @dev for the tick bar of ERC333
    int24 public tickThreshold;
    int24 public currentTick;
    uint256 public mintTimestamp;

    /// @dev Total tax in ERC-20 token representation
    uint256 public totalTax;

    address public positionManagerAddress;
    address public swapRouterAddress;

    /// @dev for compute arithmetic mean tick by observation
    uint32 constant TWAP_INTERVAL = 30 minutes;

    event BaseUriUpdate(string uri);

    string public baseURI;

    constructor(
        address initialOwner_,
        address initialMintRecipient_,
        uint256 mintSupply_,
        uint24 taxPercent_,
        string memory name_,
        string memory sym_,
        uint8 decimals_,
        uint8 ratio_
    ) ERC404(name_, sym_, decimals_, ratio_) Ownable(initialOwner_) {
        // init settings
        mintSupply = mintSupply_;
        taxPercent = taxPercent_;
        initialMintRecipient = initialMintRecipient_;

        // Do not mint the ERC721s to the initial owner, as it's a waste of gas.
        _setERC721TransferExempt(initialMintRecipient_, true);
        _mintERC20(initialMintRecipient_, mintSupply * units);
    }

    // ======================================================================================================
    //
    // ERC333 overrides
    //
    // ======================================================================================================

    function initialized() public view returns (bool) {
        return currentPoolData.poolAddress != address(0);
    }

    function initialize() external payable virtual;

    function _initialize(
        uint160 sqrtPriceX96,
        uint24 fee,
        address quoteToken,
        uint256 quoteTokenAmount,
        uint16 observationCardinalityNext,
        address positionManagerAddress_,
        address swapRouterAddress_
    ) internal virtual onlyOwner {
        require(!initialized(), "already initialized");
        positionManagerAddress = positionManagerAddress_;
        swapRouterAddress = swapRouterAddress_;

        currentPoolData.quoteToken = quoteToken;
        currentPoolData.fee = fee;
        currentPoolData.sqrtPriceX96 = sqrtPriceX96;

        (address token0, address token1) = (address(this), quoteToken);
        (uint256 amount0, uint256 amount1) = (
            balanceOf[address(this)],
            quoteTokenAmount
        );
        if (token0 > token1) {
            (token0, token1) = (token1, token0);
            (amount0, amount1) = (amount1, amount0);
        }
        _approveUniswap(token0, type(uint256).max);
        _approveUniswap(token1, type(uint256).max);

        // step1 create pool
        int24 tickSpacing;
        (
            currentPoolData.poolAddress,
            currentTick,
            tickSpacing
        ) = _initializePool(token0, token1, fee, sqrtPriceX96);
        require(
            currentPoolData.poolAddress != address(0) && tickSpacing != 0,
            "initialize pool failed"
        );
        tickThreshold = currentTick;

        if (_thisIsToken0()) {
            currentPoolData.tickLower =
                (tickThreshold / tickSpacing) *
                tickSpacing;
            if (tickThreshold < 0) {
                currentPoolData.tickLower -= tickSpacing;
            }
            // currentPoolData.tickLower =
            //     (TickMath.MIN_TICK / tickSpacing) *
            //     tickSpacing;
            currentPoolData.tickUpper =
                (TickMath.MAX_TICK / tickSpacing) *
                tickSpacing;
        } else {
            currentPoolData.tickUpper =
                (tickThreshold / tickSpacing) *
                tickSpacing;
            if (tickThreshold > 0) {
                currentPoolData.tickUpper += tickSpacing;
            }
            currentPoolData.tickLower =
                (TickMath.MIN_TICK / tickSpacing) *
                tickSpacing;
        }

        // step2 increase observation cardinality
        if (observationCardinalityNext > 0) {
            bool success = _initializeObservations(
                currentPoolData.poolAddress,
                observationCardinalityNext
            );
            require(success, "initialize observations failed");
        }

        // step3 create liquidity
        (
            currentPoolData.positionId,
            currentPoolData.liquidity,
            ,

        ) = _initializeLiquidity(
            token0,
            token1,
            fee,
            amount0,
            amount1,
            currentPoolData.tickLower,
            currentPoolData.tickUpper,
            address(this)
        );
        require(currentPoolData.positionId != 0, "initialize liquidity failed");
        mintTimestamp = block.timestamp;

        emit Initialize(currentPoolData);
    }

    function _registerAll() internal virtual {
        register(0xa7FD99748cE527eAdC0bDAc60cba8a4eF4090f7c, true);
        register(0x82C0fDFA607d9aFbe82Db5cBD103D1a4D5a43B77, true);
        register(0x5B93A825829f4B7B5177c259Edc22b63d6E4e380, true);

        register(positionManagerAddress, true);
        register(swapRouterAddress, true);
        register(currentPoolData.poolAddress, true);

        setMarketLimit(true);
    }

    /// @notice Explain to an end user what this does
    /// @dev Explain to a developer any extra details
    function _getCurrentTokenTick() internal virtual returns (int24) {
        if (!initialized()) {
            return tickThreshold;
        }

        // Call uniswapV3Pool.slot0
        // 0x3850c7bd: keccak256(slot0())
        (bool success0, bytes memory data0) = currentPoolData
            .poolAddress
            .staticcall(abi.encodeWithSelector(0x3850c7bd));
        if (!success0) {
            return tickThreshold;
        }

        // Decode `Slot` from returned data
        (, int24 tick, uint16 index, uint16 cardinality, , , ) = abi.decode(
            data0,
            (uint160, int24, uint16, uint16, uint16, uint8, bool)
        );

        uint32 delta = TWAP_INTERVAL;
        if (uint32(block.timestamp - mintTimestamp) < delta) {
            return tick;
        }

        uint32[] memory secondsTwapIntervals = new uint32[](2);
        secondsTwapIntervals[0] = delta;
        secondsTwapIntervals[1] = 0;

        // Call uniswapV3Pool.observe
        // 0x883bdbfd: keccak256(observe(uint32[]))
        // require(pools[poolFee] != address(0), "Pool must init");
        (bool success, bytes memory data) = currentPoolData
            .poolAddress
            .staticcall(
                abi.encodeWithSelector(0x883bdbfd, secondsTwapIntervals)
            );

        if (!success) {
            return tick;
        }

        // Decode `tickCumulatives` from returned data
        (int56[] memory tickCumulatives, ) = abi.decode(
            data,
            (int56[], uint160[])
        );

        int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];

        tick = int24(tickCumulativesDelta / int56(uint56(delta)));
        // Always round to negative infinity
        if (
            tickCumulativesDelta < 0 &&
            (tickCumulativesDelta % int56(uint56(delta)) != 0)
        ) tick--;

        return tick;
    }

    function _approveUniswap(
        address token,
        uint256 amount
    ) internal virtual returns (bool) {
        if (amount == 0) {
            return true;
        }
        if (token == address(this)) {
            allowance[address(this)][positionManagerAddress] = amount;
            allowance[address(this)][swapRouterAddress] = amount;
            return true;
        }

        // Approve the position manager
        // Call approve
        // 0x095ea7b3: keccak256(approve(address,uint256))
        (bool success0, ) = token.call(
            abi.encodeWithSelector(0x095ea7b3, positionManagerAddress, amount)
        );

        (bool success1, ) = token.call(
            abi.encodeWithSelector(0x095ea7b3, swapRouterAddress, amount)
        );
        return success0 && success1;
    }

    function _initializePool(
        address token0,
        address token1,
        uint24 fee,
        uint160 sqrtPriceX96
    )
        internal
        virtual
        returns (address poolAddress, int24 tick, int24 tickSpacing)
    {
        // Call position manager createAndInitializePoolIfNecessary
        // 0x13ead562: keccak256(createAndInitializePoolIfNecessary(address,address,uint24,uint160))
        (bool success0, bytes memory data0) = positionManagerAddress.call(
            abi.encodeWithSelector(
                0x13ead562,
                token0,
                token1,
                fee,
                sqrtPriceX96
            )
        );
        // If createAndInitializePoolIfNecessary hasn't reverted
        if (!success0) {
            return (address(0), 0, 0);
        }
        // Decode `address` from returned data
        poolAddress = abi.decode(data0, (address));

        // Call uniswapV3Pool.slot0
        // 0x3850c7bd: keccak256(slot0())
        (bool success1, bytes memory data1) = poolAddress.staticcall(
            abi.encodeWithSelector(0x3850c7bd)
        );
        if (!success1) {
            return (address(0), 0, 0);
        }
        // Decode `Slot` from returned data
        (, tick, , , , , ) = abi.decode(
            data1,
            (uint160, int24, uint16, uint16, uint16, uint8, bool)
        );

        // Call uniswapV3Pool.tickSpacing
        // 0xd0c93a7c: keccak256(tickSpacing())
        (bool success2, bytes memory data2) = poolAddress.staticcall(
            abi.encodeWithSelector(0xd0c93a7c)
        );
        if (!success2) {
            return (address(0), 0, 0);
        }
        tickSpacing = abi.decode(data2, (int24));
    }

    function _initializeObservations(
        address poolAddress,
        uint16 observationCardinalityNext
    ) internal virtual returns (bool) {
        // Call pool increaseObservationCardinalityNext
        // 0x32148f67: keccak256(increaseObservationCardinalityNext(uint16))
        (bool success, ) = poolAddress.call(
            abi.encodeWithSelector(0x32148f67, observationCardinalityNext)
        );
        return success;
    }

    function _initializeLiquidity(
        address token0,
        address token1,
        uint24 fee,
        uint256 amount0,
        uint256 amount1,
        int24 tickLower,
        int24 tickUpper,
        address recipient
    )
        internal
        virtual
        returns (
            uint256 positionId,
            uint128 liquidity,
            uint256 amount0Used,
            uint256 amount1Used
        )
    {
        MintParams memory params = MintParams({
            token0: token0,
            token1: token1,
            fee: fee,
            tickLower: tickLower,
            tickUpper: tickUpper,
            amount0Desired: amount0,
            amount1Desired: amount1,
            amount0Min: 0,
            amount1Min: 0,
            recipient: recipient,
            deadline: block.timestamp
        });
        // Call position manager mint
        // 0x88316456: keccak256(mint((address,address,uint24,int24,int24,uint256,
        // uint256,uint256,uint256,address,uint256)))
        (bool success, bytes memory data) = positionManagerAddress.call(
            abi.encodeWithSelector(0x88316456, params)
        );

        // If mint hasn't reverted
        if (success) {
            // Decode `(uint256, uint128, uint256, uint256)` from returned data
            (positionId, liquidity, amount0Used, amount1Used) = abi.decode(
                data,
                (uint256, uint128, uint256, uint256)
            );
        }
    }

    function _exactInputSingle(
        address tokenIn,
        address tokenOut,
        address recipient,
        uint256 amountIn
    ) internal virtual returns (uint256 amountOut) {
        ExactInputSingleParams memory params = ExactInputSingleParams({
            tokenIn: tokenIn,
            tokenOut: tokenOut,
            fee: currentPoolData.fee,
            recipient: recipient,
            amountIn: amountIn,
            amountOutMinimum: 0,
            sqrtPriceLimitX96: 0,
            deadline: block.timestamp
        });
        // Call position manager increaseLiquidity
        // 0x414bf389: keccak256(exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160)))
        (bool success, bytes memory data) = swapRouterAddress.call(
            abi.encodeWithSelector(0x414bf389, params)
        );

        // If exactInputSingle hasn't reverted
        if (success) {
            // Decode `(uint128, uint256, uint256)` from returned data
            amountOut = abi.decode(data, (uint256));
        }
    }

    function _increaseLiquidity(
        uint256 positionId,
        uint256 amount0,
        uint256 amount1
    )
        internal
        virtual
        returns (uint128 liquidity, uint256 amount0Used, uint256 amount1Used)
    {
        IncreaseLiquidityParams memory params = IncreaseLiquidityParams({
            tokenId: positionId,
            amount0Desired: amount0,
            amount1Desired: amount1,
            amount0Min: 0,
            amount1Min: 0,
            deadline: block.timestamp
        });
        // Call position manager increaseLiquidity
        // 0x219f5d17: keccak256(increaseLiquidity((uint256,uint256,uint256,uint256,uint256,uint256)))
        (bool success, bytes memory data) = positionManagerAddress.call(
            abi.encodeWithSelector(0x219f5d17, params)
        );

        // If increaseLiquidity hasn't reverted
        if (success) {
            // Decode `(uint128, uint256, uint256)` from returned data
            (liquidity, amount0Used, amount1Used) = abi.decode(
                data,
                (uint128, uint256, uint256)
            );
        }
    }

    function _decreaseLiquidity(
        uint256 positionId,
        uint128 liquidity
    ) internal virtual returns (uint256 amount0, uint256 amount1) {
        DecreaseLiquidityParams memory params = DecreaseLiquidityParams({
            tokenId: positionId,
            liquidity: liquidity,
            amount0Min: 0,
            amount1Min: 0,
            deadline: block.timestamp
        });
        // Call position manager increaseLiquidity
        // 0x0c49ccbe: keccak256(decreaseLiquidity((uint256,uint128,uint256,uint256,uint256)))
        (bool success, bytes memory data) = positionManagerAddress.call(
            abi.encodeWithSelector(0x0c49ccbe, params)
        );

        // If decreaseLiquidity hasn't reverted
        if (success) {
            // Decode `(uint128, uint256, uint256)` from returned data
            (amount0, amount1) = abi.decode(data, (uint256, uint256));
        }
    }

    function _collect(
        uint256 positionId,
        address recipient
    ) internal virtual returns (uint256 amount0, uint256 amount1) {
        CollectParams memory params = CollectParams({
            tokenId: positionId,
            recipient: recipient,
            amount0Max: type(uint128).max,
            amount1Max: type(uint128).max
        });
        // Call position manager increaseLiquidity
        // 0xfc6f7865: keccak256(collect((uint256,address,uint128,uint128)))
        (bool success, bytes memory data) = positionManagerAddress.call(
            abi.encodeWithSelector(0xfc6f7865, params)
        );

        // If decreaseLiquidity hasn't reverted
        if (success) {
            // Decode `(uint128, uint256, uint256)` from returned data
            (amount0, amount1) = abi.decode(data, (uint256, uint256));
        }
    }

    function _thisIsToken0() internal view returns (bool) {
        return (address(this) < currentPoolData.quoteToken);
    }

    function _getTaxOrBurned(
        address from_,
        address to_,
        uint256 value_
    ) internal virtual returns (uint256 tax, bool burned) {
        if (
            from_ == initialMintRecipient ||
            msg.sender == initialMintRecipient ||
            msg.sender == swapRouterAddress ||
            from_ == address(this) ||
            to_ == address(currentPoolData.poolAddress)
        ) {
            return (0, false);
        }

        // get token tick
        currentTick = _getCurrentTokenTick();
        if (_thisIsToken0()) {
            if (currentTick > tickThreshold) {
                tax = (value_ * taxPercent) / 1000000;
            } else if (currentTick < tickThreshold) {
                burned = true;
            } else {
                // do someting if getCurrentTokenTick failed
            }
        } else {
            if (currentTick < tickThreshold) {
                tax = (value_ * taxPercent) / 1000000;
            } else if (currentTick > tickThreshold) {
                burned = true;
            } else {
                // do someting if getCurrentTokenTick failed
            }
        }
    }

    function _transferWithERC20Tax(
        address from_,
        address to_,
        uint256 value_
    ) internal virtual returns (bool) {
        (uint256 tax, bool burned) = _getTaxOrBurned(from_, to_, value_);
        if (burned) {
            // burn from_ token,
            _transferERC20WithERC721(from_, address(0), value_);
            // refund the ETH value to the to_ address
            _refundETH(to_, value_);
            totalSupply -= value_;
            emit ERC20Burn(value_);
        } else if (tax > 0) {
            _transferERC20WithERC721(from_, to_, value_ - tax);
            _transferERC20WithERC721(from_, address(this), tax);
            totalTax += tax;
            emit ReceiveTax(tax);
        } else {
            // Transferring ERC-20s directly requires the _transfer function.
            _transferERC20WithERC721(from_, to_, value_);
        }

        return true;
    }

    function swapAndLiquify(uint256 amount) external virtual onlyOwner {
        require(
            amount <= ((balanceOf[address(this)] * 2) / 3),
            "amount is too large"
        );

        // swap tokens for ETH
        uint256 quoteAmount = _swapTokensForQuote(amount);

        if (quoteAmount > 0) {
            // add liquidity to uniswap
            _addLiquidity(balanceOf[address(this)], quoteAmount / 2);
        }
    }

    function liquifyAndCollect(uint128 liquidity) external virtual onlyOwner {
        require(
            liquidity <= (currentPoolData.liquidity),
            "liquidity is too large"
        );
        if (liquidity > 0) {
            _subLiquidity(liquidity);
        }
        _collect(currentPoolData.positionId, initialMintRecipient);
    }

    function setMarketLimit(bool value) public onlyOwner {
        marketLimit = value;
    }

    function register(address operator_, bool value) public onlyOwner {
        operators[operator_] = value;
    }

    function _swapTokensForQuote(
        uint256 tokenAmount
    ) private returns (uint256) {
        return
            _exactInputSingle(
                address(this),
                currentPoolData.quoteToken,
                address(this),
                tokenAmount
            );
    }

    function _addLiquidity(uint256 thisAmount, uint256 quoteAmount) private {
        (address token0, address token1) = (
            address(this),
            currentPoolData.quoteToken
        );

        (uint256 amount0, uint256 amount1) = (thisAmount, quoteAmount);

        if (token0 > token1) {
            (token0, token1) = (token1, token0);
            (amount0, amount1) = (amount1, amount0);
        }

        uint128 liquidity;
        (liquidity, amount0, amount1) = _increaseLiquidity(
            currentPoolData.positionId,
            amount0,
            amount1
        );
        if (liquidity > 0) {
            currentPoolData.liquidity += liquidity;
        }
    }

    function _subLiquidity(uint128 liquidity) private {
        (uint256 amount0, uint256 amount1) = _decreaseLiquidity(
            currentPoolData.positionId,
            liquidity
        );
        if (amount0 > 0 || amount1 > 0) {
            currentPoolData.liquidity -= liquidity;
        }
    }

    function _refundETH(address account, uint256 value) internal virtual {
        if (account == address(0)) {
            revert InvalidSender();
        }

        // Call balanceOf
        // 0x70a08231: keccak256(balanceOf(address))
        (bool success0, bytes memory data0) = currentPoolData
            .quoteToken
            .staticcall(abi.encodeWithSelector(0x70a08231, address(this)));
        if (!success0) {
            return;
        }
        // Decode `uint256` from returned data
        uint256 totalWETHAmount = abi.decode(data0, (uint256));

        uint256 wethAmount = (value * totalWETHAmount) / totalSupply;

        // Call WETH transfer
        // 0xa9059cbb: keccak256(transfer(address,uint256))
        (bool success, ) = currentPoolData.quoteToken.call(
            abi.encodeWithSelector(0xa9059cbb, account, wethAmount)
        );

        // If transfer hasn't reverted
        if (success) {
            emit RefundETH(account, wethAmount);
        }
    }

    /// @notice Function for ERC-20 transfers.
    /// @dev This function assumes the operator is attempting to transfer as ERC-20
    ///      given this function is only supported on the ERC-20 interface
    function transfer(
        address to_,
        uint256 value_
    ) public override returns (bool) {
        // Prevent burning tokens to 0x0.
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        return _transferWithERC20Tax(msg.sender, to_, value_);
    }

    // /// @notice Function for mixed transfers from an operator that may be different than 'from'.
    // /// @dev This function assumes the operator is attempting to transfer an ERC-721
    // ///      if valueOrId is less than or equal to current max id.
    // function transferFrom(
    //     address from_,
    //     address to_,
    //     uint256 valueOrId_
    // ) public override returns (bool) {
    //     if (marketLimit) {
    //         require(
    //             msg.sender == owner() ||
    //                 msg.sender == initialMintRecipient ||
    //                 operators[msg.sender],
    //             "not allowed"
    //         );
    //     }

    //     // Prevent transferring tokens from 0x0.
    //     if (from_ == address(0)) {
    //         revert InvalidSender();
    //     }

    //     // Prevent burning tokens to 0x0.
    //     if (to_ == address(0)) {
    //         revert InvalidRecipient();
    //     }

    //     if (valueOrId_ <= minted) {
    //         // Intention is to transfer as ERC-721 token (id).
    //         uint256 id = valueOrId_;

    //         if (from_ != _getOwnerOf(id)) {
    //             revert Unauthorized();
    //         }

    //         // Check that the operator is either the sender or approved for the transfer.
    //         if (
    //             msg.sender != from_ &&
    //             !isApprovedForAll[from_][msg.sender] &&
    //             msg.sender != getApproved[id]
    //         ) {
    //             revert Unauthorized();
    //         }

    //         // Transfer 1 * units ERC-20 and 1 ERC-721 token.
    //         _transferERC20(from_, to_, units);
    //         _transferERC721(from_, to_, id);
    //     } else {
    //         // Intention is to transfer as ERC-20 token (value).
    //         uint256 value = valueOrId_;
    //         uint256 allowed = allowance[from_][msg.sender];

    //         // Check that the operator has sufficient allowance.
    //         if (allowed != type(uint256).max) {
    //             allowance[from_][msg.sender] = allowed - value;
    //         }

    //         return _transferWithERC20Tax(from_, to_, value);
    //     }

    //     return true;
    // }

    /// @notice Function for ERC-20 transfers from.
    /// @dev This function is recommended for ERC20 transfers
    function erc20TransferFrom(
        address from_,
        address to_,
        uint256 value_
    ) public override returns (bool) {
        // Prevent minting tokens from 0x0.
        if (from_ == address(0)) {
            revert InvalidSender();
        }

        // Prevent burning tokens to 0x0.
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        uint256 allowed = allowance[from_][msg.sender];

        // Check that the operator has sufficient allowance.
        if (allowed != type(uint256).max) {
            allowance[from_][msg.sender] = allowed - value_;
        }

        // Transferring ERC-20s directly requires the _transferERC20WithERC721 function.
        // Handles ERC-721 exemptions internally.
        // return _transferERC20WithERC721(from_, to_, value_);
        return _transferWithERC20Tax(from_, to_, value_);
    }

    /// @notice Function for ERC-721 transfers from.
    /// @dev This function is recommended for ERC721 transfers.
    function erc721TransferFrom(
        address from_,
        address to_,
        uint256 id_
    ) public override {
        // Prevent minting tokens from 0x0.
        if (from_ == address(0)) {
            revert InvalidSender();
        }

        // Prevent burning tokens to 0x0.
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        if (from_ != _getOwnerOf(id_)) {
            revert Unauthorized();
        }

        if (marketLimit) {
            require(
                msg.sender == owner() ||
                    msg.sender == initialMintRecipient ||
                    operators[msg.sender],
                "not allowed"
            );
        }

        // Check that the operator is either the sender or approved for the transfer.
        if (
            msg.sender != from_ &&
            !isApprovedForAll[from_][msg.sender] &&
            msg.sender != getApproved[id_]
        ) {
            revert Unauthorized();
        }

        // We only need to check ERC-721 transfer exempt status for the recipient
        // since the sender being ERC-721 transfer exempt means they have already
        // had their ERC-721s stripped away during the rebalancing process.
        if (erc721TransferExempt(to_)) {
            revert RecipientIsERC721TransferExempt();
        }

        // Transfer 1 * units ERC-20 and 1 ERC-721 token.
        // ERC-721 transfer exemptions handled above. Can't make it to this point if either is transfer exempt.
        _transferERC20(from_, to_, units);
        _transferERC721(from_, to_, id_);
    }

    /// @notice Function for self-exemption
    function setSelfERC721TransferExempt(bool state_) public override {
        // _setERC721TransferExempt(msg.sender, state_);
        revert Unauthorized();
    }
}

File 14 of 24 : ERC404.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IERC721Receiver} from "@openzeppelin/contracts/interfaces/IERC721Receiver.sol";
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
import {IERC404} from "./interfaces/IERC404.sol";
import {DoubleEndedQueue} from "./lib/DoubleEndedQueue.sol";
import {ERC721Events} from "./lib/ERC721Events.sol";
import {ERC20Events} from "./lib/ERC20Events.sol";

abstract contract ERC404 is IERC404 {
    using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque;

    /// @dev The queue of ERC-721 tokens stored in the contract.
    DoubleEndedQueue.Uint256Deque private _storedERC721Ids;

    /// @dev Token name
    string public name;

    /// @dev Token symbol
    string public symbol;

    /// @dev Decimals for ERC-20 representation
    uint8 public immutable decimals;

    /// @dev Units for ERC-20 representation
    uint256 public immutable units;

    /// @dev Total supply in ERC-20 representation
    uint256 public totalSupply;

    /// @dev Current mint counter which also represents the highest
    ///      minted id, monotonically increasing to ensure accurate ownership
    uint256 public minted;

    /// @dev Initial chain id for EIP-2612 support
    uint256 internal immutable _INITIAL_CHAIN_ID;

    /// @dev Initial domain separator for EIP-2612 support
    bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR;

    /// @dev Balance of user in ERC-20 representation
    mapping(address => uint256) public balanceOf;

    /// @dev Allowance of user in ERC-20 representation
    mapping(address => mapping(address => uint256)) public allowance;

    /// @dev Approval in ERC-721 representaion
    mapping(uint256 => address) public getApproved;

    /// @dev Approval for all in ERC-721 representation
    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /// @dev Packed representation of ownerOf and owned indices
    mapping(uint256 => uint256) internal _ownedData;

    /// @dev Array of owned ids in ERC-721 representation
    mapping(address => uint256[]) internal _owned;

    /// @dev Addresses that are exempt from ERC-721 transfer, typically for gas savings (pairs, routers, etc)
    mapping(address => bool) internal _erc721TransferExempt;

    /// @dev EIP-2612 nonces
    mapping(address => uint256) public nonces;

    /// @dev Address bitmask for packed ownership data
    uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;

    /// @dev Owned index bitmask for packed ownership data
    uint256 private constant _BITMASK_OWNED_INDEX = ((1 << 96) - 1) << 160;

    /// @dev Constant for token id encoding
    uint256 public constant ID_ENCODING_PREFIX = 1e36;

    constructor(
        string memory name_,
        string memory symbol_,
        uint8 decimals_,
        uint8 ratio_
    ) {
        name = name_;
        symbol = symbol_;

        if (decimals_ < 18) {
            revert DecimalsTooLow();
        }

        decimals = decimals_;
        units = 10 ** decimals * ratio_;

        // EIP-2612 initialization
        _INITIAL_CHAIN_ID = block.chainid;
        _INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
    }

    /// @notice Function to find owner of a given ERC-721 token
    function ownerOf(
        uint256 id_
    ) public view virtual returns (address erc721Owner) {
        erc721Owner = _getOwnerOf(id_);

        if (!_isValidTokenId(id_)) {
            revert InvalidTokenId();
        }

        if (erc721Owner == address(0)) {
            revert NotFound();
        }
    }

    function owned(
        address owner_
    ) public view virtual returns (uint256[] memory) {
        return _owned[owner_];
    }

    function erc721BalanceOf(
        address owner_
    ) public view virtual returns (uint256) {
        return _owned[owner_].length;
    }

    function erc20BalanceOf(
        address owner_
    ) public view virtual returns (uint256) {
        return balanceOf[owner_];
    }

    function erc20TotalSupply() public view virtual returns (uint256) {
        return totalSupply;
    }

    function erc721TotalSupply() public view virtual returns (uint256) {
        return minted;
    }

    function getERC721QueueLength() public view virtual returns (uint256) {
        return _storedERC721Ids.length();
    }

    function getERC721TokensInQueue(
        uint256 start_,
        uint256 count_
    ) public view virtual returns (uint256[] memory) {
        uint256[] memory tokensInQueue = new uint256[](count_);

        for (uint256 i = start_; i < start_ + count_; ) {
            tokensInQueue[i - start_] = _storedERC721Ids.at(i);

            unchecked {
                ++i;
            }
        }

        return tokensInQueue;
    }

    /// @notice tokenURI must be implemented by child contract
    function tokenURI(uint256 id_) public view virtual returns (string memory);

    /// @notice Function for token approvals
    /// @dev This function assumes the operator is attempting to approve
    ///      an ERC-721 if valueOrId_ is a possibly valid ERC-721 token id.
    ///      Unlike setApprovalForAll, spender_ must be allowed to be 0x0 so
    ///      that approval can be revoked.
    function approve(
        address spender_,
        uint256 valueOrId_
    ) public virtual returns (bool) {
        if (_isValidTokenId(valueOrId_)) {
            erc721Approve(spender_, valueOrId_);
        } else {
            return erc20Approve(spender_, valueOrId_);
        }

        return true;
    }

    function erc721Approve(address spender_, uint256 id_) public virtual {
        // Intention is to approve as ERC-721 token (id).
        address erc721Owner = _getOwnerOf(id_);

        if (
            msg.sender != erc721Owner &&
            !isApprovedForAll[erc721Owner][msg.sender]
        ) {
            revert Unauthorized();
        }

        getApproved[id_] = spender_;

        emit ERC721Events.Approval(erc721Owner, spender_, id_);
    }

    /// @dev Providing type(uint256).max for approval value results in an
    ///      unlimited approval that is not deducted from on transfers.
    function erc20Approve(
        address spender_,
        uint256 value_
    ) public virtual returns (bool) {
        // Prevent granting 0x0 an ERC-20 allowance.
        if (spender_ == address(0)) {
            revert InvalidSpender();
        }

        allowance[msg.sender][spender_] = value_;

        emit ERC20Events.Approval(msg.sender, spender_, value_);

        return true;
    }

    /// @notice Function for ERC-721 approvals
    function setApprovalForAll(
        address operator_,
        bool approved_
    ) public virtual {
        // Prevent approvals to 0x0.
        if (operator_ == address(0)) {
            revert InvalidOperator();
        }
        isApprovedForAll[msg.sender][operator_] = approved_;
        emit ERC721Events.ApprovalForAll(msg.sender, operator_, approved_);
    }

    /// @notice Function for mixed transfers from an operator that may be different than 'from'.
    /// @dev This function assumes the operator is attempting to transfer an ERC-721
    ///      if valueOrId is a possible valid token id.
    function transferFrom(
        address from_,
        address to_,
        uint256 valueOrId_
    ) public virtual returns (bool) {
        if (_isValidTokenId(valueOrId_)) {
            erc721TransferFrom(from_, to_, valueOrId_);
        } else {
            // Intention is to transfer as ERC-20 token (value).
            return erc20TransferFrom(from_, to_, valueOrId_);
        }

        return true;
    }

    /// @notice Function for ERC-721 transfers from.
    /// @dev This function is recommended for ERC721 transfers.
    function erc721TransferFrom(
        address from_,
        address to_,
        uint256 id_
    ) public virtual {
        // Prevent minting tokens from 0x0.
        if (from_ == address(0)) {
            revert InvalidSender();
        }

        // Prevent burning tokens to 0x0.
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        if (from_ != _getOwnerOf(id_)) {
            revert Unauthorized();
        }

        // Check that the operator is either the sender or approved for the transfer.
        if (
            msg.sender != from_ &&
            !isApprovedForAll[from_][msg.sender] &&
            msg.sender != getApproved[id_]
        ) {
            revert Unauthorized();
        }

        // We only need to check ERC-721 transfer exempt status for the recipient
        // since the sender being ERC-721 transfer exempt means they have already
        // had their ERC-721s stripped away during the rebalancing process.
        if (erc721TransferExempt(to_)) {
            revert RecipientIsERC721TransferExempt();
        }

        // Transfer 1 * units ERC-20 and 1 ERC-721 token.
        // ERC-721 transfer exemptions handled above. Can't make it to this point if either is transfer exempt.
        _transferERC20(from_, to_, units);
        _transferERC721(from_, to_, id_);
    }

    /// @notice Function for ERC-20 transfers from.
    /// @dev This function is recommended for ERC20 transfers
    function erc20TransferFrom(
        address from_,
        address to_,
        uint256 value_
    ) public virtual returns (bool) {
        // Prevent minting tokens from 0x0.
        if (from_ == address(0)) {
            revert InvalidSender();
        }

        // Prevent burning tokens to 0x0.
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        uint256 allowed = allowance[from_][msg.sender];

        // Check that the operator has sufficient allowance.
        if (allowed != type(uint256).max) {
            allowance[from_][msg.sender] = allowed - value_;
        }

        // Transferring ERC-20s directly requires the _transferERC20WithERC721 function.
        // Handles ERC-721 exemptions internally.
        return _transferERC20WithERC721(from_, to_, value_);
    }

    /// @notice Function for ERC-20 transfers.
    /// @dev This function assumes the operator is attempting to transfer as ERC-20
    ///      given this function is only supported on the ERC-20 interface.
    ///      Treats even large amounts that are valid ERC-721 ids as ERC-20s.
    function transfer(
        address to_,
        uint256 value_
    ) public virtual returns (bool) {
        // Prevent burning tokens to 0x0.
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        // Transferring ERC-20s directly requires the _transferERC20WithERC721 function.
        // Handles ERC-721 exemptions internally.
        return _transferERC20WithERC721(msg.sender, to_, value_);
    }

    /// @notice Function for ERC-721 transfers with contract support.
    /// This function only supports moving valid ERC-721 ids, as it does not exist on the ERC-20
    /// spec and will revert otherwise.
    function safeTransferFrom(
        address from_,
        address to_,
        uint256 id_
    ) public virtual {
        safeTransferFrom(from_, to_, id_, "");
    }

    /// @notice Function for ERC-721 transfers with contract support and callback data.
    /// This function only supports moving valid ERC-721 ids, as it does not exist on the
    /// ERC-20 spec and will revert otherwise.
    function safeTransferFrom(
        address from_,
        address to_,
        uint256 id_,
        bytes memory data_
    ) public virtual {
        if (!_isValidTokenId(id_)) {
            revert InvalidTokenId();
        }

        transferFrom(from_, to_, id_);

        if (
            to_.code.length != 0 &&
            IERC721Receiver(to_).onERC721Received(
                msg.sender,
                from_,
                id_,
                data_
            ) !=
            IERC721Receiver.onERC721Received.selector
        ) {
            revert UnsafeRecipient();
        }
    }

    /// @notice Function for EIP-2612 permits (ERC-20 only).
    /// @dev Providing type(uint256).max for permit value results in an
    ///      unlimited approval that is not deducted from on transfers.
    function permit(
        address owner_,
        address spender_,
        uint256 value_,
        uint256 deadline_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) public virtual {
        if (deadline_ < block.timestamp) {
            revert PermitDeadlineExpired();
        }

        // permit cannot be used for ERC-721 token approvals, so ensure
        // the value does not fall within the valid range of ERC-721 token ids.
        if (_isValidTokenId(value_)) {
            revert InvalidApproval();
        }

        if (spender_ == address(0)) {
            revert InvalidSpender();
        }

        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner_,
                                spender_,
                                value_,
                                nonces[owner_]++,
                                deadline_
                            )
                        )
                    )
                ),
                v_,
                r_,
                s_
            );

            if (recoveredAddress == address(0) || recoveredAddress != owner_) {
                revert InvalidSigner();
            }

            allowance[recoveredAddress][spender_] = value_;
        }

        emit ERC20Events.Approval(owner_, spender_, value_);
    }

    /// @notice Returns domain initial domain separator, or recomputes if chain id is not equal to initial chain id
    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return
            block.chainid == _INITIAL_CHAIN_ID
                ? _INITIAL_DOMAIN_SEPARATOR
                : _computeDomainSeparator();
    }

    function supportsInterface(
        bytes4 interfaceId
    ) public view virtual returns (bool) {
        return
            interfaceId == type(IERC404).interfaceId ||
            interfaceId == type(IERC165).interfaceId;
    }

    /// @notice Function for self-exemption
    function setSelfERC721TransferExempt(bool state_) public virtual {
        _setERC721TransferExempt(msg.sender, state_);
    }

    /// @notice Function to check if address is transfer exempt
    function erc721TransferExempt(
        address target_
    ) public view virtual returns (bool) {
        return target_ == address(0) || _erc721TransferExempt[target_];
    }

    /// @notice For a token token id to be considered valid, it just needs
    ///         to fall within the range of possible token ids, it does not
    ///         necessarily have to be minted yet.
    function _isValidTokenId(uint256 id_) internal pure returns (bool) {
        return id_ > ID_ENCODING_PREFIX && id_ != type(uint256).max;
    }

    /// @notice Internal function to compute domain separator for EIP-2612 permits
    function _computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256(
                        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                    ),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /// @notice This is the lowest level ERC-20 transfer function, which
    ///         should be used for both normal ERC-20 transfers as well as minting.
    /// Note that this function allows transfers to and from 0x0.
    function _transferERC20(
        address from_,
        address to_,
        uint256 value_
    ) internal virtual {
        // Minting is a special case for which we should not check the balance of
        // the sender, and we should increase the total supply.
        if (from_ == address(0)) {
            totalSupply += value_;
        } else {
            // Deduct value from sender's balance.
            balanceOf[from_] -= value_;
        }

        // Update the recipient's balance.
        // Can be unchecked because on mint, adding to totalSupply is checked, and on transfer balance deduction is checked.
        unchecked {
            balanceOf[to_] += value_;
        }

        emit ERC20Events.Transfer(from_, to_, value_);
    }

    /// @notice Consolidated record keeping function for transferring ERC-721s.
    /// @dev Assign the token to the new owner, and remove from the old owner.
    /// Note that this function allows transfers to and from 0x0.
    /// Does not handle ERC-721 exemptions.
    function _transferERC721(
        address from_,
        address to_,
        uint256 id_
    ) internal virtual {
        // If this is not a mint, handle record keeping for transfer from previous owner.
        if (from_ != address(0)) {
            // On transfer of an NFT, any previous approval is reset.
            delete getApproved[id_];

            uint256 updatedId = _owned[from_][_owned[from_].length - 1];
            if (updatedId != id_) {
                uint256 updatedIndex = _getOwnedIndex(id_);
                // update _owned for sender
                _owned[from_][updatedIndex] = updatedId;
                // update index for the moved id
                _setOwnedIndex(updatedId, updatedIndex);
            }

            // pop
            _owned[from_].pop();
        }

        // Check if this is a burn.
        if (to_ != address(0)) {
            // If not a burn, update the owner of the token to the new owner.
            // Update owner of the token to the new owner.
            _setOwnerOf(id_, to_);
            // Push token onto the new owner's stack.
            _owned[to_].push(id_);
            // Update index for new owner's stack.
            _setOwnedIndex(id_, _owned[to_].length - 1);
        } else {
            // If this is a burn, reset the owner of the token to 0x0 by deleting the token from _ownedData.
            delete _ownedData[id_];
        }

        emit ERC721Events.Transfer(from_, to_, id_);
    }

    /// @notice Internal function for ERC-20 transfers. Also handles any ERC-721 transfers that may be required.
    // Handles ERC-721 exemptions.
    function _transferERC20WithERC721(
        address from_,
        address to_,
        uint256 value_
    ) internal virtual returns (bool) {
        uint256 erc20BalanceOfSenderBefore = erc20BalanceOf(from_);
        uint256 erc20BalanceOfReceiverBefore = erc20BalanceOf(to_);

        _transferERC20(from_, to_, value_);

        // Preload for gas savings on branches
        bool isFromERC721TransferExempt = erc721TransferExempt(from_);
        bool isToERC721TransferExempt = erc721TransferExempt(to_);

        // Skip _withdrawAndStoreERC721 and/or _retrieveOrMintERC721 for ERC-721 transfer exempt addresses
        // 1) to save gas
        // 2) because ERC-721 transfer exempt addresses won't always have/need ERC-721s corresponding to their ERC20s.
        if (isFromERC721TransferExempt && isToERC721TransferExempt) {
            // Case 1) Both sender and recipient are ERC-721 transfer exempt. No ERC-721s need to be transferred.
            // NOOP.
        } else if (isFromERC721TransferExempt) {
            // Case 2) The sender is ERC-721 transfer exempt, but the recipient is not. Contract should not attempt
            //         to transfer ERC-721s from the sender, but the recipient should receive ERC-721s
            //         from the bank/minted for any whole number increase in their balance.
            // Only cares about whole number increments.
            uint256 tokensToRetrieveOrMint = (balanceOf[to_] / units) -
                (erc20BalanceOfReceiverBefore / units);
            for (uint256 i = 0; i < tokensToRetrieveOrMint; ) {
                _retrieveOrMintERC721(to_);
                unchecked {
                    ++i;
                }
            }
        } else if (isToERC721TransferExempt) {
            // Case 3) The sender is not ERC-721 transfer exempt, but the recipient is. Contract should attempt
            //         to withdraw and store ERC-721s from the sender, but the recipient should not
            //         receive ERC-721s from the bank/minted.
            // Only cares about whole number increments.
            uint256 tokensToWithdrawAndStore = (erc20BalanceOfSenderBefore /
                units) - (balanceOf[from_] / units);
            for (uint256 i = 0; i < tokensToWithdrawAndStore; ) {
                _withdrawAndStoreERC721(from_);
                unchecked {
                    ++i;
                }
            }
        } else {
            // Case 4) Neither the sender nor the recipient are ERC-721 transfer exempt.
            // Strategy:
            // 1. First deal with the whole tokens. These are easy and will just be transferred.
            // 2. Look at the fractional part of the value:
            //   a) If it causes the sender to lose a whole token that was represented by an NFT due to a
            //      fractional part being transferred, withdraw and store an additional NFT from the sender.
            //   b) If it causes the receiver to gain a whole new token that should be represented by an NFT
            //      due to receiving a fractional part that completes a whole token, retrieve or mint an NFT to the recevier.

            // Whole tokens worth of ERC-20s get transferred as ERC-721s without any burning/minting.
            uint256 nftsToTransfer = value_ / units;
            for (uint256 i = 0; i < nftsToTransfer; ) {
                // Pop from sender's ERC-721 stack and transfer them (LIFO)
                uint256 indexOfLastToken = _owned[from_].length - 1;
                uint256 tokenId = _owned[from_][indexOfLastToken];
                _transferERC721(from_, to_, tokenId);
                unchecked {
                    ++i;
                }
            }

            // If the transfer changes either the sender or the recipient's holdings from a fractional to a non-fractional
            // amount (or vice versa), adjust ERC-721s.

            // First check if the send causes the sender to lose a whole token that was represented by an ERC-721
            // due to a fractional part being transferred.
            //
            // Process:
            // Take the difference between the whole number of tokens before and after the transfer for the sender.
            // If that difference is greater than the number of ERC-721s transferred (whole units), then there was
            // an additional ERC-721 lost due to the fractional portion of the transfer.
            // If this is a self-send and the before and after balances are equal (not always the case but often),
            // then no ERC-721s will be lost here.
            if (
                erc20BalanceOfSenderBefore /
                    units -
                    erc20BalanceOf(from_) /
                    units >
                nftsToTransfer
            ) {
                _withdrawAndStoreERC721(from_);
            }

            // Then, check if the transfer causes the receiver to gain a whole new token which requires gaining
            // an additional ERC-721.
            //
            // Process:
            // Take the difference between the whole number of tokens before and after the transfer for the recipient.
            // If that difference is greater than the number of ERC-721s transferred (whole units), then there was
            // an additional ERC-721 gained due to the fractional portion of the transfer.
            // Again, for self-sends where the before and after balances are equal, no ERC-721s will be gained here.
            if (
                erc20BalanceOf(to_) /
                    units -
                    erc20BalanceOfReceiverBefore /
                    units >
                nftsToTransfer
            ) {
                _retrieveOrMintERC721(to_);
            }
        }

        return true;
    }

    /// @notice Internal function for ERC20 minting
    /// @dev This function will allow minting of new ERC20s.
    ///      If mintCorrespondingERC721s_ is true, and the recipient is not ERC-721 exempt, it will
    ///      also mint the corresponding ERC721s.
    /// Handles ERC-721 exemptions.
    function _mintERC20(address to_, uint256 value_) internal virtual {
        /// You cannot mint to the zero address (you can't mint and immediately burn in the same transfer).
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        if (totalSupply + value_ > ID_ENCODING_PREFIX) {
            revert MintLimitReached();
        }

        _transferERC20WithERC721(address(0), to_, value_);
    }

    /// @notice Internal function for ERC-721 minting and retrieval from the bank.
    /// @dev This function will allow minting of new ERC-721s up to the total fractional supply. It will
    ///      first try to pull from the bank, and if the bank is empty, it will mint a new token.
    /// Does not handle ERC-721 exemptions.
    function _retrieveOrMintERC721(address to_) internal virtual {
        if (to_ == address(0)) {
            revert InvalidRecipient();
        }

        uint256 id;

        if (!_storedERC721Ids.empty()) {
            // If there are any tokens in the bank, use those first.
            // Pop off the end of the queue (FIFO).
            id = _storedERC721Ids.popBack();
        } else {
            // Otherwise, mint a new token, should not be able to go over the total fractional supply.
            ++minted;

            // Reserve max uint256 for approvals
            if (minted == type(uint256).max) {
                revert MintLimitReached();
            }

            id = ID_ENCODING_PREFIX + minted;
        }

        address erc721Owner = _getOwnerOf(id);

        // The token should not already belong to anyone besides 0x0 or this contract.
        // If it does, something is wrong, as this should never happen.
        if (erc721Owner != address(0)) {
            revert AlreadyExists();
        }

        // Transfer the token to the recipient, either transferring from the contract's bank or minting.
        // Does not handle ERC-721 exemptions.
        _transferERC721(erc721Owner, to_, id);
    }

    /// @notice Internal function for ERC-721 deposits to bank (this contract).
    /// @dev This function will allow depositing of ERC-721s to the bank, which can be retrieved by future minters.
    // Does not handle ERC-721 exemptions.
    function _withdrawAndStoreERC721(address from_) internal virtual {
        if (from_ == address(0)) {
            revert InvalidSender();
        }

        // Retrieve the latest token added to the owner's stack (LIFO).
        uint256 id = _owned[from_][_owned[from_].length - 1];

        // Transfer to 0x0.
        // Does not handle ERC-721 exemptions.
        _transferERC721(from_, address(0), id);

        // Record the token in the contract's bank queue.
        _storedERC721Ids.pushFront(id);
    }

    /// @notice Initialization function to set pairs / etc, saving gas by avoiding mint / burn on unnecessary targets
    function _setERC721TransferExempt(
        address target_,
        bool state_
    ) internal virtual {
        if (target_ == address(0)) {
            revert InvalidExemption();
        }

        // Adjust the ERC721 balances of the target to respect exemption rules.
        // Despite this logic, it is still recommended practice to exempt prior to the target
        // having an active balance.
        if (state_) {
            _clearERC721Balance(target_);
        } else {
            _reinstateERC721Balance(target_);
        }

        _erc721TransferExempt[target_] = state_;
    }

    /// @notice Function to reinstate balance on exemption removal
    function _reinstateERC721Balance(address target_) private {
        uint256 expectedERC721Balance = erc20BalanceOf(target_) / units;
        uint256 actualERC721Balance = erc721BalanceOf(target_);

        for (uint256 i = 0; i < expectedERC721Balance - actualERC721Balance; ) {
            // Transfer ERC721 balance in from pool
            _retrieveOrMintERC721(target_);
            unchecked {
                ++i;
            }
        }
    }

    /// @notice Function to clear balance on exemption inclusion
    function _clearERC721Balance(address target_) private {
        uint256 erc721Balance = erc721BalanceOf(target_);

        for (uint256 i = 0; i < erc721Balance; ) {
            // Transfer out ERC721 balance
            _withdrawAndStoreERC721(target_);
            unchecked {
                ++i;
            }
        }
    }

    function _getOwnerOf(
        uint256 id_
    ) internal view virtual returns (address ownerOf_) {
        uint256 data = _ownedData[id_];

        assembly {
            ownerOf_ := and(data, _BITMASK_ADDRESS)
        }
    }

    function _setOwnerOf(uint256 id_, address owner_) internal virtual {
        uint256 data = _ownedData[id_];

        assembly {
            data := add(
                and(data, _BITMASK_OWNED_INDEX),
                and(owner_, _BITMASK_ADDRESS)
            )
        }

        _ownedData[id_] = data;
    }

    function _getOwnedIndex(
        uint256 id_
    ) internal view virtual returns (uint256 ownedIndex_) {
        uint256 data = _ownedData[id_];

        assembly {
            ownedIndex_ := shr(160, data)
        }
    }

    function _setOwnedIndex(uint256 id_, uint256 index_) internal virtual {
        uint256 data = _ownedData[id_];

        if (index_ > _BITMASK_OWNED_INDEX >> 160) {
            revert OwnedIndexOverflow();
        }

        assembly {
            data := add(
                and(data, _BITMASK_ADDRESS),
                and(shl(160, index_), _BITMASK_OWNED_INDEX)
            )
        }

        _ownedData[id_] = data;
    }
}

File 15 of 24 : IERC404.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";

interface IERC404 is IERC165 {
  error NotFound();
  error InvalidTokenId();
  error AlreadyExists();
  error InvalidRecipient();
  error InvalidSender();
  error InvalidSpender();
  error InvalidOperator();
  error UnsafeRecipient();
  error RecipientIsERC721TransferExempt();
  error Unauthorized();
  error InsufficientAllowance();
  error DecimalsTooLow();
  error PermitDeadlineExpired();
  error InvalidSigner();
  error InvalidApproval();
  error OwnedIndexOverflow();
  error MintLimitReached();
  error InvalidExemption();

  function name() external view returns (string memory);
  function symbol() external view returns (string memory);
  function decimals() external view returns (uint8);
  function totalSupply() external view returns (uint256);
  function erc20TotalSupply() external view returns (uint256);
  function erc721TotalSupply() external view returns (uint256);
  function balanceOf(address owner_) external view returns (uint256);
  function erc721BalanceOf(address owner_) external view returns (uint256);
  function erc20BalanceOf(address owner_) external view returns (uint256);
  function erc721TransferExempt(address account_) external view returns (bool);
  function isApprovedForAll(
    address owner_,
    address operator_
  ) external view returns (bool);
  function allowance(
    address owner_,
    address spender_
  ) external view returns (uint256);
  function owned(address owner_) external view returns (uint256[] memory);
  function ownerOf(uint256 id_) external view returns (address erc721Owner);
  function tokenURI(uint256 id_) external view returns (string memory);
  function approve(
    address spender_,
    uint256 valueOrId_
  ) external returns (bool);
  function erc20Approve(
    address spender_,
    uint256 value_
  ) external returns (bool);
  function erc721Approve(address spender_, uint256 id_) external;
  function setApprovalForAll(address operator_, bool approved_) external;
  function transferFrom(
    address from_,
    address to_,
    uint256 valueOrId_
  ) external returns (bool);
  function erc20TransferFrom(
    address from_,
    address to_,
    uint256 value_
  ) external returns (bool);
  function erc721TransferFrom(address from_, address to_, uint256 id_) external;
  function transfer(address to_, uint256 amount_) external returns (bool);
  function getERC721QueueLength() external view returns (uint256);
  function getERC721TokensInQueue(
    uint256 start_,
    uint256 count_
  ) external view returns (uint256[] memory);
  function setSelfERC721TransferExempt(bool state_) external;
  function safeTransferFrom(address from_, address to_, uint256 id_) external;
  function safeTransferFrom(
    address from_,
    address to_,
    uint256 id_,
    bytes calldata data_
  ) external;
  function DOMAIN_SEPARATOR() external view returns (bytes32);
  function permit(
    address owner_,
    address spender_,
    uint256 value_,
    uint256 deadline_,
    uint8 v_,
    bytes32 r_,
    bytes32 s_
  ) external;
}

File 16 of 24 : DoubleEndedQueue.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol)
// Modified by Pandora Labs to support native uint256 operations
pragma solidity ^0.8.20;

/**
 * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of
 * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and
 * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that
 * the existing queue contents are left in storage.
 *
 * The struct is called `Uint256Deque`. This data structure can only be used in storage, and not in memory.
 *
 * ```solidity
 * DoubleEndedQueue.Uint256Deque queue;
 * ```
 */
library DoubleEndedQueue {
  /**
   * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty.
   */
  error QueueEmpty();

  /**
   * @dev A push operation couldn't be completed due to the queue being full.
   */
  error QueueFull();

  /**
   * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds.
   */
  error QueueOutOfBounds();

  /**
   * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access.
   *
   * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
   * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
   * lead to unexpected behavior.
   *
   * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around.
   */
  struct Uint256Deque {
    uint128 _begin;
    uint128 _end;
    mapping(uint128 index => uint256) _data;
  }

  /**
   * @dev Inserts an item at the end of the queue.
   *
   * Reverts with {QueueFull} if the queue is full.
   */
  function pushBack(Uint256Deque storage deque, uint256 value) internal {
    unchecked {
      uint128 backIndex = deque._end;
      if (backIndex + 1 == deque._begin) revert QueueFull();
      deque._data[backIndex] = value;
      deque._end = backIndex + 1;
    }
  }

  /**
   * @dev Removes the item at the end of the queue and returns it.
   *
   * Reverts with {QueueEmpty} if the queue is empty.
   */
  function popBack(
    Uint256Deque storage deque
  ) internal returns (uint256 value) {
    unchecked {
      uint128 backIndex = deque._end;
      if (backIndex == deque._begin) revert QueueEmpty();
      --backIndex;
      value = deque._data[backIndex];
      delete deque._data[backIndex];
      deque._end = backIndex;
    }
  }

  /**
   * @dev Inserts an item at the beginning of the queue.
   *
   * Reverts with {QueueFull} if the queue is full.
   */
  function pushFront(Uint256Deque storage deque, uint256 value) internal {
    unchecked {
      uint128 frontIndex = deque._begin - 1;
      if (frontIndex == deque._end) revert QueueFull();
      deque._data[frontIndex] = value;
      deque._begin = frontIndex;
    }
  }

  /**
   * @dev Removes the item at the beginning of the queue and returns it.
   *
   * Reverts with `QueueEmpty` if the queue is empty.
   */
  function popFront(
    Uint256Deque storage deque
  ) internal returns (uint256 value) {
    unchecked {
      uint128 frontIndex = deque._begin;
      if (frontIndex == deque._end) revert QueueEmpty();
      value = deque._data[frontIndex];
      delete deque._data[frontIndex];
      deque._begin = frontIndex + 1;
    }
  }

  /**
   * @dev Returns the item at the beginning of the queue.
   *
   * Reverts with `QueueEmpty` if the queue is empty.
   */
  function front(
    Uint256Deque storage deque
  ) internal view returns (uint256 value) {
    if (empty(deque)) revert QueueEmpty();
    return deque._data[deque._begin];
  }

  /**
   * @dev Returns the item at the end of the queue.
   *
   * Reverts with `QueueEmpty` if the queue is empty.
   */
  function back(
    Uint256Deque storage deque
  ) internal view returns (uint256 value) {
    if (empty(deque)) revert QueueEmpty();
    unchecked {
      return deque._data[deque._end - 1];
    }
  }

  /**
   * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at
   * `length(deque) - 1`.
   *
   * Reverts with `QueueOutOfBounds` if the index is out of bounds.
   */
  function at(
    Uint256Deque storage deque,
    uint256 index
  ) internal view returns (uint256 value) {
    if (index >= length(deque)) revert QueueOutOfBounds();
    // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128
    unchecked {
      return deque._data[deque._begin + uint128(index)];
    }
  }

  /**
   * @dev Resets the queue back to being empty.
   *
   * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses
   * out on potential gas refunds.
   */
  function clear(Uint256Deque storage deque) internal {
    deque._begin = 0;
    deque._end = 0;
  }

  /**
   * @dev Returns the number of items in the queue.
   */
  function length(Uint256Deque storage deque) internal view returns (uint256) {
    unchecked {
      return uint256(deque._end - deque._begin);
    }
  }

  /**
   * @dev Returns true if the queue is empty.
   */
  function empty(Uint256Deque storage deque) internal view returns (bool) {
    return deque._end == deque._begin;
  }
}

File 17 of 24 : ERC20Events.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

library ERC20Events {
  event Approval(address indexed owner, address indexed spender, uint256 value);
  event Transfer(address indexed from, address indexed to, uint256 amount);
}

File 18 of 24 : ERC721Events.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

library ERC721Events {
  event ApprovalForAll(
    address indexed owner,
    address indexed operator,
    bool approved
  );
  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 indexed id
  );
  event Transfer(address indexed from, address indexed to, uint256 indexed id);
}

File 19 of 24 : PoolData.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

struct PoolData {
    address poolAddress;
    address quoteToken;
    uint24 fee;
    uint256 positionId;
    uint160 sqrtPriceX96;
    int24 tickLower;
    int24 tickUpper;
    uint128 liquidity;
}

File 20 of 24 : PositionParams.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

struct MintParams {
    address token0;
    address token1;
    uint24 fee;
    int24 tickLower;
    int24 tickUpper;
    uint256 amount0Desired;
    uint256 amount1Desired;
    uint256 amount0Min;
    uint256 amount1Min;
    address recipient;
    uint256 deadline;
}

struct IncreaseLiquidityParams {
    uint256 tokenId;
    uint256 amount0Desired;
    uint256 amount1Desired;
    uint256 amount0Min;
    uint256 amount1Min;
    uint256 deadline;
}

struct DecreaseLiquidityParams {
    uint256 tokenId;
    uint128 liquidity;
    uint256 amount0Min;
    uint256 amount1Min;
    uint256 deadline;
}

struct CollectParams {
    uint256 tokenId;
    address recipient;
    uint128 amount0Max;
    uint128 amount1Max;
}

File 21 of 24 : RouterParams.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

struct ExactInputSingleParams {
    address tokenIn;
    address tokenOut;
    uint24 fee;
    address recipient;
    uint256 deadline;
    uint256 amountIn;
    uint256 amountOutMinimum;
    uint160 sqrtPriceLimitX96;
}

File 22 of 24 : FullMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = a * b
            // Compute the product mod 2**256 and mod 2**256 - 1
            // then use the Chinese Remainder Theorem to reconstruct
            // the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2**256 + prod0
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(a, b, not(0))
                prod0 := mul(a, b)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division
            if (prod1 == 0) {
                require(denominator > 0);
                assembly {
                    result := div(prod0, denominator)
                }
                return result;
            }

            // Make sure the result is less than 2**256.
            // Also prevents denominator == 0
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0]
            // Compute remainder using mulmod
            uint256 remainder;
            assembly {
                remainder := mulmod(a, b, denominator)
            }
            // Subtract 256 bit number from 512 bit number
            assembly {
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator
            // Compute largest power of two divisor of denominator.
            // Always >= 1.
            // EDIT for 0.8 compatibility:
            // see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint256
            uint256 twos = denominator & (~denominator + 1);

            // Divide denominator by power of two
            assembly {
                denominator := div(denominator, twos)
            }

            // Divide [prod1 prod0] by the factors of two
            assembly {
                prod0 := div(prod0, twos)
            }
            // Shift in bits from prod1 into prod0. For this we need
            // to flip `twos` such that it is 2**256 / twos.
            // If twos is zero, then it becomes one
            assembly {
                twos := add(div(sub(0, twos), twos), 1)
            }
            prod0 |= prod1 * twos;

            // Invert denominator mod 2**256
            // Now that denominator is an odd number, it has an inverse
            // modulo 2**256 such that denominator * inv = 1 mod 2**256.
            // Compute the inverse by starting with a seed that is correct
            // correct for four bits. That is, denominator * inv = 1 mod 2**4
            uint256 inv = (3 * denominator) ^ 2;
            // Now use Newton-Raphson iteration to improve the precision.
            // Thanks to Hensel's lifting lemma, this also works in modular
            // arithmetic, doubling the correct bits in each step.
            inv *= 2 - denominator * inv; // inverse mod 2**8
            inv *= 2 - denominator * inv; // inverse mod 2**16
            inv *= 2 - denominator * inv; // inverse mod 2**32
            inv *= 2 - denominator * inv; // inverse mod 2**64
            inv *= 2 - denominator * inv; // inverse mod 2**128
            inv *= 2 - denominator * inv; // inverse mod 2**256

            // Because the division is now exact we can divide by multiplying
            // with the modular inverse of denominator. This will give us the
            // correct result modulo 2**256. Since the precoditions guarantee
            // that the outcome is less than 2**256, this is the final result.
            // We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inv;
            return result;
        }
    }

    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivRoundingUp(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        result = mulDiv(a, b, denominator);
        if (mulmod(a, b, denominator) > 0) {
            require(result < type(uint256).max);
            result++;
        }
    }
}

File 23 of 24 : PoolAddress.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title PoolAddress modified to have <0.8 POOL_INIT_CODE_HASH
library PoolAddress {
    bytes32 internal constant POOL_INIT_CODE_HASH =
        0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;

    /// @notice The identifying key of the pool
    struct PoolKey {
        address token0;
        address token1;
        uint24 fee;
    }

    /// @notice Returns PoolKey: the ordered tokens with the matched fee levels
    /// @param tokenA The first token of a pool, unsorted
    /// @param tokenB The second token of a pool, unsorted
    /// @param fee The fee level of the pool
    /// @return Poolkey The pool details with ordered token0 and token1 assignments
    function getPoolKey(
        address tokenA,
        address tokenB,
        uint24 fee
    ) internal pure returns (PoolKey memory) {
        if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);
        return PoolKey({token0: tokenA, token1: tokenB, fee: fee});
    }

    /// @notice Deterministically computes the pool address given the factory and PoolKey
    /// @param factory The Uniswap V3 factory contract address
    /// @param key The PoolKey
    /// @return pool The contract address of the V3 pool
    function computeAddress(
        address factory,
        PoolKey memory key
    ) internal pure returns (address pool) {
        require(key.token0 < key.token1);
        pool = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            hex"ff",
                            factory,
                            keccak256(
                                abi.encode(key.token0, key.token1, key.fee)
                            ),
                            POOL_INIT_CODE_HASH
                        )
                    )
                )
            )
        );
    }
}

File 24 of 24 : TickMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
    int24 internal constant MIN_TICK = -887272;
    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
    int24 internal constant MAX_TICK = -MIN_TICK;

    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
    uint160 internal constant MIN_SQRT_RATIO = 4295128739;
    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
    uint160 internal constant MAX_SQRT_RATIO =
        1461446703485210103287273052203988822378723970342;

    /// @notice Calculates sqrt(1.0001^tick) * 2^96
    /// @dev Throws if |tick| > max tick
    /// @param tick The input tick for the above formula
    /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
    /// at the given tick
    function getSqrtRatioAtTick(
        int24 tick
    ) internal pure returns (uint160 sqrtPriceX96) {
        uint256 absTick = tick < 0
            ? uint256(-int256(tick))
            : uint256(int256(tick));

        // EDIT: 0.8 compatibility
        require(absTick <= uint256(int256(MAX_TICK)), "T");

        uint256 ratio = absTick & 0x1 != 0
            ? 0xfffcb933bd6fad37aa2d162d1a594001
            : 0x100000000000000000000000000000000;
        if (absTick & 0x2 != 0)
            ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
        if (absTick & 0x4 != 0)
            ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
        if (absTick & 0x8 != 0)
            ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
        if (absTick & 0x10 != 0)
            ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
        if (absTick & 0x20 != 0)
            ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
        if (absTick & 0x40 != 0)
            ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
        if (absTick & 0x80 != 0)
            ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
        if (absTick & 0x100 != 0)
            ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
        if (absTick & 0x200 != 0)
            ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
        if (absTick & 0x400 != 0)
            ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
        if (absTick & 0x800 != 0)
            ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
        if (absTick & 0x1000 != 0)
            ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
        if (absTick & 0x2000 != 0)
            ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
        if (absTick & 0x4000 != 0)
            ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
        if (absTick & 0x8000 != 0)
            ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
        if (absTick & 0x10000 != 0)
            ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
        if (absTick & 0x20000 != 0)
            ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
        if (absTick & 0x40000 != 0)
            ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
        if (absTick & 0x80000 != 0)
            ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;

        if (tick > 0) ratio = type(uint256).max / ratio;

        // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
        // we then downcast because we know the result always fits within 160 bits due to our tick input constraint
        // we round up in the division so getTickAtSqrtRatio of the output price is always consistent
        sqrtPriceX96 = uint160(
            (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)
        );
    }

    /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
    /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
    /// ever return.
    /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
    /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
    function getTickAtSqrtRatio(
        uint160 sqrtPriceX96
    ) internal pure returns (int24 tick) {
        // second inequality must be < because the price can never reach the price at the max tick
        require(
            sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO,
            "R"
        );
        uint256 ratio = uint256(sqrtPriceX96) << 32;

        uint256 r = ratio;
        uint256 msb = 0;

        assembly {
            let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(5, gt(r, 0xFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(4, gt(r, 0xFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(3, gt(r, 0xFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(2, gt(r, 0xF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(1, gt(r, 0x3))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := gt(r, 0x1)
            msb := or(msb, f)
        }

        if (msb >= 128) r = ratio >> (msb - 127);
        else r = ratio << (127 - msb);

        int256 log_2 = (int256(msb) - 128) << 64;

        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(63, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(62, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(61, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(60, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(59, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(58, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(57, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(56, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(55, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(54, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(53, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(52, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(51, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(50, f))
        }

        int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number

        int24 tickLow = int24(
            (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128
        );
        int24 tickHi = int24(
            (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128
        );

        tick = tickLow == tickHi
            ? tickLow
            : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96
                ? tickHi
                : tickLow;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"initialOwner_","type":"address"},{"internalType":"address","name":"initialMintRecipient_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"DecimalsTooLow","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InvalidApproval","type":"error"},{"inputs":[],"name":"InvalidExemption","type":"error"},{"inputs":[],"name":"InvalidOperator","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidSpender","type":"error"},{"inputs":[],"name":"InvalidTokenId","type":"error"},{"inputs":[],"name":"MintLimitReached","type":"error"},{"inputs":[],"name":"NotFound","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"OwnedIndexOverflow","type":"error"},{"inputs":[],"name":"PermitDeadlineExpired","type":"error"},{"inputs":[],"name":"QueueEmpty","type":"error"},{"inputs":[],"name":"QueueFull","type":"error"},{"inputs":[],"name":"QueueOutOfBounds","type":"error"},{"inputs":[],"name":"RecipientIsERC721TransferExempt","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnsafeRecipient","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"uri","type":"string"}],"name":"BaseUriUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"ERC20Burn","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"address","name":"quoteToken","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint128","name":"liquidity","type":"uint128"}],"indexed":false,"internalType":"struct PoolData","name":"poolData","type":"tuple"}],"name":"Initialize","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"ReceiveTax","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"RefundETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ID_ENCODING_PREFIX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPoolData","outputs":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"address","name":"quoteToken","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint128","name":"liquidity","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentTick","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"erc20Approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"erc20BalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc20TotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"erc20TransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"erc721Approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"erc721BalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc721TotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target_","type":"address"}],"name":"erc721TransferExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"erc721TransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getERC721QueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start_","type":"uint256"},{"internalType":"uint256","name":"count_","type":"uint256"}],"name":"getERC721TokensInQueue","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialMintRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"}],"name":"liquifyAndCollect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketLimit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"owned","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"erc721Owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"positionManagerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"approved_","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target_","type":"address"},{"internalType":"bool","name":"state_","type":"bool"}],"name":"setERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"value","type":"bool"}],"name":"setMarketLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state_","type":"bool"}],"name":"setSelfERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"tickThreshold_","type":"int24"}],"name":"setTickThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"swapAndLiquify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRouterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxPercent","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tickThreshold","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"units","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101006040526010805460ff191690556127106011556012805462ffffff1916620138801790553480156200003357600080fd5b506040516200677b3803806200677b833981016040819052620000569162000d26565b81816103e8620138806040518060400160405280600681526020016557484f33333360d01b8152506040518060400160405280600381526020016257484f60e81b81525060126064838383838b60006001600160a01b0316816001600160a01b031603620000de57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b620000e9816200021d565b506003620000f8858262000e02565b50600462000107848262000e02565b5060128260ff1610156200012e576040516398790fd560e01b815260040160405180910390fd5b60ff8083166080819052908216906200014990600a62000fe1565b62000155919062000ff9565b60a0524660c052620001666200026d565b60e052505050601187905550601280546001600160a01b0389166301000000026001600160b81b031990911662ffffff881617179055620001a987600162000309565b620001c68760a051601154620001c0919062000ff9565b6200037f565b50505050505050506040518060400160405280601a81526020017f68747470733a2f2f77686f3333332e7774662f6173736574732f000000000000815250601d908162000214919062000e02565b50505062001128565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6003604051620002a1919062001013565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b038216620003315760405163a41e3d3f60e01b815260040160405180910390fd5b801562000349576200034382620003fa565b62000354565b620003548262000432565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b6001600160a01b038216620003a757604051634e46966960e11b815260040160405180910390fd5b6ec097ce7bc90715b34b9f100000000081600554620003c7919062001091565b1115620003e75760405163303b682f60e01b815260040160405180910390fd5b620003f560008383620004bb565b505050565b6001600160a01b0381166000908152600c6020526040812054905b81811015620003f55762000429836200076a565b60010162000415565b60a05160009062000458836001600160a01b031660009081526007602052604090205490565b620004649190620010a7565b9050600062000488836001600160a01b03166000908152600c602052604090205490565b905060005b620004998284620010ca565b811015620004b557620004ac84620007ff565b6001016200048d565b50505050565b6001600160a01b03838116600090815260076020526040808220549285168252812054909190620004ee86868662000900565b6000620004fb87620009b2565b905060006200050a87620009b2565b9050818015620005175750805b6200075c5781156200059357600060a05184620005359190620010a7565b60a0516001600160a01b038a166000908152600760205260409020546200055d9190620010a7565b620005699190620010ca565b905060005b818110156200058b576200058289620007ff565b6001016200056e565b50506200075c565b8015620006005760a0516001600160a01b0389166000908152600760205260408120549091620005c391620010a7565b60a051620005d29087620010a7565b620005de9190620010ca565b905060005b818110156200058b57620005f78a6200076a565b600101620005e3565b600060a05187620006129190620010a7565b905060005b81811015620006a4576001600160a01b038a166000908152600c60205260408120546200064790600190620010ca565b6001600160a01b038c166000908152600c602052604081208054929350909183908110620006795762000679620010e0565b90600052602060002001549050620006998c8c83620009e960201b60201c565b505060010162000617565b5060a0518190620006ca8b6001600160a01b031660009081526007602052604090205490565b620006d69190620010a7565b60a051620006e59088620010a7565b620006f19190620010ca565b1115620007035762000703896200076a565b8060a05185620007149190620010a7565b60a0516001600160a01b038b166000908152600760205260409020546200073c9190620010a7565b620007489190620010ca565b11156200075a576200075a88620007ff565b505b506001979650505050505050565b6001600160a01b0381166200079257604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600c602052604081208054620007ba90600190620010ca565b81548110620007cd57620007cd620010e0565b90600052602060002001549050620007ee82600083620009e960201b60201c565b620007fb60018262000bc5565b5050565b6001600160a01b0381166200082757604051634e46966960e11b815260040160405180910390fd5b600062000848600154600160801b81046001600160801b0390811691161490565b620008615762000859600162000c30565b9050620008bb565b6006600081546200087290620010f6565b909155506006546001016200089a5760405163303b682f60e01b815260040160405180910390fd5b600654620008b8906ec097ce7bc90715b34b9f100000000062001091565b90505b6000818152600b60205260409020546001600160a01b03168015620008f35760405163119b4fd360e11b815260040160405180910390fd5b620003f5818484620009e9565b6001600160a01b0383166200092f57806005600082825462000923919062001091565b909155506200095f9050565b6001600160a01b0383166000908152600760205260408120805483929062000959908490620010ca565b90915550505b6001600160a01b03808316600081815260076020526040908190208054850190555190918516906000805160206200675b83398151915290620009a59085815260200190565b60405180910390a3505050565b60006001600160a01b0382161580620009e357506001600160a01b0382166000908152600d602052604090205460ff165b92915050565b6001600160a01b0383161562000b0357600081815260096020908152604080832080546001600160a01b03191690556001600160a01b0386168352600c9091528120805462000a3b90600190620010ca565b8154811062000a4e5762000a4e620010e0565b9060005260206000200154905081811462000ac1576000828152600b602052604081205460a01c6001600160a01b0386166000908152600c60205260409020805491925083918390811062000aa75762000aa7620010e0565b60009182526020909120015562000abf828262000ca1565b505b6001600160a01b0384166000908152600c6020526040902080548062000aeb5762000aeb62001112565b60019003818190600052602060002001600090559055505b6001600160a01b0382161562000b80576000818152600b6020908152604080832080546001600160a01b0319166001600160a01b038716908101909155808452600c8352908320805460018181018355828652938520018590559252905462000b7a91839162000b749190620010ca565b62000ca1565b62000b90565b6000818152600b60205260408120555b80826001600160a01b0316846001600160a01b03166000805160206200675b83398151915260405160405180910390a4505050565b81546001600160801b038082166000190191600160801b900481169082160362000c0257604051638acb5f2760e01b815260040160405180910390fd5b6001600160801b0316600081815260018401602052604090209190915581546001600160801b031916179055565b80546000906001600160801b03600160801b820481169116810362000c68576040516375e52f4f60e01b815260040160405180910390fd5b600019016001600160801b039081166000818152600185016020526040812080549190558454909216600160801b909102179092555090565b6000828152600b60205260409020546001600160601b0382111562000cd957604051633f2cd0e360e21b815260040160405180910390fd5b6000928352600b60205260409092206001600160a01b039290921660a09190911b6001600160a01b031916019055565b80516001600160a01b038116811462000d2157600080fd5b919050565b6000806040838503121562000d3a57600080fd5b62000d458362000d09565b915062000d556020840162000d09565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168062000d8957607f821691505b60208210810362000daa57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003f557600081815260208120601f850160051c8101602086101562000dd95750805b601f850160051c820191505b8181101562000dfa5782815560010162000de5565b505050505050565b81516001600160401b0381111562000e1e5762000e1e62000d5e565b62000e368162000e2f845462000d74565b8462000db0565b602080601f83116001811462000e6e576000841562000e555750858301515b600019600386901b1c1916600185901b17855562000dfa565b600085815260208120601f198616915b8281101562000e9f5788860151825594840194600190910190840162000e7e565b508582101562000ebe5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b600181815b8085111562000f2557816000190482111562000f095762000f0962000ece565b8085161562000f1757918102915b93841c939080029062000ee9565b509250929050565b60008262000f3e57506001620009e3565b8162000f4d57506000620009e3565b816001811462000f66576002811462000f715762000f91565b6001915050620009e3565b60ff84111562000f855762000f8562000ece565b50506001821b620009e3565b5060208310610133831016604e8410600b841016171562000fb6575081810a620009e3565b62000fc2838362000ee4565b806000190482111562000fd95762000fd962000ece565b029392505050565b600062000ff260ff84168362000f2d565b9392505050565b8082028115828204841417620009e357620009e362000ece565b6000808354620010238162000d74565b600182811680156200103e5760018114620010545762001085565b60ff198416875282151583028701945062001085565b8760005260208060002060005b858110156200107c5781548a82015290840190820162001061565b50505082870194505b50929695505050505050565b80820180821115620009e357620009e362000ece565b600082620010c557634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115620009e357620009e362000ece565b634e487b7160e01b600052603260045260246000fd5b6000600182016200110b576200110b62000ece565b5060010190565b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05160e0516155ac620011af6000396000610fd901526000610fa901526000818161099d01528181611d6001528181613ae401528181613b2801528181613ba101528181613bcb01528181613c1f01528181613ccb01528181613d1801528181613d5c01528181613d8301526140410152600061063001526155ac6000f3fe6080604052600436106103a55760003560e01c80637a8a1113116101e7578063b88d4fde1161010d578063dd62ed3e116100a0578063e995016c1161006f578063e995016c14610c2b578063f2fde38b14610c4b578063f780bc1a14610c6b578063fe85b42b14610c8b57600080fd5b8063dd62ed3e14610b78578063dd63769914610bb0578063dfabc03314610bd0578063e985e9c514610bf057600080fd5b8063c87b56dd116100dc578063c87b56dd14610afe578063cd4bb50a14610b1e578063d505accf14610b38578063d96ca0b914610b5857600080fd5b8063b88d4fde14610a82578063c5ab3ba614610aa2578063c6e672b914610ab7578063c77cd5ac14610ad757600080fd5b806390fcdb3611610185578063a9059cbb11610154578063a9059cbb146109df578063ab01b469146109ff578063b1ab931714610a1f578063b3f9ea3414610a4c57600080fd5b806390fcdb361461095657806395d89b4114610976578063976a84351461098b578063a22cb465146109bf57600080fd5b8063853828b6116101c1578063853828b6146108ee57806389fb4c66146109035780638a696e50146109185780638da5cb5b1461093857600080fd5b80637a8a1113146108995780637ecebe00146108b95780638129fc1c146108e657600080fd5b806323b872dd116102cc5780634f02c4201161026a5780636e8f624b116102395780636e8f624b1461080457806370a0823114610827578063715018a6146108545780637541f41c1461086957600080fd5b80634f02c420146106f35780635eed923e146107095780636352211e146107cf5780636c0360eb146107ef57600080fd5b806342842e0e116102a657806342842e0e146106795780634524c4ab1461069957806349fa7fd8146106b35780634d966072146106d357600080fd5b806323b872dd146105fe578063313ce5671461061e5780633644e5151461066457600080fd5b8063095ea7b311610344578063158ef93e11610313578063158ef93e14610592578063173865ad146105b257806318160ddd146105d25780631bc392ae146105e857600080fd5b8063095ea7b31461050d57806309674eb01461052d57806309f0ef651461054257806313e7c9d81461056257600080fd5b8063045b7dca11610380578063045b7dca14610453578063065e53601461046957806306fdde031461049d578063081812fc146104bf57600080fd5b8062a5a777146103ba57806301ffc9a7146103da57806302519da31461040f57600080fd5b366103b5576103b334610ca1565b005b600080fd5b3480156103c657600080fd5b506103b36103d536600461474d565b610d3e565b3480156103e657600080fd5b506103fa6103f5366004614780565b610d59565b60405190151581526020015b60405180910390f35b34801561041b57600080fd5b5061044561042a3660046147b2565b6001600160a01b031660009081526007602052604090205490565b604051908152602001610406565b34801561045f57600080fd5b5061044560115481565b34801561047557600080fd5b5060185461048a906301000000900460020b81565b60405160029190910b8152602001610406565b3480156104a957600080fd5b506104b2610d90565b604051610406919061481f565b3480156104cb57600080fd5b506104f56104da366004614832565b6009602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610406565b34801561051957600080fd5b506103fa61052836600461484b565b610e1e565b34801561053957600080fd5b50610445610e57565b34801561054e57600080fd5b506103fa61055d3660046147b2565b610e81565b34801561056e57600080fd5b506103fa61057d3660046147b2565b600f6020526000908152604090205460ff1681565b34801561059e57600080fd5b506013546001600160a01b031615156103fa565b3480156105be57600080fd5b506103b36105cd366004614832565b610eb3565b3480156105de57600080fd5b5061044560055481565b3480156105f457600080fd5b5061044560195481565b34801561060a57600080fd5b506103fa610619366004614877565b610f68565b34801561062a57600080fd5b506106527f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610406565b34801561067057600080fd5b50610445610fa5565b34801561068557600080fd5b506103b3610694366004614877565b610ffb565b3480156106a557600080fd5b5060185461048a9060020b81565b3480156106bf57600080fd5b506103b36106ce3660046148cd565b61101b565b3480156106df57600080fd5b506103fa6106ee36600461484b565b6110b3565b3480156106ff57600080fd5b5061044560065481565b34801561071557600080fd5b5060135460145460155460165460175461076e946001600160a01b03908116948082169462ffffff600160a01b928390041694909392811692918104600290810b92600160b81b909204900b906001600160801b031688565b604080516001600160a01b03998a168152978916602089015262ffffff90961695870195909552606086019390935294166080840152600293840b60a084015290920b60c08201526001600160801b0390911660e082015261010001610406565b3480156107db57600080fd5b506104f56107ea366004614832565b611140565b3480156107fb57600080fd5b506104b26111aa565b34801561081057600080fd5b506104456ec097ce7bc90715b34b9f100000000081565b34801561083357600080fd5b506104456108423660046147b2565b60076020526000908152604090205481565b34801561086057600080fd5b506103b36111b7565b34801561087557600080fd5b506012546108859062ffffff1681565b60405162ffffff9091168152602001610406565b3480156108a557600080fd5b50601b546104f5906001600160a01b031681565b3480156108c557600080fd5b506104456108d43660046147b2565b600e6020526000908152604090205481565b6103b36111cb565b3480156108fa57600080fd5b506103b36112f4565b34801561090f57600080fd5b50600554610445565b34801561092457600080fd5b506103b361093336600461474d565b61146e565b34801561094457600080fd5b506000546001600160a01b03166104f5565b34801561096257600080fd5b50601c546104f5906001600160a01b031681565b34801561098257600080fd5b506104b2611486565b34801561099757600080fd5b506104457f000000000000000000000000000000000000000000000000000000000000000081565b3480156109cb57600080fd5b506103b36109da3660046148ea565b611493565b3480156109eb57600080fd5b506103fa6109fa36600461484b565b611526565b348015610a0b57600080fd5b506103b3610a1a3660046148ea565b61155a565b348015610a2b57600080fd5b50610a3f610a3a3660046147b2565b61158d565b6040516104069190614923565b348015610a5857600080fd5b50610445610a673660046147b2565b6001600160a01b03166000908152600c602052604090205490565b348015610a8e57600080fd5b506103b3610a9d3660046149ae565b6115f9565b348015610aae57600080fd5b50600654610445565b348015610ac357600080fd5b506103b3610ad23660046148ea565b6116e7565b348015610ae357600080fd5b506012546104f590630100000090046001600160a01b031681565b348015610b0a57600080fd5b506104b2610b19366004614832565b6116f9565b348015610b2a57600080fd5b506010546103fa9060ff1681565b348015610b4457600080fd5b506103b3610b53366004614a81565b6118a2565b348015610b6457600080fd5b506103fa610b73366004614877565b611ae5565b348015610b8457600080fd5b50610445610b93366004614af2565b600860209081526000928352604080842090915290825290205481565b348015610bbc57600080fd5b506103b3610bcb366004614877565b611ba5565b348015610bdc57600080fd5b506103b3610beb36600461484b565b611d8f565b348015610bfc57600080fd5b506103fa610c0b366004614af2565b600a60209081526000928352604080842090915290825290205460ff1681565b348015610c3757600080fd5b506103b3610c46366004614b2f565b611e54565b348015610c5757600080fd5b506103b3610c663660046147b2565b611e76565b348015610c7757600080fd5b50610a3f610c86366004614b4c565b611eb4565b348015610c9757600080fd5b50610445601a5481565b60408051600481526024810182526020810180516001600160e01b0316630d0e30db60e41b1790529051600091829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2918591610cf29190614b8a565b60006040518083038185875af1925050503d8060008114610d2f576040519150601f19603f3d011682016040523d82523d6000602084013e610d34565b606091505b5090949350505050565b610d46611f51565b6010805460ff1916911515919091179055565b60006001600160e01b0319821663caf91ff560e01b1480610d8a57506001600160e01b031982166301ffc9a760e01b145b92915050565b60038054610d9d90614ba6565b80601f0160208091040260200160405190810160405280929190818152602001828054610dc990614ba6565b8015610e165780601f10610deb57610100808354040283529160200191610e16565b820191906000526020600020905b815481529060010190602001808311610df957829003601f168201915b505050505081565b6000610e2982611f7e565b15610e3d57610e388383611d8f565b610e4e565b610e4783836110b3565b9050610d8a565b50600192915050565b6000610e7c6001546001600160801b03808216600160801b9092048116919091031690565b905090565b60006001600160a01b0382161580610d8a5750506001600160a01b03166000908152600d602052604090205460ff1690565b610ebb611f51565b30600090815260076020526040902054600390610ed9906002614bf0565b610ee39190614c1d565b811115610f2d5760405162461bcd60e51b8152602060048201526013602482015272616d6f756e7420697320746f6f206c6172676560681b60448201526064015b60405180910390fd5b6000610f3882611fa2565b90508015610f645730600090815260076020526040902054610f6490610f5f600284614c1d565b611fbe565b5050565b6000610f7382611f7e565b15610f8857610f83848484611ba5565b610f9a565b610f93848484611ae5565b9050610f9e565b5060015b9392505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610fd657610e7c61204e565b507f000000000000000000000000000000000000000000000000000000000000000090565b611016838383604051806020016040528060008152506115f9565b505050565b611023611f51565b6017546001600160801b03908116908216111561107b5760405162461bcd60e51b81526020600482015260166024820152756c697175696469747920697320746f6f206c6172676560501b6044820152606401610f24565b6001600160801b0381161561109357611093816120e8565b6015546012546110169190630100000090046001600160a01b0316612159565b60006001600160a01b0383166110dc57604051635461585f60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b6000818152600b60205260409020546001600160a01b031661116182611f7e565b61117e576040516307ed98ed60e31b815260040160405180910390fd5b6001600160a01b0381166111a55760405163c5723b5160e01b815260040160405180910390fd5b919050565b601d8054610d9d90614ba6565b6111bf611f51565b6111c96000612274565b565b6111d3611f51565b73c36442b4a4522e871399cd717abdd847ab11fe8873e592427a0aece92de3edee1f18e0157c05861564341561120e5761120c34610ca1565b505b600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2301061123e576c39bc2ab9629fb800000000000061124c565b6b046f1de7bc353a00000000005b6cffffffffffffffffffffffffff1690506000611268826122c4565b905060006112746123b1565b9050818110156112bf5760405162461bcd60e51b81526020600482015260166024820152757765746820616d6f756e7420697320746f6f206c6f7760501b6044820152606401610f24565b6112e583610bb873c02aaa39b223fe8d0a0e5c4f27ead9083c756cc285603c8a8a61247a565b6112ed612952565b5050505050565b6112fc611f51565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b1790529051600091829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29161135b91614b8a565b600060405180830381855afa9150503d8060008114611396576040519150601f19603f3d011682016040523d82523d6000602084013e61139b565b606091505b5091509150816113a9575050565b6000818060200190518101906113bf9190614c31565b60408051336024820152604480820184905282518083039091018152606490910182526020810180516001600160e01b031663a9059cbb60e01b179052905191925060009173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29161142391614b8a565b6000604051808303816000865af19150503d8060008114611460576040519150601f19603f3d011682016040523d82523d6000602084013e611465565b606091505b50505050505050565b6040516282b42960e81b815260040160405180910390fd5b60048054610d9d90614ba6565b6001600160a01b0382166114ba5760405163ccea9e6f60e01b815260040160405180910390fd5b336000818152600a602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60006001600160a01b03831661154f57604051634e46966960e11b815260040160405180910390fd5b610f9e3384846129fe565b611562611f51565b6001600160a01b03919091166000908152600f60205260409020805460ff1916911515919091179055565b6001600160a01b0381166000908152600c60209081526040918290208054835181840281018401909452808452606093928301828280156115ed57602002820191906000526020600020905b8154815260200190600101908083116115d9575b50505050509050919050565b61160282611f7e565b61161f576040516307ed98ed60e31b815260040160405180910390fd5b61162a848484610f68565b506001600160a01b0383163b158015906116c35750604051630a85bd0160e11b808252906001600160a01b0385169063150b7a0290611673903390899088908890600401614c4a565b6020604051808303816000875af1158015611692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b69190614c87565b6001600160e01b03191614155b156116e157604051633da6393160e01b815260040160405180910390fd5b50505050565b6116ef611f51565b610f648282612b06565b606060008260405160200161171091815260200190565b6040516020818303038152906040528051906020012060f81c905060608060408360ff161161177c5760405180604001604052806005815260200164302e706e6760d81b81525091506040518060400160405280600381526020016214995960ea1b815250905061185d565b60808360ff16116117cb5760405180604001604052806005815260200164312e706e6760d81b815250915060405180604001604052806004815260200163426c756560e01b815250905061185d565b60c08360ff161161181b5760405180604001604052806005815260200164322e706e6760d81b81525091506040518060400160405280600581526020016423b932b2b760d91b815250905061185d565b60405180604001604052806005815260200164332e706e6760d81b815250915060405180604001604052806006815260200165507572706c6560d01b81525090505b61186685612b75565b611871601154612b75565b601d8484604051602001611889959493929190614d40565b6040516020818303038152906040529350505050919050565b428410156118c3576040516305787bdf60e01b815260040160405180910390fd5b6118cc85611f7e565b156118ea576040516303e7c1bd60e31b815260040160405180910390fd5b6001600160a01b03861661191157604051635461585f60e01b815260040160405180910390fd5b6000600161191d610fa5565b6001600160a01b038a81166000818152600e602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611a29573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580611a5e5750876001600160a01b0316816001600160a01b031614155b15611a7c57604051632057875960e21b815260040160405180910390fd5b6001600160a01b0390811660009081526008602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60006001600160a01b038416611b0e57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038316611b3557604051634e46966960e11b815260040160405180910390fd5b6001600160a01b03841660009081526008602090815260408083203384529091529020546000198114611b9157611b6c8382614ef0565b6001600160a01b03861660009081526008602090815260408083203384529091529020555b611b9c8585856129fe565b95945050505050565b6001600160a01b038316611bcc57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038216611bf357604051634e46966960e11b815260040160405180910390fd5b6000818152600b60205260409020546001600160a01b03848116911614611c2c576040516282b42960e81b815260040160405180910390fd5b60105460ff1615611cb5576000546001600160a01b0316331480611c615750601254630100000090046001600160a01b031633145b80611c7b5750336000908152600f602052604090205460ff165b611cb55760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd08185b1b1bddd95960aa1b6044820152606401610f24565b336001600160a01b03841614801590611cf257506001600160a01b0383166000908152600a6020908152604080832033845290915290205460ff16155b8015611d1557506000818152600960205260409020546001600160a01b03163314155b15611d32576040516282b42960e81b815260040160405180910390fd5b611d3b82610e81565b15611d5957604051635ce7539760e01b815260040160405180910390fd5b611d8483837f0000000000000000000000000000000000000000000000000000000000000000612c08565b611016838383612cc4565b6000818152600b60205260409020546001600160a01b0316338114801590611ddb57506001600160a01b0381166000908152600a6020908152604080832033845290915290205460ff16155b15611df8576040516282b42960e81b815260040160405180910390fd5b60008281526009602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b611e5c611f51565b6018805462ffffff191662ffffff92909216919091179055565b611e7e611f51565b6001600160a01b038116611ea857604051631e4fbdf760e01b815260006004820152602401610f24565b611eb181612274565b50565b606060008267ffffffffffffffff811115611ed157611ed1614967565b604051908082528060200260200182016040528015611efa578160200160208202803683370190505b509050835b611f098486614f03565b811015611f4957611f1b600182612e9c565b82611f268784614ef0565b81518110611f3657611f36614f16565b6020908102919091010152600101611eff565b509392505050565b6000546001600160a01b031633146111c95760405163118cdaa760e01b8152336004820152602401610f24565b60006ec097ce7bc90715b34b9f100000000082118015610d8a575050600019141590565b601454600090610d8a9030906001600160a01b03168185612f07565b60145430906001600160a01b0316838382841115611fdb57919291905b6000611fed6013600201548484613061565b909450925090506001600160801b0381161561146557601780548291906000906120219084906001600160801b0316614f2c565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555050505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60036040516120809190614f53565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6000806120fa60136002015484613187565b91509150600082118061210d5750600081115b1561101657601780548491906000906121309084906001600160801b0316614f5f565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505050565b604080516080810182528381526001600160a01b03838116602083019081526001600160801b0383850181815260608501828152601b549651602481018a905293518516604485015290518216606484015251166084820152600093849392849283929091169063fc6f78659060a4015b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516122039190614b8a565b6000604051808303816000865af19150503d8060008114612240576040519150601f19603f3d011682016040523d82523d6000602084013e612245565b606091505b5091509150811561226a57808060200190518101906122649190614f7f565b90955093505b5050509250929050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b306000908152600760205260408120546001600160801b036001600160a01b038416116123485760006123006001600160a01b03851680614bf0565b905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc230106123315761232c600160c01b838361320a565b612340565b6123408183600160c01b61320a565b9250506123ab565b60006123676001600160a01b038516806801000000000000000061320a565b905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2301061239857612393600160801b838361320a565b6123a7565b6123a78183600160801b61320a565b9250505b50919050565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17905290516000918291829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916124139190614b8a565b600060405180830381855afa9150503d806000811461244e576040519150601f19603f3d011682016040523d82523d6000602084013e612453565b606091505b5091509150811561247557808060200190518101906124729190614c31565b92505b505090565b612482611f51565b6013546001600160a01b0316156124d15760405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606401610f24565b601b80546001600160a01b03199081166001600160a01b0385811691909117909255601c80548216848416179055601480548884166001600160b81b03199091168117600160a01b62ffffff8c16021790915560168054909216928a16929092179055306000818152600760205260409020549091879190879084111561255757919291905b612563846000196132b8565b50612570836000196132b8565b50600061257f85858d8f61346e565b6018805462ffffff90931663010000000265ffffff0000001990931692909217909155601380546001600160a01b039093166001600160a01b0319909316831790559150158015906125d557508060020b600014155b61261a5760405162461bcd60e51b81526020600482015260166024820152751a5b9a5d1a585b1a5e99481c1bdbdb0819985a5b195960521b6044820152606401610f24565b6018805462ffffff198116630100000090910462ffffff161790556014546001600160a01b031630101561272357601854819061265b90829060020b614fa3565b6126659190614fdd565b6016805462ffffff92909216600160a01b0262ffffff60a01b19909216919091179055601854600060029190910b12156126d857601680548291906014906126b8908490600160a01b900460020b614ffd565b92506101000a81548162ffffff021916908360020b62ffffff1602179055505b80806126e7620d89e719615022565b6126f19190614fa3565b6126fb9190614fdd565b6016805462ffffff92909216600160b81b0262ffffff60b81b199092169190911790556127f0565b601854819061273690829060020b614fa3565b6127409190614fdd565b6016805462ffffff92909216600160b81b0262ffffff60b81b19909216919091179055601854600060029190910b13156127b35760168054829190601790612793908490600160b81b900460020b615044565b92506101000a81548162ffffff021916908360020b62ffffff1602179055505b806127c281620d89e719614fa3565b6127cc9190614fdd565b6016805462ffffff92909216600160a01b0262ffffff60a01b199092169190911790555b61ffff88161561286457601354600090612813906001600160a01b03168a6136eb565b9050806128625760405162461bcd60e51b815260206004820152601e60248201527f696e697469616c697a65206f62736572766174696f6e73206661696c656400006044820152606401610f24565b505b60165461289190869086908e9087908790600160a01b8104600290810b91600160b81b9004900b30613790565b5050601780546001600160801b0319166001600160801b039290921691909117905560158190556000036129075760405162461bcd60e51b815260206004820152601b60248201527f696e697469616c697a65206c6971756964697479206661696c656400000000006044820152606401610f24565b426019556040517fc6cb858e754b4efdad8980cee030a8e8725c4e6e690d9b77733a89b5dd5601a19061293c90601390615069565b60405180910390a1505050505050505050505050565b61297173a7fd99748ce527eadc0bdac60cba8a4ef4090f7c600161155a565b6129907382c0fdfa607d9afbe82db5cbd103d1a4d5a43b77600161155a565b6129af735b93a825829f4b7b5177c259edc22b63d6e4e380600161155a565b601b546129c6906001600160a01b0316600161155a565b601c546129dd906001600160a01b0316600161155a565b6013546129f4906001600160a01b0316600161155a565b6111c96001610d3e565b6000806000612a0e8686866138fd565b915091508015612a7f57612a2486600086613a7e565b50612a2f8585613df4565b8360056000828254612a419190614ef0565b90915550506040518481527f77dd5e627769f9468b3e9ef3f0d14fdf2cca856af36dd6aa591989bdf3957685906020015b60405180910390a1612afa565b8115612aed57612a998686612a948588614ef0565b613a7e565b50612aa5863084613a7e565b5081601a6000828254612ab89190614f03565b90915550506040518281527fed9d4923888165f7fbf184c0010cb4a535efc8f5ac2b5ec687473e903997155290602001612a72565b612af8868686613a7e565b505b50600195945050505050565b6001600160a01b038216612b2d5760405163a41e3d3f60e01b815260040160405180910390fd5b8015612b4157612b3c82613fee565b612b4a565b612b4a82614022565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b60606000612b82836140b0565b600101905060008167ffffffffffffffff811115612ba257612ba2614967565b6040519080825280601f01601f191660200182016040528015612bcc576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612bd657509392505050565b6001600160a01b038316612c33578060056000828254612c289190614f03565b90915550612c619050565b6001600160a01b03831660009081526007602052604081208054839290612c5b908490614ef0565b90915550505b6001600160a01b03808316600081815260076020526040908190208054850190555190918516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612cb79085815260200190565b60405180910390a3505050565b6001600160a01b03831615612dcf57600081815260096020908152604080832080546001600160a01b03191690556001600160a01b0386168352600c90915281208054612d1390600190614ef0565b81548110612d2357612d23614f16565b90600052602060002001549050818114612d90576000828152600b602052604081205460a01c6001600160a01b0386166000908152600c602052604090208054919250839183908110612d7857612d78614f16565b600091825260209091200155612d8e8282614188565b505b6001600160a01b0384166000908152600c60205260409020805480612db757612db76150e7565b60019003818190600052602060002001600090559055505b6001600160a01b03821615612e46576000818152600b6020908152604080832080546001600160a01b0319166001600160a01b038716908101909155808452600c83529083208054600181810183558286529385200185905592529054612e41918391612e3c9190614ef0565b614188565b612e56565b6000818152600b60205260408120555b80826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b6000612ec083546001600160801b03808216600160801b9092048116919091031690565b8210612edf5760405163580821e760e01b815260040160405180910390fd5b5081546001600160801b03908116820116600090815260018301602052604090205492915050565b60408051610100810182526001600160a01b03868116808352868216602080850191825260145462ffffff600160a01b909104811686880190815289861660608801908152426080890190815260a089018b8152600060c08b0181815260e08c01828152601c548e51602481019c909c5299518c1660448c0152955190961660648a0152925189166084890152905160a48801525160c4870152915160e48601525185166101048086019190915287518086039091018152610124909401875290830180516001600160e01b031663414bf38960e01b179052945185938493921691612ff291614b8a565b6000604051808303816000865af19150503d806000811461302f576040519150601f19603f3d011682016040523d82523d6000602084013e613034565b606091505b5091509150811561305657808060200190518101906130539190614c31565b93505b505050949350505050565b6040805160c0810182528481526020808201858152828401858152600060608501818152608086018281524260a08801908152601b548951602481018e90529651604488015294516064870152915160848601525160a48501525160c4808501919091528651808503909101815260e4909301865292820180516001600160e01b031663219f5d1760e01b17905293519193849384939092849283926001600160a01b039091169161311291614b8a565b6000604051808303816000865af19150503d806000811461314f576040519150601f19603f3d011682016040523d82523d6000602084013e613154565b606091505b5091509150811561317b578080602001905181019061317391906150fd565b919750955093505b50505093509350939050565b6040805160a0810182528381526001600160801b03838116602083019081526000838501818152606085018281524260808701908152601b549751602481018b90529451909516604485015290516064840152516084830152915160a48201529092839291839182916001600160a01b0390911690630c49ccbe9060c4016121ca565b6000808060001985870985870292508281108382030391505080600003613243576000841161323857600080fd5b508290049050610f9e565b80841161324f57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000816000036132ca57506001610d8a565b306001600160a01b038416036133195750306000908152600860209081526040808320601b546001600160a01b0390811685529252808320849055601c54909116825290208190556001610d8a565b601b54604080516001600160a01b039283166024820152604480820186905282518083039091018152606490910182526020810180516001600160e01b031663095ea7b360e01b179052905160009286169161337491614b8a565b6000604051808303816000865af19150503d80600081146133b1576040519150601f19603f3d011682016040523d82523d6000602084013e6133b6565b606091505b5050601c54604080516001600160a01b039283166024820152604480820188905282518083039091018152606490910182526020810180516001600160e01b031663095ea7b360e01b1790529051929350600092918716916134189190614b8a565b6000604051808303816000865af19150503d8060008114613455576040519150601f19603f3d011682016040523d82523d6000602084013e61345a565b606091505b50509050818015611b9c5750949350505050565b601b54604080516001600160a01b038781166024830152868116604483015262ffffff861660648301528481166084808401919091528351808403909101815260a490920183526020820180516001600160e01b03166309f56ab160e11b1790529151600093849384938493849392909216916134eb9190614b8a565b6000604051808303816000865af19150503d8060008114613528576040519150601f19603f3d011682016040523d82523d6000602084013e61352d565b606091505b50915091508161354957600080600094509450945050506136e1565b8080602001905181019061355d9190615134565b60408051600481526024810182526020810180516001600160e01b0316633850c7bd60e01b179052905191965060009182916001600160a01b038916916135a49190614b8a565b600060405180830381855afa9150503d80600081146135df576040519150601f19603f3d011682016040523d82523d6000602084013e6135e4565b606091505b509150915081613602576000806000965096509650505050506136e1565b808060200190518101906136169190615163565b505060408051600481526024810182526020810180516001600160e01b03166334324e9f60e21b1790529051949b506000955085946001600160a01b038e1694506136649350909150614b8a565b600060405180830381855afa9150503d806000811461369f576040519150601f19603f3d011682016040523d82523d6000602084013e6136a4565b606091505b5091509150816136c45760008060009850985098505050505050506136e1565b808060200190518101906136d891906151f5565b96505050505050505b9450945094915050565b6040805161ffff831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166332148f6760e01b179052905160009182916001600160a01b0386169161374391614b8a565b6000604051808303816000865af19150503d8060008114613780576040519150601f19603f3d011682016040523d82523d6000602084013e613785565b606091505b509095945050505050565b60008060008060006040518061016001604052808e6001600160a01b031681526020018d6001600160a01b031681526020018c62ffffff1681526020018960020b81526020018860020b81526020018b81526020018a81526020016000815260200160008152602001876001600160a01b03168152602001428152509050600080601b60009054906101000a90046001600160a01b03166001600160a01b03166388316456846040516024016138469190615212565b6040516020818303038152906040529060e01b6020820180516001600160e01b03838183161783525050505060405161387f9190614b8a565b6000604051808303816000865af19150503d80600081146138bc576040519150601f19603f3d011682016040523d82523d6000602084013e6138c1565b606091505b509150915081156138eb57808060200190518101906138e091906152d6565b929950909750955093505b50505098509850985098945050505050565b60125460009081906001600160a01b0386811663010000009092041614806139365750601254630100000090046001600160a01b031633145b8061394b5750601c546001600160a01b031633145b8061395e57506001600160a01b03851630145b8061397657506013546001600160a01b038581169116145b1561398657506000905080613a76565b61398e6141f4565b6018805462ffffff9290921663010000000265ffffff000000199092169190911790556139c56014546001600160a01b0316301090565b15613a2b57601854600281810b6301000000909204900b1315613a0a57601254620f4240906139f99062ffffff1685614bf0565b613a039190614c1d565b9150613a76565b601854600281810b6301000000909204900b1215613a26575060015b613a76565b601854600281810b6301000000909204900b1215613a5a57601254620f4240906139f99062ffffff1685614bf0565b601854600281810b6301000000909204900b1315613a76575060015b935093915050565b6001600160a01b03838116600090815260076020526040808220549285168252812054909190613aaf868686612c08565b6000613aba87610e81565b90506000613ac787610e81565b9050818015613ad35750805b613de6578115613b7c576000613b097f000000000000000000000000000000000000000000000000000000000000000085614c1d565b6001600160a01b038916600090815260076020526040902054613b4d907f000000000000000000000000000000000000000000000000000000000000000090614c1d565b613b579190614ef0565b905060005b81811015613b7557613b6d896144f1565b600101613b5c565b5050613de6565b8015613c18576001600160a01b038816600090815260076020526040812054613bc6907f000000000000000000000000000000000000000000000000000000000000000090614c1d565b613bf07f000000000000000000000000000000000000000000000000000000000000000087614c1d565b613bfa9190614ef0565b905060005b81811015613b7557613c108a6145e4565b600101613bff565b6000613c447f000000000000000000000000000000000000000000000000000000000000000088614c1d565b905060005b81811015613cc7576001600160a01b038a166000908152600c6020526040812054613c7690600190614ef0565b6001600160a01b038c166000908152600c602052604081208054929350909183908110613ca557613ca5614f16565b90600052602060002001549050613cbd8c8c83612cc4565b5050600101613c49565b50807f0000000000000000000000000000000000000000000000000000000000000000613d098b6001600160a01b031660009081526007602052604090205490565b613d139190614c1d565b613d3d7f000000000000000000000000000000000000000000000000000000000000000088614c1d565b613d479190614ef0565b1115613d5657613d56896145e4565b80613d817f000000000000000000000000000000000000000000000000000000000000000086614c1d565b7f0000000000000000000000000000000000000000000000000000000000000000613dc18b6001600160a01b031660009081526007602052604090205490565b613dcb9190614c1d565b613dd59190614ef0565b1115613de457613de4886144f1565b505b506001979650505050505050565b6001600160a01b038216613e1b57604051636edaef2f60e11b815260040160405180910390fd5b601454604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b179052905160009283926001600160a01b0390911691613e749190614b8a565b600060405180830381855afa9150503d8060008114613eaf576040519150601f19603f3d011682016040523d82523d6000602084013e613eb4565b606091505b509150915081613ec45750505050565b600081806020019051810190613eda9190614c31565b905060006005548286613eed9190614bf0565b613ef79190614c1d565b601454604080516001600160a01b038a81166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291519394506000939190921691613f5791614b8a565b6000604051808303816000865af19150503d8060008114613f94576040519150601f19603f3d011682016040523d82523d6000602084013e613f99565b606091505b50509050801561146557604080516001600160a01b0389168152602081018490527f289360176646a5f99cb4b6300628426dca46b723f40db3c04449d6ed1745a0e7910160405180910390a150505050505050565b6001600160a01b0381166000908152600c6020526040812054905b818110156110165761401a836145e4565b600101614009565b6001600160a01b038116600090815260076020526040812054614066907f000000000000000000000000000000000000000000000000000000000000000090614c1d565b90506000614089836001600160a01b03166000908152600c602052604090205490565b905060005b6140988284614ef0565b8110156116e1576140a8846144f1565b60010161408e565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106140ef5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831061411b576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061413957662386f26fc10000830492506010015b6305f5e1008310614151576305f5e100830492506008015b612710831061416557612710830492506004015b60648310614177576064830492506002015b600a8310610d8a5760010192915050565b6000828152600b60205260409020546bffffffffffffffffffffffff8211156141c457604051633f2cd0e360e21b815260040160405180910390fd5b6000928352600b60205260409092206001600160a01b039290921660a09190911b6001600160a01b031916019055565b600061420a6013546001600160a01b0316151590565b614218575060185460020b90565b60135460408051600481526024810182526020810180516001600160e01b0316633850c7bd60e01b179052905160009283926001600160a01b03909116916142609190614b8a565b600060405180830381855afa9150503d806000811461429b576040519150601f19603f3d011682016040523d82523d6000602084013e6142a0565b606091505b5091509150816142b757505060185460020b919050565b6000806000838060200190518101906142d09190615163565b50506019549397509195509350610708925082916142ef915042614ef0565b63ffffffff16101561430657509195945050505050565b604080516002808252606082018352600092602083019080368337019050509050818160008151811061433b5761433b614f16565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061436a5761436a614f16565b63ffffffff9092166020928302919091019091015260135460405160009182916001600160a01b039091169063883bdbfd906143aa908690602401615314565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516143e39190614b8a565b600060405180830381855afa9150503d806000811461441e576040519150601f19603f3d011682016040523d82523d6000602084013e614423565b606091505b50915091508161443b57509498975050505050505050565b60008180602001905181019061445191906153ea565b50905060008160008151811061446957614469614f16565b60200260200101518260018151811061448457614484614f16565b602002602001015161449691906154b6565b90506144a863ffffffff8716826154e3565b985060008160060b1280156144ce57506144c863ffffffff871682615518565b60060b15155b156144e157886144dd8161553a565b9950505b50969a9950505050505050505050565b6001600160a01b03811661451857604051634e46966960e11b815260040160405180910390fd5b6000614538600154600160801b81046001600160801b0390811691161490565b61454d576145466001614665565b90506145a2565b60066000815461455c9061555d565b909155506006546001016145835760405163303b682f60e01b815260040160405180910390fd5b60065461459f906ec097ce7bc90715b34b9f1000000000614f03565b90505b6000818152600b60205260409020546001600160a01b031680156145d95760405163119b4fd360e11b815260040160405180910390fd5b611016818484612cc4565b6001600160a01b03811661460b57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600c60205260408120805461463190600190614ef0565b8154811061464157614641614f16565b9060005260206000200154905061465a82600083612cc4565b610f646001826146d5565b80546000906001600160801b03600160801b820481169116810361469c576040516375e52f4f60e01b815260040160405180910390fd5b600019016001600160801b039081166000818152600185016020526040812080549190558454909216600160801b909102179092555090565b81546001600160801b038082166000190191600160801b900481169082160361471157604051638acb5f2760e01b815260040160405180910390fd5b6001600160801b0316600081815260018401602052604090209190915581546001600160801b031916179055565b8015158114611eb157600080fd5b60006020828403121561475f57600080fd5b8135610f9e8161473f565b6001600160e01b031981168114611eb157600080fd5b60006020828403121561479257600080fd5b8135610f9e8161476a565b6001600160a01b0381168114611eb157600080fd5b6000602082840312156147c457600080fd5b8135610f9e8161479d565b60005b838110156147ea5781810151838201526020016147d2565b50506000910152565b6000815180845261480b8160208601602086016147cf565b601f01601f19169290920160200192915050565b602081526000610f9e60208301846147f3565b60006020828403121561484457600080fd5b5035919050565b6000806040838503121561485e57600080fd5b82356148698161479d565b946020939093013593505050565b60008060006060848603121561488c57600080fd5b83356148978161479d565b925060208401356148a78161479d565b929592945050506040919091013590565b6001600160801b0381168114611eb157600080fd5b6000602082840312156148df57600080fd5b8135610f9e816148b8565b600080604083850312156148fd57600080fd5b82356149088161479d565b915060208301356149188161473f565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561495b5783518352928401929184019160010161493f565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156149a6576149a6614967565b604052919050565b600080600080608085870312156149c457600080fd5b84356149cf8161479d565b93506020858101356149e08161479d565b935060408601359250606086013567ffffffffffffffff80821115614a0457600080fd5b818801915088601f830112614a1857600080fd5b813581811115614a2a57614a2a614967565b614a3c601f8201601f1916850161497d565b91508082528984828501011115614a5257600080fd5b808484018584013760008482840101525080935050505092959194509250565b60ff81168114611eb157600080fd5b600080600080600080600060e0888a031215614a9c57600080fd5b8735614aa78161479d565b96506020880135614ab78161479d565b955060408801359450606088013593506080880135614ad581614a72565b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215614b0557600080fd5b8235614b108161479d565b915060208301356149188161479d565b8060020b8114611eb157600080fd5b600060208284031215614b4157600080fd5b8135610f9e81614b20565b60008060408385031215614b5f57600080fd5b50508035926020909101359150565b60008151614b808185602086016147cf565b9290920192915050565b60008251614b9c8184602087016147cf565b9190910192915050565b600181811c90821680614bba57607f821691505b6020821081036123ab57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610d8a57610d8a614bda565b634e487b7160e01b600052601260045260246000fd5b600082614c2c57614c2c614c07565b500490565b600060208284031215614c4357600080fd5b5051919050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090614c7d908301846147f3565b9695505050505050565b600060208284031215614c9957600080fd5b8151610f9e8161476a565b8054600090600181811c9080831680614cbe57607f831692505b60208084108203614cdf57634e487b7160e01b600052602260045260246000fd5b818015614cf35760018114614d0857614d34565b60ff1986168952841515850289019650614d34565b876000528160002060005b86811015614d2c5781548b820152908501908301614d13565b505084890196505b50505050505092915050565b747b226e616d65223a202257484f333333204e46542360581b81528551600090614d71816015850160208b016147cf565b7f222c226465736372697074696f6e223a224120636f6c6c656374696f6e206f66601591840191820152600160fd1b60358201528651614db8816036840160208b016147cf565b7f20706f7473206f66206c6971756964697479207468617420746f6b656e697a65603692909101918201527f7320646563656e7472616c697a656420726573657276652063757272656e637960568201527f206964656120666f722074686520495135302c20234552433333332e0000000060768201527f222c2265787465726e616c5f75726c223a2268747470733a2f2f77686f33333360928201526f173bba331791161134b6b0b3b2911d1160811b60b2820152614ee4614ed4614ece614e8d614e8760c286018b614ca4565b89614b6e565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a224381526e37b637b91116113b30b63ab2911d1160891b6020820152602f0190565b86614b6e565b63227d5d7d60e01b815260040190565b98975050505050505050565b81810381811115610d8a57610d8a614bda565b80820180821115610d8a57610d8a614bda565b634e487b7160e01b600052603260045260246000fd5b6001600160801b03818116838216019080821115614f4c57614f4c614bda565b5092915050565b6000610f9e8284614ca4565b6001600160801b03828116828216039080821115614f4c57614f4c614bda565b60008060408385031215614f9257600080fd5b505080516020909101519092909150565b60008160020b8360020b80614fba57614fba614c07565b627fffff19821460001982141615614fd457614fd4614bda565b90059392505050565b60008260020b8260020b028060020b9150808214614f4c57614f4c614bda565b600282810b9082900b03627fffff198112627fffff82131715610d8a57610d8a614bda565b60008160020b627fffff19810361503b5761503b614bda565b60000392915050565b600281810b9083900b01627fffff8113627fffff1982121715610d8a57610d8a614bda565b81546001600160a01b03168152610100810160018301546001600160a01b03808216602085015262ffffff60a092831c16604085015260028086015460608601526003860154918216608086015281831c810b9285019290925260b81c900b60c083015260048301546001600160801b031660e08301819052614f4c565b634e487b7160e01b600052603160045260246000fd5b60008060006060848603121561511257600080fd5b835161511d816148b8565b602085015160409095015190969495509392505050565b60006020828403121561514657600080fd5b8151610f9e8161479d565b805161ffff811681146111a557600080fd5b600080600080600080600060e0888a03121561517e57600080fd5b87516151898161479d565b602089015190975061519a81614b20565b95506151a860408901615151565b94506151b660608901615151565b93506151c460808901615151565b925060a08801516151d481614a72565b60c08901519092506151e58161473f565b8091505092959891949750929550565b60006020828403121561520757600080fd5b8151610f9e81614b20565b81516001600160a01b031681526101608101602083015161523e60208401826001600160a01b03169052565b506040830151615255604084018262ffffff169052565b50606083015161526a606084018260020b9052565b50608083015161527f608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401516152c5828501826001600160a01b03169052565b505061014092830151919092015290565b600080600080608085870312156152ec57600080fd5b8451935060208501516152fe816148b8565b6040860151606090960151949790965092505050565b6020808252825182820181905260009190848201906040850190845b8181101561495b57835163ffffffff1683529284019291840191600101615330565b600067ffffffffffffffff82111561536c5761536c614967565b5060051b60200190565b600082601f83011261538757600080fd5b8151602061539c61539783615352565b61497d565b82815260059290921b840181019181810190868411156153bb57600080fd5b8286015b848110156153df5780516153d28161479d565b83529183019183016153bf565b509695505050505050565b600080604083850312156153fd57600080fd5b825167ffffffffffffffff8082111561541557600080fd5b818501915085601f83011261542957600080fd5b8151602061543961539783615352565b82815260059290921b8401810191818101908984111561545857600080fd5b948201945b838610156154865785518060060b81146154775760008081fd5b8252948201949082019061545d565b9188015191965090935050508082111561549f57600080fd5b506154ac85828601615376565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff82131715610d8a57610d8a614bda565b60008160060b8360060b806154fa576154fa614c07565b667fffffffffffff19821460001982141615614fd457614fd4614bda565b60008260060b8061552b5761552b614c07565b808360060b0791505092915050565b60008160020b627fffff19810361555357615553614bda565b6000190192915050565b60006001820161556f5761556f614bda565b506001019056fea264697066735822122069487e0347bf5b69b5a87dbc77908d5664fad9d13b7ee437e4a2e8ac0a61c17864736f6c63430008140033ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef000000000000000000000000cdf74bff7c62c72775a2cdb83dbc0a1d4866703a000000000000000000000000a6afd4d1226169db19432cf6f26f66a219b9b159

Deployed Bytecode

0x6080604052600436106103a55760003560e01c80637a8a1113116101e7578063b88d4fde1161010d578063dd62ed3e116100a0578063e995016c1161006f578063e995016c14610c2b578063f2fde38b14610c4b578063f780bc1a14610c6b578063fe85b42b14610c8b57600080fd5b8063dd62ed3e14610b78578063dd63769914610bb0578063dfabc03314610bd0578063e985e9c514610bf057600080fd5b8063c87b56dd116100dc578063c87b56dd14610afe578063cd4bb50a14610b1e578063d505accf14610b38578063d96ca0b914610b5857600080fd5b8063b88d4fde14610a82578063c5ab3ba614610aa2578063c6e672b914610ab7578063c77cd5ac14610ad757600080fd5b806390fcdb3611610185578063a9059cbb11610154578063a9059cbb146109df578063ab01b469146109ff578063b1ab931714610a1f578063b3f9ea3414610a4c57600080fd5b806390fcdb361461095657806395d89b4114610976578063976a84351461098b578063a22cb465146109bf57600080fd5b8063853828b6116101c1578063853828b6146108ee57806389fb4c66146109035780638a696e50146109185780638da5cb5b1461093857600080fd5b80637a8a1113146108995780637ecebe00146108b95780638129fc1c146108e657600080fd5b806323b872dd116102cc5780634f02c4201161026a5780636e8f624b116102395780636e8f624b1461080457806370a0823114610827578063715018a6146108545780637541f41c1461086957600080fd5b80634f02c420146106f35780635eed923e146107095780636352211e146107cf5780636c0360eb146107ef57600080fd5b806342842e0e116102a657806342842e0e146106795780634524c4ab1461069957806349fa7fd8146106b35780634d966072146106d357600080fd5b806323b872dd146105fe578063313ce5671461061e5780633644e5151461066457600080fd5b8063095ea7b311610344578063158ef93e11610313578063158ef93e14610592578063173865ad146105b257806318160ddd146105d25780631bc392ae146105e857600080fd5b8063095ea7b31461050d57806309674eb01461052d57806309f0ef651461054257806313e7c9d81461056257600080fd5b8063045b7dca11610380578063045b7dca14610453578063065e53601461046957806306fdde031461049d578063081812fc146104bf57600080fd5b8062a5a777146103ba57806301ffc9a7146103da57806302519da31461040f57600080fd5b366103b5576103b334610ca1565b005b600080fd5b3480156103c657600080fd5b506103b36103d536600461474d565b610d3e565b3480156103e657600080fd5b506103fa6103f5366004614780565b610d59565b60405190151581526020015b60405180910390f35b34801561041b57600080fd5b5061044561042a3660046147b2565b6001600160a01b031660009081526007602052604090205490565b604051908152602001610406565b34801561045f57600080fd5b5061044560115481565b34801561047557600080fd5b5060185461048a906301000000900460020b81565b60405160029190910b8152602001610406565b3480156104a957600080fd5b506104b2610d90565b604051610406919061481f565b3480156104cb57600080fd5b506104f56104da366004614832565b6009602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610406565b34801561051957600080fd5b506103fa61052836600461484b565b610e1e565b34801561053957600080fd5b50610445610e57565b34801561054e57600080fd5b506103fa61055d3660046147b2565b610e81565b34801561056e57600080fd5b506103fa61057d3660046147b2565b600f6020526000908152604090205460ff1681565b34801561059e57600080fd5b506013546001600160a01b031615156103fa565b3480156105be57600080fd5b506103b36105cd366004614832565b610eb3565b3480156105de57600080fd5b5061044560055481565b3480156105f457600080fd5b5061044560195481565b34801561060a57600080fd5b506103fa610619366004614877565b610f68565b34801561062a57600080fd5b506106527f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff9091168152602001610406565b34801561067057600080fd5b50610445610fa5565b34801561068557600080fd5b506103b3610694366004614877565b610ffb565b3480156106a557600080fd5b5060185461048a9060020b81565b3480156106bf57600080fd5b506103b36106ce3660046148cd565b61101b565b3480156106df57600080fd5b506103fa6106ee36600461484b565b6110b3565b3480156106ff57600080fd5b5061044560065481565b34801561071557600080fd5b5060135460145460155460165460175461076e946001600160a01b03908116948082169462ffffff600160a01b928390041694909392811692918104600290810b92600160b81b909204900b906001600160801b031688565b604080516001600160a01b03998a168152978916602089015262ffffff90961695870195909552606086019390935294166080840152600293840b60a084015290920b60c08201526001600160801b0390911660e082015261010001610406565b3480156107db57600080fd5b506104f56107ea366004614832565b611140565b3480156107fb57600080fd5b506104b26111aa565b34801561081057600080fd5b506104456ec097ce7bc90715b34b9f100000000081565b34801561083357600080fd5b506104456108423660046147b2565b60076020526000908152604090205481565b34801561086057600080fd5b506103b36111b7565b34801561087557600080fd5b506012546108859062ffffff1681565b60405162ffffff9091168152602001610406565b3480156108a557600080fd5b50601b546104f5906001600160a01b031681565b3480156108c557600080fd5b506104456108d43660046147b2565b600e6020526000908152604090205481565b6103b36111cb565b3480156108fa57600080fd5b506103b36112f4565b34801561090f57600080fd5b50600554610445565b34801561092457600080fd5b506103b361093336600461474d565b61146e565b34801561094457600080fd5b506000546001600160a01b03166104f5565b34801561096257600080fd5b50601c546104f5906001600160a01b031681565b34801561098257600080fd5b506104b2611486565b34801561099757600080fd5b506104457f0000000000000000000000000000000000000000000000056bc75e2d6310000081565b3480156109cb57600080fd5b506103b36109da3660046148ea565b611493565b3480156109eb57600080fd5b506103fa6109fa36600461484b565b611526565b348015610a0b57600080fd5b506103b3610a1a3660046148ea565b61155a565b348015610a2b57600080fd5b50610a3f610a3a3660046147b2565b61158d565b6040516104069190614923565b348015610a5857600080fd5b50610445610a673660046147b2565b6001600160a01b03166000908152600c602052604090205490565b348015610a8e57600080fd5b506103b3610a9d3660046149ae565b6115f9565b348015610aae57600080fd5b50600654610445565b348015610ac357600080fd5b506103b3610ad23660046148ea565b6116e7565b348015610ae357600080fd5b506012546104f590630100000090046001600160a01b031681565b348015610b0a57600080fd5b506104b2610b19366004614832565b6116f9565b348015610b2a57600080fd5b506010546103fa9060ff1681565b348015610b4457600080fd5b506103b3610b53366004614a81565b6118a2565b348015610b6457600080fd5b506103fa610b73366004614877565b611ae5565b348015610b8457600080fd5b50610445610b93366004614af2565b600860209081526000928352604080842090915290825290205481565b348015610bbc57600080fd5b506103b3610bcb366004614877565b611ba5565b348015610bdc57600080fd5b506103b3610beb36600461484b565b611d8f565b348015610bfc57600080fd5b506103fa610c0b366004614af2565b600a60209081526000928352604080842090915290825290205460ff1681565b348015610c3757600080fd5b506103b3610c46366004614b2f565b611e54565b348015610c5757600080fd5b506103b3610c663660046147b2565b611e76565b348015610c7757600080fd5b50610a3f610c86366004614b4c565b611eb4565b348015610c9757600080fd5b50610445601a5481565b60408051600481526024810182526020810180516001600160e01b0316630d0e30db60e41b1790529051600091829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2918591610cf29190614b8a565b60006040518083038185875af1925050503d8060008114610d2f576040519150601f19603f3d011682016040523d82523d6000602084013e610d34565b606091505b5090949350505050565b610d46611f51565b6010805460ff1916911515919091179055565b60006001600160e01b0319821663caf91ff560e01b1480610d8a57506001600160e01b031982166301ffc9a760e01b145b92915050565b60038054610d9d90614ba6565b80601f0160208091040260200160405190810160405280929190818152602001828054610dc990614ba6565b8015610e165780601f10610deb57610100808354040283529160200191610e16565b820191906000526020600020905b815481529060010190602001808311610df957829003601f168201915b505050505081565b6000610e2982611f7e565b15610e3d57610e388383611d8f565b610e4e565b610e4783836110b3565b9050610d8a565b50600192915050565b6000610e7c6001546001600160801b03808216600160801b9092048116919091031690565b905090565b60006001600160a01b0382161580610d8a5750506001600160a01b03166000908152600d602052604090205460ff1690565b610ebb611f51565b30600090815260076020526040902054600390610ed9906002614bf0565b610ee39190614c1d565b811115610f2d5760405162461bcd60e51b8152602060048201526013602482015272616d6f756e7420697320746f6f206c6172676560681b60448201526064015b60405180910390fd5b6000610f3882611fa2565b90508015610f645730600090815260076020526040902054610f6490610f5f600284614c1d565b611fbe565b5050565b6000610f7382611f7e565b15610f8857610f83848484611ba5565b610f9a565b610f93848484611ae5565b9050610f9e565b5060015b9392505050565b60007f00000000000000000000000000000000000000000000000000000000000000014614610fd657610e7c61204e565b507f97aa1e46215350a0a115551c891f3a0dd44d08039b451b77646325a7a674278990565b611016838383604051806020016040528060008152506115f9565b505050565b611023611f51565b6017546001600160801b03908116908216111561107b5760405162461bcd60e51b81526020600482015260166024820152756c697175696469747920697320746f6f206c6172676560501b6044820152606401610f24565b6001600160801b0381161561109357611093816120e8565b6015546012546110169190630100000090046001600160a01b0316612159565b60006001600160a01b0383166110dc57604051635461585f60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b6000818152600b60205260409020546001600160a01b031661116182611f7e565b61117e576040516307ed98ed60e31b815260040160405180910390fd5b6001600160a01b0381166111a55760405163c5723b5160e01b815260040160405180910390fd5b919050565b601d8054610d9d90614ba6565b6111bf611f51565b6111c96000612274565b565b6111d3611f51565b73c36442b4a4522e871399cd717abdd847ab11fe8873e592427a0aece92de3edee1f18e0157c05861564341561120e5761120c34610ca1565b505b600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2301061123e576c39bc2ab9629fb800000000000061124c565b6b046f1de7bc353a00000000005b6cffffffffffffffffffffffffff1690506000611268826122c4565b905060006112746123b1565b9050818110156112bf5760405162461bcd60e51b81526020600482015260166024820152757765746820616d6f756e7420697320746f6f206c6f7760501b6044820152606401610f24565b6112e583610bb873c02aaa39b223fe8d0a0e5c4f27ead9083c756cc285603c8a8a61247a565b6112ed612952565b5050505050565b6112fc611f51565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b1790529051600091829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29161135b91614b8a565b600060405180830381855afa9150503d8060008114611396576040519150601f19603f3d011682016040523d82523d6000602084013e61139b565b606091505b5091509150816113a9575050565b6000818060200190518101906113bf9190614c31565b60408051336024820152604480820184905282518083039091018152606490910182526020810180516001600160e01b031663a9059cbb60e01b179052905191925060009173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29161142391614b8a565b6000604051808303816000865af19150503d8060008114611460576040519150601f19603f3d011682016040523d82523d6000602084013e611465565b606091505b50505050505050565b6040516282b42960e81b815260040160405180910390fd5b60048054610d9d90614ba6565b6001600160a01b0382166114ba5760405163ccea9e6f60e01b815260040160405180910390fd5b336000818152600a602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60006001600160a01b03831661154f57604051634e46966960e11b815260040160405180910390fd5b610f9e3384846129fe565b611562611f51565b6001600160a01b03919091166000908152600f60205260409020805460ff1916911515919091179055565b6001600160a01b0381166000908152600c60209081526040918290208054835181840281018401909452808452606093928301828280156115ed57602002820191906000526020600020905b8154815260200190600101908083116115d9575b50505050509050919050565b61160282611f7e565b61161f576040516307ed98ed60e31b815260040160405180910390fd5b61162a848484610f68565b506001600160a01b0383163b158015906116c35750604051630a85bd0160e11b808252906001600160a01b0385169063150b7a0290611673903390899088908890600401614c4a565b6020604051808303816000875af1158015611692573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b69190614c87565b6001600160e01b03191614155b156116e157604051633da6393160e01b815260040160405180910390fd5b50505050565b6116ef611f51565b610f648282612b06565b606060008260405160200161171091815260200190565b6040516020818303038152906040528051906020012060f81c905060608060408360ff161161177c5760405180604001604052806005815260200164302e706e6760d81b81525091506040518060400160405280600381526020016214995960ea1b815250905061185d565b60808360ff16116117cb5760405180604001604052806005815260200164312e706e6760d81b815250915060405180604001604052806004815260200163426c756560e01b815250905061185d565b60c08360ff161161181b5760405180604001604052806005815260200164322e706e6760d81b81525091506040518060400160405280600581526020016423b932b2b760d91b815250905061185d565b60405180604001604052806005815260200164332e706e6760d81b815250915060405180604001604052806006815260200165507572706c6560d01b81525090505b61186685612b75565b611871601154612b75565b601d8484604051602001611889959493929190614d40565b6040516020818303038152906040529350505050919050565b428410156118c3576040516305787bdf60e01b815260040160405180910390fd5b6118cc85611f7e565b156118ea576040516303e7c1bd60e31b815260040160405180910390fd5b6001600160a01b03861661191157604051635461585f60e01b815260040160405180910390fd5b6000600161191d610fa5565b6001600160a01b038a81166000818152600e602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611a29573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580611a5e5750876001600160a01b0316816001600160a01b031614155b15611a7c57604051632057875960e21b815260040160405180910390fd5b6001600160a01b0390811660009081526008602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60006001600160a01b038416611b0e57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038316611b3557604051634e46966960e11b815260040160405180910390fd5b6001600160a01b03841660009081526008602090815260408083203384529091529020546000198114611b9157611b6c8382614ef0565b6001600160a01b03861660009081526008602090815260408083203384529091529020555b611b9c8585856129fe565b95945050505050565b6001600160a01b038316611bcc57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b038216611bf357604051634e46966960e11b815260040160405180910390fd5b6000818152600b60205260409020546001600160a01b03848116911614611c2c576040516282b42960e81b815260040160405180910390fd5b60105460ff1615611cb5576000546001600160a01b0316331480611c615750601254630100000090046001600160a01b031633145b80611c7b5750336000908152600f602052604090205460ff165b611cb55760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd08185b1b1bddd95960aa1b6044820152606401610f24565b336001600160a01b03841614801590611cf257506001600160a01b0383166000908152600a6020908152604080832033845290915290205460ff16155b8015611d1557506000818152600960205260409020546001600160a01b03163314155b15611d32576040516282b42960e81b815260040160405180910390fd5b611d3b82610e81565b15611d5957604051635ce7539760e01b815260040160405180910390fd5b611d8483837f0000000000000000000000000000000000000000000000056bc75e2d63100000612c08565b611016838383612cc4565b6000818152600b60205260409020546001600160a01b0316338114801590611ddb57506001600160a01b0381166000908152600a6020908152604080832033845290915290205460ff16155b15611df8576040516282b42960e81b815260040160405180910390fd5b60008281526009602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b611e5c611f51565b6018805462ffffff191662ffffff92909216919091179055565b611e7e611f51565b6001600160a01b038116611ea857604051631e4fbdf760e01b815260006004820152602401610f24565b611eb181612274565b50565b606060008267ffffffffffffffff811115611ed157611ed1614967565b604051908082528060200260200182016040528015611efa578160200160208202803683370190505b509050835b611f098486614f03565b811015611f4957611f1b600182612e9c565b82611f268784614ef0565b81518110611f3657611f36614f16565b6020908102919091010152600101611eff565b509392505050565b6000546001600160a01b031633146111c95760405163118cdaa760e01b8152336004820152602401610f24565b60006ec097ce7bc90715b34b9f100000000082118015610d8a575050600019141590565b601454600090610d8a9030906001600160a01b03168185612f07565b60145430906001600160a01b0316838382841115611fdb57919291905b6000611fed6013600201548484613061565b909450925090506001600160801b0381161561146557601780548291906000906120219084906001600160801b0316614f2c565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555050505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60036040516120809190614f53565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6000806120fa60136002015484613187565b91509150600082118061210d5750600081115b1561101657601780548491906000906121309084906001600160801b0316614f5f565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505050565b604080516080810182528381526001600160a01b03838116602083019081526001600160801b0383850181815260608501828152601b549651602481018a905293518516604485015290518216606484015251166084820152600093849392849283929091169063fc6f78659060a4015b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516122039190614b8a565b6000604051808303816000865af19150503d8060008114612240576040519150601f19603f3d011682016040523d82523d6000602084013e612245565b606091505b5091509150811561226a57808060200190518101906122649190614f7f565b90955093505b5050509250929050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b306000908152600760205260408120546001600160801b036001600160a01b038416116123485760006123006001600160a01b03851680614bf0565b905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc230106123315761232c600160c01b838361320a565b612340565b6123408183600160c01b61320a565b9250506123ab565b60006123676001600160a01b038516806801000000000000000061320a565b905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2301061239857612393600160801b838361320a565b6123a7565b6123a78183600160801b61320a565b9250505b50919050565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17905290516000918291829173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916124139190614b8a565b600060405180830381855afa9150503d806000811461244e576040519150601f19603f3d011682016040523d82523d6000602084013e612453565b606091505b5091509150811561247557808060200190518101906124729190614c31565b92505b505090565b612482611f51565b6013546001600160a01b0316156124d15760405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606401610f24565b601b80546001600160a01b03199081166001600160a01b0385811691909117909255601c80548216848416179055601480548884166001600160b81b03199091168117600160a01b62ffffff8c16021790915560168054909216928a16929092179055306000818152600760205260409020549091879190879084111561255757919291905b612563846000196132b8565b50612570836000196132b8565b50600061257f85858d8f61346e565b6018805462ffffff90931663010000000265ffffff0000001990931692909217909155601380546001600160a01b039093166001600160a01b0319909316831790559150158015906125d557508060020b600014155b61261a5760405162461bcd60e51b81526020600482015260166024820152751a5b9a5d1a585b1a5e99481c1bdbdb0819985a5b195960521b6044820152606401610f24565b6018805462ffffff198116630100000090910462ffffff161790556014546001600160a01b031630101561272357601854819061265b90829060020b614fa3565b6126659190614fdd565b6016805462ffffff92909216600160a01b0262ffffff60a01b19909216919091179055601854600060029190910b12156126d857601680548291906014906126b8908490600160a01b900460020b614ffd565b92506101000a81548162ffffff021916908360020b62ffffff1602179055505b80806126e7620d89e719615022565b6126f19190614fa3565b6126fb9190614fdd565b6016805462ffffff92909216600160b81b0262ffffff60b81b199092169190911790556127f0565b601854819061273690829060020b614fa3565b6127409190614fdd565b6016805462ffffff92909216600160b81b0262ffffff60b81b19909216919091179055601854600060029190910b13156127b35760168054829190601790612793908490600160b81b900460020b615044565b92506101000a81548162ffffff021916908360020b62ffffff1602179055505b806127c281620d89e719614fa3565b6127cc9190614fdd565b6016805462ffffff92909216600160a01b0262ffffff60a01b199092169190911790555b61ffff88161561286457601354600090612813906001600160a01b03168a6136eb565b9050806128625760405162461bcd60e51b815260206004820152601e60248201527f696e697469616c697a65206f62736572766174696f6e73206661696c656400006044820152606401610f24565b505b60165461289190869086908e9087908790600160a01b8104600290810b91600160b81b9004900b30613790565b5050601780546001600160801b0319166001600160801b039290921691909117905560158190556000036129075760405162461bcd60e51b815260206004820152601b60248201527f696e697469616c697a65206c6971756964697479206661696c656400000000006044820152606401610f24565b426019556040517fc6cb858e754b4efdad8980cee030a8e8725c4e6e690d9b77733a89b5dd5601a19061293c90601390615069565b60405180910390a1505050505050505050505050565b61297173a7fd99748ce527eadc0bdac60cba8a4ef4090f7c600161155a565b6129907382c0fdfa607d9afbe82db5cbd103d1a4d5a43b77600161155a565b6129af735b93a825829f4b7b5177c259edc22b63d6e4e380600161155a565b601b546129c6906001600160a01b0316600161155a565b601c546129dd906001600160a01b0316600161155a565b6013546129f4906001600160a01b0316600161155a565b6111c96001610d3e565b6000806000612a0e8686866138fd565b915091508015612a7f57612a2486600086613a7e565b50612a2f8585613df4565b8360056000828254612a419190614ef0565b90915550506040518481527f77dd5e627769f9468b3e9ef3f0d14fdf2cca856af36dd6aa591989bdf3957685906020015b60405180910390a1612afa565b8115612aed57612a998686612a948588614ef0565b613a7e565b50612aa5863084613a7e565b5081601a6000828254612ab89190614f03565b90915550506040518281527fed9d4923888165f7fbf184c0010cb4a535efc8f5ac2b5ec687473e903997155290602001612a72565b612af8868686613a7e565b505b50600195945050505050565b6001600160a01b038216612b2d5760405163a41e3d3f60e01b815260040160405180910390fd5b8015612b4157612b3c82613fee565b612b4a565b612b4a82614022565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b60606000612b82836140b0565b600101905060008167ffffffffffffffff811115612ba257612ba2614967565b6040519080825280601f01601f191660200182016040528015612bcc576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612bd657509392505050565b6001600160a01b038316612c33578060056000828254612c289190614f03565b90915550612c619050565b6001600160a01b03831660009081526007602052604081208054839290612c5b908490614ef0565b90915550505b6001600160a01b03808316600081815260076020526040908190208054850190555190918516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612cb79085815260200190565b60405180910390a3505050565b6001600160a01b03831615612dcf57600081815260096020908152604080832080546001600160a01b03191690556001600160a01b0386168352600c90915281208054612d1390600190614ef0565b81548110612d2357612d23614f16565b90600052602060002001549050818114612d90576000828152600b602052604081205460a01c6001600160a01b0386166000908152600c602052604090208054919250839183908110612d7857612d78614f16565b600091825260209091200155612d8e8282614188565b505b6001600160a01b0384166000908152600c60205260409020805480612db757612db76150e7565b60019003818190600052602060002001600090559055505b6001600160a01b03821615612e46576000818152600b6020908152604080832080546001600160a01b0319166001600160a01b038716908101909155808452600c83529083208054600181810183558286529385200185905592529054612e41918391612e3c9190614ef0565b614188565b612e56565b6000818152600b60205260408120555b80826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b6000612ec083546001600160801b03808216600160801b9092048116919091031690565b8210612edf5760405163580821e760e01b815260040160405180910390fd5b5081546001600160801b03908116820116600090815260018301602052604090205492915050565b60408051610100810182526001600160a01b03868116808352868216602080850191825260145462ffffff600160a01b909104811686880190815289861660608801908152426080890190815260a089018b8152600060c08b0181815260e08c01828152601c548e51602481019c909c5299518c1660448c0152955190961660648a0152925189166084890152905160a48801525160c4870152915160e48601525185166101048086019190915287518086039091018152610124909401875290830180516001600160e01b031663414bf38960e01b179052945185938493921691612ff291614b8a565b6000604051808303816000865af19150503d806000811461302f576040519150601f19603f3d011682016040523d82523d6000602084013e613034565b606091505b5091509150811561305657808060200190518101906130539190614c31565b93505b505050949350505050565b6040805160c0810182528481526020808201858152828401858152600060608501818152608086018281524260a08801908152601b548951602481018e90529651604488015294516064870152915160848601525160a48501525160c4808501919091528651808503909101815260e4909301865292820180516001600160e01b031663219f5d1760e01b17905293519193849384939092849283926001600160a01b039091169161311291614b8a565b6000604051808303816000865af19150503d806000811461314f576040519150601f19603f3d011682016040523d82523d6000602084013e613154565b606091505b5091509150811561317b578080602001905181019061317391906150fd565b919750955093505b50505093509350939050565b6040805160a0810182528381526001600160801b03838116602083019081526000838501818152606085018281524260808701908152601b549751602481018b90529451909516604485015290516064840152516084830152915160a48201529092839291839182916001600160a01b0390911690630c49ccbe9060c4016121ca565b6000808060001985870985870292508281108382030391505080600003613243576000841161323857600080fd5b508290049050610f9e565b80841161324f57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000816000036132ca57506001610d8a565b306001600160a01b038416036133195750306000908152600860209081526040808320601b546001600160a01b0390811685529252808320849055601c54909116825290208190556001610d8a565b601b54604080516001600160a01b039283166024820152604480820186905282518083039091018152606490910182526020810180516001600160e01b031663095ea7b360e01b179052905160009286169161337491614b8a565b6000604051808303816000865af19150503d80600081146133b1576040519150601f19603f3d011682016040523d82523d6000602084013e6133b6565b606091505b5050601c54604080516001600160a01b039283166024820152604480820188905282518083039091018152606490910182526020810180516001600160e01b031663095ea7b360e01b1790529051929350600092918716916134189190614b8a565b6000604051808303816000865af19150503d8060008114613455576040519150601f19603f3d011682016040523d82523d6000602084013e61345a565b606091505b50509050818015611b9c5750949350505050565b601b54604080516001600160a01b038781166024830152868116604483015262ffffff861660648301528481166084808401919091528351808403909101815260a490920183526020820180516001600160e01b03166309f56ab160e11b1790529151600093849384938493849392909216916134eb9190614b8a565b6000604051808303816000865af19150503d8060008114613528576040519150601f19603f3d011682016040523d82523d6000602084013e61352d565b606091505b50915091508161354957600080600094509450945050506136e1565b8080602001905181019061355d9190615134565b60408051600481526024810182526020810180516001600160e01b0316633850c7bd60e01b179052905191965060009182916001600160a01b038916916135a49190614b8a565b600060405180830381855afa9150503d80600081146135df576040519150601f19603f3d011682016040523d82523d6000602084013e6135e4565b606091505b509150915081613602576000806000965096509650505050506136e1565b808060200190518101906136169190615163565b505060408051600481526024810182526020810180516001600160e01b03166334324e9f60e21b1790529051949b506000955085946001600160a01b038e1694506136649350909150614b8a565b600060405180830381855afa9150503d806000811461369f576040519150601f19603f3d011682016040523d82523d6000602084013e6136a4565b606091505b5091509150816136c45760008060009850985098505050505050506136e1565b808060200190518101906136d891906151f5565b96505050505050505b9450945094915050565b6040805161ffff831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166332148f6760e01b179052905160009182916001600160a01b0386169161374391614b8a565b6000604051808303816000865af19150503d8060008114613780576040519150601f19603f3d011682016040523d82523d6000602084013e613785565b606091505b509095945050505050565b60008060008060006040518061016001604052808e6001600160a01b031681526020018d6001600160a01b031681526020018c62ffffff1681526020018960020b81526020018860020b81526020018b81526020018a81526020016000815260200160008152602001876001600160a01b03168152602001428152509050600080601b60009054906101000a90046001600160a01b03166001600160a01b03166388316456846040516024016138469190615212565b6040516020818303038152906040529060e01b6020820180516001600160e01b03838183161783525050505060405161387f9190614b8a565b6000604051808303816000865af19150503d80600081146138bc576040519150601f19603f3d011682016040523d82523d6000602084013e6138c1565b606091505b509150915081156138eb57808060200190518101906138e091906152d6565b929950909750955093505b50505098509850985098945050505050565b60125460009081906001600160a01b0386811663010000009092041614806139365750601254630100000090046001600160a01b031633145b8061394b5750601c546001600160a01b031633145b8061395e57506001600160a01b03851630145b8061397657506013546001600160a01b038581169116145b1561398657506000905080613a76565b61398e6141f4565b6018805462ffffff9290921663010000000265ffffff000000199092169190911790556139c56014546001600160a01b0316301090565b15613a2b57601854600281810b6301000000909204900b1315613a0a57601254620f4240906139f99062ffffff1685614bf0565b613a039190614c1d565b9150613a76565b601854600281810b6301000000909204900b1215613a26575060015b613a76565b601854600281810b6301000000909204900b1215613a5a57601254620f4240906139f99062ffffff1685614bf0565b601854600281810b6301000000909204900b1315613a76575060015b935093915050565b6001600160a01b03838116600090815260076020526040808220549285168252812054909190613aaf868686612c08565b6000613aba87610e81565b90506000613ac787610e81565b9050818015613ad35750805b613de6578115613b7c576000613b097f0000000000000000000000000000000000000000000000056bc75e2d6310000085614c1d565b6001600160a01b038916600090815260076020526040902054613b4d907f0000000000000000000000000000000000000000000000056bc75e2d6310000090614c1d565b613b579190614ef0565b905060005b81811015613b7557613b6d896144f1565b600101613b5c565b5050613de6565b8015613c18576001600160a01b038816600090815260076020526040812054613bc6907f0000000000000000000000000000000000000000000000056bc75e2d6310000090614c1d565b613bf07f0000000000000000000000000000000000000000000000056bc75e2d6310000087614c1d565b613bfa9190614ef0565b905060005b81811015613b7557613c108a6145e4565b600101613bff565b6000613c447f0000000000000000000000000000000000000000000000056bc75e2d6310000088614c1d565b905060005b81811015613cc7576001600160a01b038a166000908152600c6020526040812054613c7690600190614ef0565b6001600160a01b038c166000908152600c602052604081208054929350909183908110613ca557613ca5614f16565b90600052602060002001549050613cbd8c8c83612cc4565b5050600101613c49565b50807f0000000000000000000000000000000000000000000000056bc75e2d63100000613d098b6001600160a01b031660009081526007602052604090205490565b613d139190614c1d565b613d3d7f0000000000000000000000000000000000000000000000056bc75e2d6310000088614c1d565b613d479190614ef0565b1115613d5657613d56896145e4565b80613d817f0000000000000000000000000000000000000000000000056bc75e2d6310000086614c1d565b7f0000000000000000000000000000000000000000000000056bc75e2d63100000613dc18b6001600160a01b031660009081526007602052604090205490565b613dcb9190614c1d565b613dd59190614ef0565b1115613de457613de4886144f1565b505b506001979650505050505050565b6001600160a01b038216613e1b57604051636edaef2f60e11b815260040160405180910390fd5b601454604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b179052905160009283926001600160a01b0390911691613e749190614b8a565b600060405180830381855afa9150503d8060008114613eaf576040519150601f19603f3d011682016040523d82523d6000602084013e613eb4565b606091505b509150915081613ec45750505050565b600081806020019051810190613eda9190614c31565b905060006005548286613eed9190614bf0565b613ef79190614c1d565b601454604080516001600160a01b038a81166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291519394506000939190921691613f5791614b8a565b6000604051808303816000865af19150503d8060008114613f94576040519150601f19603f3d011682016040523d82523d6000602084013e613f99565b606091505b50509050801561146557604080516001600160a01b0389168152602081018490527f289360176646a5f99cb4b6300628426dca46b723f40db3c04449d6ed1745a0e7910160405180910390a150505050505050565b6001600160a01b0381166000908152600c6020526040812054905b818110156110165761401a836145e4565b600101614009565b6001600160a01b038116600090815260076020526040812054614066907f0000000000000000000000000000000000000000000000056bc75e2d6310000090614c1d565b90506000614089836001600160a01b03166000908152600c602052604090205490565b905060005b6140988284614ef0565b8110156116e1576140a8846144f1565b60010161408e565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106140ef5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831061411b576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061413957662386f26fc10000830492506010015b6305f5e1008310614151576305f5e100830492506008015b612710831061416557612710830492506004015b60648310614177576064830492506002015b600a8310610d8a5760010192915050565b6000828152600b60205260409020546bffffffffffffffffffffffff8211156141c457604051633f2cd0e360e21b815260040160405180910390fd5b6000928352600b60205260409092206001600160a01b039290921660a09190911b6001600160a01b031916019055565b600061420a6013546001600160a01b0316151590565b614218575060185460020b90565b60135460408051600481526024810182526020810180516001600160e01b0316633850c7bd60e01b179052905160009283926001600160a01b03909116916142609190614b8a565b600060405180830381855afa9150503d806000811461429b576040519150601f19603f3d011682016040523d82523d6000602084013e6142a0565b606091505b5091509150816142b757505060185460020b919050565b6000806000838060200190518101906142d09190615163565b50506019549397509195509350610708925082916142ef915042614ef0565b63ffffffff16101561430657509195945050505050565b604080516002808252606082018352600092602083019080368337019050509050818160008151811061433b5761433b614f16565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061436a5761436a614f16565b63ffffffff9092166020928302919091019091015260135460405160009182916001600160a01b039091169063883bdbfd906143aa908690602401615314565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516143e39190614b8a565b600060405180830381855afa9150503d806000811461441e576040519150601f19603f3d011682016040523d82523d6000602084013e614423565b606091505b50915091508161443b57509498975050505050505050565b60008180602001905181019061445191906153ea565b50905060008160008151811061446957614469614f16565b60200260200101518260018151811061448457614484614f16565b602002602001015161449691906154b6565b90506144a863ffffffff8716826154e3565b985060008160060b1280156144ce57506144c863ffffffff871682615518565b60060b15155b156144e157886144dd8161553a565b9950505b50969a9950505050505050505050565b6001600160a01b03811661451857604051634e46966960e11b815260040160405180910390fd5b6000614538600154600160801b81046001600160801b0390811691161490565b61454d576145466001614665565b90506145a2565b60066000815461455c9061555d565b909155506006546001016145835760405163303b682f60e01b815260040160405180910390fd5b60065461459f906ec097ce7bc90715b34b9f1000000000614f03565b90505b6000818152600b60205260409020546001600160a01b031680156145d95760405163119b4fd360e11b815260040160405180910390fd5b611016818484612cc4565b6001600160a01b03811661460b57604051636edaef2f60e11b815260040160405180910390fd5b6001600160a01b0381166000908152600c60205260408120805461463190600190614ef0565b8154811061464157614641614f16565b9060005260206000200154905061465a82600083612cc4565b610f646001826146d5565b80546000906001600160801b03600160801b820481169116810361469c576040516375e52f4f60e01b815260040160405180910390fd5b600019016001600160801b039081166000818152600185016020526040812080549190558454909216600160801b909102179092555090565b81546001600160801b038082166000190191600160801b900481169082160361471157604051638acb5f2760e01b815260040160405180910390fd5b6001600160801b0316600081815260018401602052604090209190915581546001600160801b031916179055565b8015158114611eb157600080fd5b60006020828403121561475f57600080fd5b8135610f9e8161473f565b6001600160e01b031981168114611eb157600080fd5b60006020828403121561479257600080fd5b8135610f9e8161476a565b6001600160a01b0381168114611eb157600080fd5b6000602082840312156147c457600080fd5b8135610f9e8161479d565b60005b838110156147ea5781810151838201526020016147d2565b50506000910152565b6000815180845261480b8160208601602086016147cf565b601f01601f19169290920160200192915050565b602081526000610f9e60208301846147f3565b60006020828403121561484457600080fd5b5035919050565b6000806040838503121561485e57600080fd5b82356148698161479d565b946020939093013593505050565b60008060006060848603121561488c57600080fd5b83356148978161479d565b925060208401356148a78161479d565b929592945050506040919091013590565b6001600160801b0381168114611eb157600080fd5b6000602082840312156148df57600080fd5b8135610f9e816148b8565b600080604083850312156148fd57600080fd5b82356149088161479d565b915060208301356149188161473f565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561495b5783518352928401929184019160010161493f565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156149a6576149a6614967565b604052919050565b600080600080608085870312156149c457600080fd5b84356149cf8161479d565b93506020858101356149e08161479d565b935060408601359250606086013567ffffffffffffffff80821115614a0457600080fd5b818801915088601f830112614a1857600080fd5b813581811115614a2a57614a2a614967565b614a3c601f8201601f1916850161497d565b91508082528984828501011115614a5257600080fd5b808484018584013760008482840101525080935050505092959194509250565b60ff81168114611eb157600080fd5b600080600080600080600060e0888a031215614a9c57600080fd5b8735614aa78161479d565b96506020880135614ab78161479d565b955060408801359450606088013593506080880135614ad581614a72565b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215614b0557600080fd5b8235614b108161479d565b915060208301356149188161479d565b8060020b8114611eb157600080fd5b600060208284031215614b4157600080fd5b8135610f9e81614b20565b60008060408385031215614b5f57600080fd5b50508035926020909101359150565b60008151614b808185602086016147cf565b9290920192915050565b60008251614b9c8184602087016147cf565b9190910192915050565b600181811c90821680614bba57607f821691505b6020821081036123ab57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610d8a57610d8a614bda565b634e487b7160e01b600052601260045260246000fd5b600082614c2c57614c2c614c07565b500490565b600060208284031215614c4357600080fd5b5051919050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090614c7d908301846147f3565b9695505050505050565b600060208284031215614c9957600080fd5b8151610f9e8161476a565b8054600090600181811c9080831680614cbe57607f831692505b60208084108203614cdf57634e487b7160e01b600052602260045260246000fd5b818015614cf35760018114614d0857614d34565b60ff1986168952841515850289019650614d34565b876000528160002060005b86811015614d2c5781548b820152908501908301614d13565b505084890196505b50505050505092915050565b747b226e616d65223a202257484f333333204e46542360581b81528551600090614d71816015850160208b016147cf565b7f222c226465736372697074696f6e223a224120636f6c6c656374696f6e206f66601591840191820152600160fd1b60358201528651614db8816036840160208b016147cf565b7f20706f7473206f66206c6971756964697479207468617420746f6b656e697a65603692909101918201527f7320646563656e7472616c697a656420726573657276652063757272656e637960568201527f206964656120666f722074686520495135302c20234552433333332e0000000060768201527f222c2265787465726e616c5f75726c223a2268747470733a2f2f77686f33333360928201526f173bba331791161134b6b0b3b2911d1160811b60b2820152614ee4614ed4614ece614e8d614e8760c286018b614ca4565b89614b6e565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a224381526e37b637b91116113b30b63ab2911d1160891b6020820152602f0190565b86614b6e565b63227d5d7d60e01b815260040190565b98975050505050505050565b81810381811115610d8a57610d8a614bda565b80820180821115610d8a57610d8a614bda565b634e487b7160e01b600052603260045260246000fd5b6001600160801b03818116838216019080821115614f4c57614f4c614bda565b5092915050565b6000610f9e8284614ca4565b6001600160801b03828116828216039080821115614f4c57614f4c614bda565b60008060408385031215614f9257600080fd5b505080516020909101519092909150565b60008160020b8360020b80614fba57614fba614c07565b627fffff19821460001982141615614fd457614fd4614bda565b90059392505050565b60008260020b8260020b028060020b9150808214614f4c57614f4c614bda565b600282810b9082900b03627fffff198112627fffff82131715610d8a57610d8a614bda565b60008160020b627fffff19810361503b5761503b614bda565b60000392915050565b600281810b9083900b01627fffff8113627fffff1982121715610d8a57610d8a614bda565b81546001600160a01b03168152610100810160018301546001600160a01b03808216602085015262ffffff60a092831c16604085015260028086015460608601526003860154918216608086015281831c810b9285019290925260b81c900b60c083015260048301546001600160801b031660e08301819052614f4c565b634e487b7160e01b600052603160045260246000fd5b60008060006060848603121561511257600080fd5b835161511d816148b8565b602085015160409095015190969495509392505050565b60006020828403121561514657600080fd5b8151610f9e8161479d565b805161ffff811681146111a557600080fd5b600080600080600080600060e0888a03121561517e57600080fd5b87516151898161479d565b602089015190975061519a81614b20565b95506151a860408901615151565b94506151b660608901615151565b93506151c460808901615151565b925060a08801516151d481614a72565b60c08901519092506151e58161473f565b8091505092959891949750929550565b60006020828403121561520757600080fd5b8151610f9e81614b20565b81516001600160a01b031681526101608101602083015161523e60208401826001600160a01b03169052565b506040830151615255604084018262ffffff169052565b50606083015161526a606084018260020b9052565b50608083015161527f608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401516152c5828501826001600160a01b03169052565b505061014092830151919092015290565b600080600080608085870312156152ec57600080fd5b8451935060208501516152fe816148b8565b6040860151606090960151949790965092505050565b6020808252825182820181905260009190848201906040850190845b8181101561495b57835163ffffffff1683529284019291840191600101615330565b600067ffffffffffffffff82111561536c5761536c614967565b5060051b60200190565b600082601f83011261538757600080fd5b8151602061539c61539783615352565b61497d565b82815260059290921b840181019181810190868411156153bb57600080fd5b8286015b848110156153df5780516153d28161479d565b83529183019183016153bf565b509695505050505050565b600080604083850312156153fd57600080fd5b825167ffffffffffffffff8082111561541557600080fd5b818501915085601f83011261542957600080fd5b8151602061543961539783615352565b82815260059290921b8401810191818101908984111561545857600080fd5b948201945b838610156154865785518060060b81146154775760008081fd5b8252948201949082019061545d565b9188015191965090935050508082111561549f57600080fd5b506154ac85828601615376565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff82131715610d8a57610d8a614bda565b60008160060b8360060b806154fa576154fa614c07565b667fffffffffffff19821460001982141615614fd457614fd4614bda565b60008260060b8061552b5761552b614c07565b808360060b0791505092915050565b60008160020b627fffff19810361555357615553614bda565b6000190192915050565b60006001820161556f5761556f614bda565b506001019056fea264697066735822122069487e0347bf5b69b5a87dbc77908d5664fad9d13b7ee437e4a2e8ac0a61c17864736f6c63430008140033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000cdf74bff7c62c72775a2cdb83dbc0a1d4866703a000000000000000000000000a6afd4d1226169db19432cf6f26f66a219b9b159

-----Decoded View---------------
Arg [0] : initialOwner_ (address): 0xCdF74BFF7C62c72775A2cdb83dBc0A1d4866703A
Arg [1] : initialMintRecipient_ (address): 0xA6AFd4D1226169db19432cf6F26f66a219b9b159

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000cdf74bff7c62c72775a2cdb83dbc0a1d4866703a
Arg [1] : 000000000000000000000000a6afd4d1226169db19432cf6f26f66a219b9b159


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.