ETH Price: $1,813.18 (+10.88%)

Contract

0x0cd7e55f61D393866db74afd6fdf49D81b82b9Be
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

Multichain Info

Transaction Hash
Method
Block
From
To
Update Lock Stat...182600082025-04-22 13:50:3122 hrs ago1745329831IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000080.00132999
Set Approval For...182599362025-04-22 13:48:0722 hrs ago1745329687IN
0x0cd7e55f...81b82b9Be
0 ETH00.00014676
Update Lock Stat...182428392025-04-22 4:18:1332 hrs ago1745295493IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000530.00629999
Set Approval For...182213532025-04-21 16:22:0144 hrs ago1745252521IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000010.00019968
Set Approval For...180984632025-04-18 20:05:414 days ago1745006741IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000040.00135897
Update Lock Stat...180589882025-04-17 22:09:515 days ago1744927791IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000020.00030819
Set Approval For...180589082025-04-17 22:07:115 days ago1744927631IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000010.00030235
Set Approval For...180053392025-04-16 16:21:336 days ago1744820493IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000160.00312179
Update Lock Stat...178122662025-04-12 5:05:4711 days ago1744434347IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000140.00226603
Set Approval For...178075932025-04-12 2:30:0111 days ago1744425001IN
0x0cd7e55f...81b82b9Be
0 ETH0.00000010.00191178
Set Approval For...177041182025-04-09 17:00:5113 days ago1744218051IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000060.00204639
Set Approval For...176144422025-04-07 15:11:3915 days ago1744038699IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000060.00121252
Update Lock Stat...175772442025-04-06 18:31:4316 days ago1743964303IN
0x0cd7e55f...81b82b9Be
0 ETH00.00000236
Set Approval For...175257402025-04-05 13:54:5517 days ago1743861295IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000060.00126111
Update Lock Stat...173504962025-04-01 12:33:2721 days ago1743510807IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000070.00119659
Set Approval For...173370492025-04-01 5:05:1322 days ago1743483913IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000030.00058769
Update Lock Stat...173252992025-03-31 22:33:3322 days ago1743460413IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000350.0017
Update Lock Stat...173194822025-03-31 19:19:3922 days ago1743448779IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000080.00141919
Update Lock Stat...173158532025-03-31 17:18:4122 days ago1743441521IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000090.00125432
Update Lock Stat...171927612025-03-28 20:55:3725 days ago1743195337IN
0x0cd7e55f...81b82b9Be
0 ETH00.00012126
Update Lock Stat...171319762025-03-27 11:09:2727 days ago1743073767IN
0x0cd7e55f...81b82b9Be
0 ETH0.000000060.00101166
Update Lock Stat...168373772025-03-20 15:29:2933 days ago1742484569IN
0x0cd7e55f...81b82b9Be
0 ETH00.00000545
Update Lock Stat...168371972025-03-20 15:23:2933 days ago1742484209IN
0x0cd7e55f...81b82b9Be
0 ETH00.0000055
Safe Transfer Fr...168369792025-03-20 15:16:1333 days ago1742483773IN
0x0cd7e55f...81b82b9Be
0 ETH00.00000492
Update Lock Stat...168364842025-03-20 14:59:4333 days ago1742482783IN
0x0cd7e55f...81b82b9Be
0 ETH00.00000323
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
44009992024-06-05 18:23:33321 days ago1717611813
0x0cd7e55f...81b82b9Be
655.5 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
44002942024-06-05 18:00:03321 days ago1717610403
0x0cd7e55f...81b82b9Be
0.138 ETH
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BlastinPepes

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 10000 runs

Other Settings:
paris EvmVersion
File 1 of 23 : BlastinPepes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "./SignatureWhitelist.sol";
import "./LPManager.sol";
import "../DN404Mirror.sol";
import "../blast/AbstractBlastContract.sol";

contract BlastinPepes is DN404Mirror, AbstractBlastContract, SignatureWhitelist, LPManager {
    error OwnableUnauthorizedAccount(address account);
    error InvalidStage();
    error InsufficientAmountForMint();
    error MaxMintExceeded();
    error InvalidMinter();
    error LiquidityLocked();

    uint256 public immutable MAX_SUPPLY = 10_000;
    uint256 public immutable MINT_PRICE = 0.069 ether;

    uint256 private immutable MAX_TEAM_SUPPLY = 1000;
    uint256 private immutable MAX_MINT = 9500;

    uint256 public lastId = 0;
    uint256 public liquidityLockedUntil = 0;

    uint256 public currentPhase = 0; // [0] - team mint, [1] - whitelist 1 mint, [2] - whitelist 2 mint, [3] - public mint, [4] - liquidity pool mint
    mapping(address => uint256) public addressToNumMinted;

    constructor(address nonfungiblePositionManager, address weth) LPManager(nonfungiblePositionManager, weth) {
        _initializeDN404Mirror(msg.sender);

        // Blast configuration
        __AbstractBlastContract_init();
        _configurePointsOperator(msg.sender);

        liquidityLockedUntil = 0;
    }

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

    /// @dev increment the current phase
    function setPhase(uint256 phase) external onlyOwner {
        currentPhase = phase;
    }

    /// @dev extend the liquidity lock
    function extendLiquidityLock(uint256 duration) external onlyOwner {
        if (liquidityLockedUntil > block.timestamp) revert LiquidityLocked();

        liquidityLockedUntil = block.timestamp + duration;
    }

    /// @dev withdraw the liquidity from the pool in the event of an emergency
    function withdraw() external onlyOwner {
        if (liquidityLockedUntil > block.timestamp) revert LiquidityLocked();

        uint256 balance = address(this).balance;
        if (balance > 0) {
            payable(owner()).transfer(balance);
        }
        _withdrawLiquidity();
    }

    /// @dev collect the fees from the pool
    function collectFees() external onlyOwner returns (uint256 amount0, uint256 amount1) {
        (amount0, amount1) = _collectFees();
    }

    /// @dev place the liquidity in the pool
    function createLpPosition() external onlyOwner {
        if (currentPhase != 4) revert InvalidStage();

        // Retrieve supply liquidity
        IDN404(baseERC20()).returnSupplyLiquidity(MAX_SUPPLY);

        _placeLiquidity(baseERC20());

        // Transfer the remaining supply to the owner
        uint256 remainingBalance = IERC20(baseERC20()).balanceOf(address(this));
        if (remainingBalance > 0) {
            IERC20(baseERC20()).transfer(msg.sender, remainingBalance);
        }
    }

    /// @dev Mints the remaining supply to the token contract to create NFTs, which will be placed in the liquidity pool
    function supplyMint(uint256 _max) external onlyOwner {
        if (currentPhase != 4) revert InvalidStage();

        uint256 remaining = MAX_SUPPLY - lastId;
        if (remaining > _max) {
            remaining = _max;
        }

        uint256[] memory ids = new uint256[](remaining);
        for (uint256 i = 0; i < remaining; i++) {
            ids[i] = ++lastId;
        }
        _mint(baseERC20(), ids, false);
    }

    /// @dev Mint function
    function mint(uint256 amount, Whitelist calldata _whitelist, Signature calldata _signature) external payable {
        _validate(_whitelist, _signature, owner());

        if (amount == 0) revert InsufficientAmountForMint();

        if (_whitelist.account != msg.sender) revert InvalidMinter();

        if (_whitelist.phase > currentPhase || currentPhase == 4) revert InvalidStage();

        uint256 numMinted = addressToNumMinted[msg.sender];
        if (numMinted + amount > _whitelist.amount) revert MaxMintExceeded();

        if (msg.value != amount * MINT_PRICE) revert InsufficientAmountForMint();
        
        if (currentPhase == 0) {
            if (lastId + amount > MAX_TEAM_SUPPLY) revert MaxMintExceeded();
        } else {
            if (lastId + amount > MAX_MINT) revert MaxMintExceeded();
        }

        addressToNumMinted[msg.sender] = numMinted + amount;

        uint256[] memory ids = new uint256[](amount);
        for (uint256 i = 0; i < amount; i++) {
            ids[i] = ++lastId;
        }

        _mint(msg.sender, ids, false);
    }

    /// @dev Public mint function for the public phase
    function publicMint(uint256 amount) external payable {
        if (currentPhase != 3) revert InvalidStage();
        if (amount == 0) revert InsufficientAmountForMint();
        if (amount > 2) revert MaxMintExceeded();
        if (lastId + amount > MAX_MINT) revert MaxMintExceeded();
        if (msg.value != amount * MINT_PRICE) revert InsufficientAmountForMint();

        addressToNumMinted[msg.sender] += amount;
        uint256[] memory ids = new uint256[](amount);
        for (uint256 i = 0; i < amount; i++) {
            ids[i] = ++lastId;
        }
        _mint(msg.sender, ids, false);
    }

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

    /// @dev Mints NFTs to the given address.
    /// @param to The address to mint NFTs to.
    /// @param ids The NFT IDs to mint.
    /// @param lock Whether to lock the NFTs
    function _mint(address to, uint256[] memory ids, bool lock) internal {
        address base = baseERC20();
        (bool success, bytes memory result) = base.call(
            abi.encodeWithSignature(
                "mintNFT(uint256,uint256[])",
                uint256(uint160(to)) << 96 | (lock ? 1 : 0),
                ids
            )
        );
        // @solidity memory-safe-assembly
        assembly {
            if iszero(and(eq(mload(add(result, 0x20)), 1), success)) {
                revert(add(result, 0x20), mload(result))
            }

            let idLen := mload(ids)
            mstore(0x00, lock)
            for {
                let s := add(ids, 0x20)
                let end := add(s, shl(5, idLen))
            } iszero(eq(s, end)) { s := add(s, 0x20) } {
                // Emit the {Transfer} event.
                if eq(lock, false) { log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, caller(), mload(s)) }
            }
        }
    }
}

File 2 of 23 : IERC5267.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.20;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

File 3 of 23 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

File 4 of 23 : 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 5 of 23 : EIP712.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.20;

import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
 * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
 * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
 * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * @custom:oz-upgrades-unsafe-allow state-variable-immutable
 */
abstract contract EIP712 is IERC5267 {
    using ShortStrings for *;

    bytes32 private constant TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _cachedDomainSeparator;
    uint256 private immutable _cachedChainId;
    address private immutable _cachedThis;

    bytes32 private immutable _hashedName;
    bytes32 private immutable _hashedVersion;

    ShortString private immutable _name;
    ShortString private immutable _version;
    string private _nameFallback;
    string private _versionFallback;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        _name = name.toShortStringWithFallback(_nameFallback);
        _version = version.toShortStringWithFallback(_versionFallback);
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = _buildDomainSeparator();
        _cachedThis = address(this);
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
            return _cachedDomainSeparator;
        } else {
            return _buildDomainSeparator();
        }
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev See {IERC-5267}.
     */
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        return (
            hex"0f", // 01111
            _EIP712Name(),
            _EIP712Version(),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }

    /**
     * @dev The name parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _name which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Name() internal view returns (string memory) {
        return _name.toStringWithFallback(_nameFallback);
    }

    /**
     * @dev The version parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _version which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Version() internal view returns (string memory) {
        return _version.toStringWithFallback(_versionFallback);
    }
}

File 6 of 23 : MessageHashUtils.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

File 7 of 23 : 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 8 of 23 : 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 9 of 23 : 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 10 of 23 : ShortStrings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)

pragma solidity ^0.8.20;

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

// | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
// | length  | 0x                                                              BB |
type ShortString is bytes32;

/**
 * @dev This library provides functions to convert short memory strings
 * into a `ShortString` type that can be used as an immutable variable.
 *
 * Strings of arbitrary length can be optimized using this library if
 * they are short enough (up to 31 bytes) by packing them with their
 * length (1 byte) in a single EVM word (32 bytes). Additionally, a
 * fallback mechanism can be used for every other case.
 *
 * Usage example:
 *
 * ```solidity
 * contract Named {
 *     using ShortStrings for *;
 *
 *     ShortString private immutable _name;
 *     string private _nameFallback;
 *
 *     constructor(string memory contractName) {
 *         _name = contractName.toShortStringWithFallback(_nameFallback);
 *     }
 *
 *     function name() external view returns (string memory) {
 *         return _name.toStringWithFallback(_nameFallback);
 *     }
 * }
 * ```
 */
library ShortStrings {
    // Used as an identifier for strings longer than 31 bytes.
    bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;

    error StringTooLong(string str);
    error InvalidShortString();

    /**
     * @dev Encode a string of at most 31 chars into a `ShortString`.
     *
     * This will trigger a `StringTooLong` error is the input string is too long.
     */
    function toShortString(string memory str) internal pure returns (ShortString) {
        bytes memory bstr = bytes(str);
        if (bstr.length > 31) {
            revert StringTooLong(str);
        }
        return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
    }

    /**
     * @dev Decode a `ShortString` back to a "normal" string.
     */
    function toString(ShortString sstr) internal pure returns (string memory) {
        uint256 len = byteLength(sstr);
        // using `new string(len)` would work locally but is not memory safe.
        string memory str = new string(32);
        /// @solidity memory-safe-assembly
        assembly {
            mstore(str, len)
            mstore(add(str, 0x20), sstr)
        }
        return str;
    }

    /**
     * @dev Return the length of a `ShortString`.
     */
    function byteLength(ShortString sstr) internal pure returns (uint256) {
        uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
        if (result > 31) {
            revert InvalidShortString();
        }
        return result;
    }

    /**
     * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
     */
    function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
        if (bytes(value).length < 32) {
            return toShortString(value);
        } else {
            StorageSlot.getStringSlot(store).value = value;
            return ShortString.wrap(FALLBACK_SENTINEL);
        }
    }

    /**
     * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
     */
    function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return toString(value);
        } else {
            return store;
        }
    }

    /**
     * @dev Return the length of a string that was encoded to `ShortString` or written to storage using
     * {setWithFallback}.
     *
     * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
     * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
     */
    function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return byteLength(value);
        } else {
            return bytes(store).length;
        }
    }
}

File 11 of 23 : StorageSlot.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}

File 12 of 23 : 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 23 : AbstractBlastContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import "./IBlast.sol";
import "./BlastConstants.sol";

/// @title AbstractBlastContract
/// @notice An abstract contract that can configure/claim Blast points/yield
abstract contract AbstractBlastContract {
    /// @dev initializer for proxy
    function __AbstractBlastContract_init() internal {
        if (getChainId() == 81457) {
            IBlast blast = _getBlast();
            blast.configure(YieldMode.CLAIMABLE, GasMode.CLAIMABLE, msg.sender);
        }
    }

    /// @dev configure the points operator
    function _configurePointsOperator(address _operator) internal {
        if (getChainId() == 81457) {
            IBlastPoints(BlastConstants.BLAST_POINTS).configurePointsOperator(_operator);
        }
    }

    /// @dev returns the address of the Blast contract
    function _getBlast() internal pure returns (IBlast) {
        return IBlast(BlastConstants.BLAST);
    }

    function getChainId() private view returns (uint256) {
        uint256 id;
        assembly {
            id := chainid()
        }
        return id;
    }
}

File 14 of 23 : BlastConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

library BlastConstants {
    /// @notice Address of the Blast predeploy.
    address internal constant BLAST = 0x4300000000000000000000000000000000000002;

    /// @notice Address of the USDB predeploy.
    address internal constant USDB = 0x4300000000000000000000000000000000000003;

    /// @notice Address of the WETH predeploy.
    address internal constant WETH = 0x4300000000000000000000000000000000000004;

    /// @notice Address of the Blast points manager.
    address internal constant BLAST_POINTS = 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800;
}

File 15 of 23 : IBlast.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

enum YieldMode {
    AUTOMATIC,
    VOID,
    CLAIMABLE
}

enum GasMode {
    VOID,
    CLAIMABLE 
}

interface IBlast{
    // configure
    function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;
    function configure(YieldMode _yield, GasMode gasMode, address governor) external;

    // base configuration options
    function configureClaimableYield() external;
    function configureClaimableYieldOnBehalf(address contractAddress) external;
    function configureAutomaticYield() external;
    function configureAutomaticYieldOnBehalf(address contractAddress) external;
    function configureVoidYield() external;
    function configureVoidYieldOnBehalf(address contractAddress) external;
    function configureClaimableGas() external;
    function configureClaimableGasOnBehalf(address contractAddress) external;
    function configureVoidGas() external;
    function configureVoidGasOnBehalf(address contractAddress) external;
    function configureGovernor(address _governor) external;
    function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;

    // claim yield
    function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256);
    function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256);

    // claim gas
    function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256);
    function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256);
    function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256);
    function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256);

    // read functions
    function readClaimableYield(address contractAddress) external view returns (uint256);
    function readYieldConfiguration(address contractAddress) external view returns (uint8);
    function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode);
}

interface IERC20Rebasing {
  // changes the yield mode of the caller and update the balance
  // to reflect the configuration
  function configure(YieldMode) external returns (uint256);
  // "claimable" yield mode accounts can call this this claim their yield
  // to another address
  function claim(address recipient, uint256 amount) external returns (uint256);
  // read the claimable amount for an account
  function getClaimableAmount(address account) external view returns (uint256);
}

interface IWETHRebasing is IERC20Rebasing {
    function deposit() external payable;
    function withdraw(uint) external;
}

interface IBlastPoints {
	function configurePointsOperator(address operator) external;
}

File 16 of 23 : DN404Mirror.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @title DN404Mirror
/// @notice DN404Mirror provides an interface for interacting with the
/// NFT tokens in a DN404 implementation.
///
/// @author vectorized.eth (@optimizoor)
/// @author Quit (@0xQuit)
/// @author Michael Amadi (@AmadiMichaels)
/// @author cygaar (@0xCygaar)
/// @author Thomas (@0xjustadev)
/// @author Harrison (@PopPunkOnChain)
///
/// @dev Note:
/// - The ERC721 data is stored in the base DN404 contract.
abstract contract DN404Mirror {
    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                           EVENTS                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Emitted when token `id` is transferred from `from` to `to`.
    event Transfer(address indexed from, address indexed to, uint256 indexed id);

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

    /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.
    event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This is for marketplace signaling purposes. This contract has a `pullOwner()`
    /// function that will sync the owner from the base contract.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev Emitted when `owner` lock or unlock token `id`.
    event UpdateLockState(address indexed owner, uint256 indexed id, bool lockStatus);

    /// @dev Emitted when token `idX` and `idY` exchanged.
    event Exchange(uint256 indexed idX, uint256 indexed idY, uint256 exchangeFee);

    /// @dev Emitted when token `id` offered for sale.
    event Offer(uint256 indexed id, address indexed to, uint256 minPrice);

    /// @dev Emitted when token `id` offered for sale.
    event CancelOffer(uint256 indexed id, address indexed owner);

    /// @dev Emitted when token `id` offered for sale.
    event Bid(uint256 indexed id, address indexed from, uint256 price);

    /// @dev Emitted when token `id` offered for sale.
    event CancelBid(uint256 indexed id, address indexed from);

    /// @dev Emitted when token `id` bought.
    event Bought(uint256 indexed id, address indexed from, address indexed to, uint256 price);

    /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
    uint256 internal constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
    uint256 internal constant _APPROVAL_EVENT_SIGNATURE =
        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;

    /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`.
    uint256 internal constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
        0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;

    /// @dev `keccak256(bytes("UpdateLockState(address,uint256,bool)"))`.
    uint256 internal constant _UPDATE_LOCK_STATE_EVENT_SIGNATURE =
        0xcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac;

    /// @dev `keccak256(bytes("Exchange(uint256,uint256,uint256)"))`
    uint256 internal constant _EXCHANGE_EVENT_SIGNATURE =
        0xbc43d7c0945f5a13a7bfa8ca7309e55f903f01d66c38c6d1353fe7ff9335d776;

    /// @dev `keccak256(bytes("Offer(uint256,address,uint256)"))`
    uint256 private constant _OFFER_EVENT_SIGNATURE =
        0x2d57124cfa4e385afd5cc9d6f24874bdd21303ac9131d7cb674be2a5855c7002;

    /// @dev `keccak256(bytes("CancelOffer(uint256,address)"))`
    uint256 private constant _CANCEL_OFFER_EVENT_SIGNATURE =
        0xc4caef7e3533865382e608c341581a5e2a1b0d1ac37b0aaf58023ccd4eedfd8e;

    /// @dev `keccak256(bytes("Bid(uint256,address,uint256)"))`
    uint256 private constant _BID_EVENT_SIGNATURE =
        0xdcd726e11f8b5e160f00290f0fe3a1abb547474e53a8e7a8f49a85e7b1ca3199;

    /// @dev `keccak256(bytes("CancelBid(uint256,address)"))`
    uint256 private constant _CANCEL_BID_EVENT_SIGNATURE =
        0x874afcdd5e90b2329b3c1601e613dcdc6abb6deb62ce61339a8337b48c053e51;

    /// @dev `keccak256(bytes("Bought(uint256,address,address,uint256)"))`
    uint256 private constant _BOUGHT_EVENT_SIGNATURE =
        0x888231f55a3cd8fd72276bc1b12ed5a60f8d92e62d288e64bf29dd6e5fc7809a;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                        CUSTOM ERRORS                       */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Thrown when a call for an NFT function did not originate
    /// from the base DN404 contract.
    error SenderNotBase();

    /// @dev Thrown when a call for an NFT function did not originate from the deployer.
    error SenderNotDeployer();

    /// @dev Thrown when transferring an NFT to a contract address that
    /// does not implement ERC721Receiver.
    error TransferToNonERC721ReceiverImplementer();

    /// @dev Thrown when linking to the DN404 base contract and the
    /// DN404 supportsInterface check fails or the call reverts.
    error CannotLink();

    /// @dev Thrown when a linkMirrorContract call is received and the
    /// NFT mirror contract has already been linked to a DN404 base contract.
    error AlreadyLinked();

    /// @dev Thrown when retrieving the base DN404 address when a link has not
    /// been established.
    error NotLinked();

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                          STORAGE                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Struct contain the NFT mirror contract storage.
    struct DN404NFTStorage {
        address baseERC20;
        address deployer;
        address owner;
    }

    /// @dev Returns a storage pointer for DN404NFTStorage.
    function _getDN404NFTStorage() internal pure virtual returns (DN404NFTStorage storage $) {
        /// @solidity memory-safe-assembly
        assembly {
            // `uint72(bytes9(keccak256("DN404_MIRROR_STORAGE")))`.
            $.slot := 0x3602298b8c10b01230 // Truncate to 9 bytes to reduce bytecode size.
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                        CONSTRUCTOR                         */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    // constructor(address deployer) {
    //     // For non-proxies, we will store the deployer so that only the deployer can
    //     // link the base contract.
    //     _getDN404NFTStorage().deployer = deployer;
    // }

    function _initializeDN404Mirror(address deployer) internal {
        // For non-proxies, we will store the deployer so that only the deployer can
        // link the base contract.
        _getDN404NFTStorage().deployer = deployer;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                     ERC721 OPERATIONS                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns the token collection name from the base DN404 contract.
    function name() public view virtual returns (string memory result) {
        return _readString(0x06fdde03, 0); // `name()`.
    }

    /// @dev Returns the token collection symbol from the base DN404 contract.
    function symbol() public view virtual returns (string memory result) {
        return _readString(0x95d89b41, 0); // `symbol()`.
    }

    /// @dev Returns the Uniform Resource Identifier (URI) for token `id` from
    /// the base DN404 contract.
    function tokenURI(uint256 id) public view virtual returns (string memory result) {
        return _readString(0xc87b56dd, id); // `tokenURI()`.
    }

    /// @dev Returns the total NFT supply from the base DN404 contract.
    function totalSupply() public view virtual returns (uint256 result) {
        return _readWord(0xe2c79281, 0, 0); // `totalNFTSupply()`.
    }

    /// @dev Returns the number of NFT tokens owned by `nftOwner` from the base DN404 contract.
    ///
    /// Requirements:
    /// - `nftOwner` must not be the zero address.
    function balanceOf(address nftOwner) public view virtual returns (uint256 result) {
        return _readWord(0xf5b100ea, uint160(nftOwner), 0); // `balanceOfNFT(address)`.
    }

    /// @dev Returns the owner of token `id` from the base DN404 contract.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function ownerOf(uint256 id) public view virtual returns (address result) {
        return address(uint160(_readWord(0x6352211e, id, 0))); // `ownerOf(uint256)`.
    }

    /// @dev Returns the owner of token `id` from the base DN404 contract.
    /// Returns `address(0)` instead of reverting if the token does not exist.
    function ownerAt(uint256 id) public view virtual returns (address result) {
        return address(uint160(_readWord(0x24359879, id, 0))); // `ownerAt(uint256)`.
    }

    /// @dev Sets `spender` as the approved account to manage token `id` in
    /// the base DN404 contract.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    /// - The caller must be the owner of the token,
    ///   or an approved operator for the token owner.
    ///
    /// Emits an {Approval} event.
    function approve(address spender, uint256 id) public virtual {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            spender := shr(96, shl(96, spender))
            let m := mload(0x40)
            mstore(0x00, 0xd10b6e0c) // `approveNFT(address,uint256,address)`.
            mstore(0x20, spender)
            mstore(0x40, id)
            mstore(0x60, caller())
            if iszero(
                and(
                    gt(returndatasize(), 0x1f),
                    call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
            // Emit the {Approval} event.
            log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, shr(96, mload(0x0c)), spender, id)
        }
    }

    /// @dev Returns the account approved to manage token `id` from
    /// the base DN404 contract.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function getApproved(uint256 id) public view virtual returns (address) {
        return address(uint160(_readWord(0x081812fc, id, 0))); // `getApproved(uint256)`.
    }

    /// @dev Sets whether `operator` is approved to manage the tokens of the caller in
    /// the base DN404 contract.
    ///
    /// Emits an {ApprovalForAll} event.
    function setApprovalForAll(address operator, bool approved) public virtual {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            operator := shr(96, shl(96, operator))
            let m := mload(0x40)
            mstore(0x00, 0x813500fc) // `setApprovalForAll(address,bool,address)`.
            mstore(0x20, operator)
            mstore(0x40, iszero(iszero(approved)))
            mstore(0x60, caller())
            if iszero(
                and(eq(mload(0x00), 1), call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20))
            ) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            // Emit the {ApprovalForAll} event.
            // The `approved` value is already at 0x40.
            log3(0x40, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), operator)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /// @dev Returns whether `operator` is approved to manage the tokens of `nftOwner` from
    /// the base DN404 contract.
    function isApprovedForAll(address nftOwner, address operator)
        public
        view
        virtual
        returns (bool result)
    {
        // `isApprovedForAll(address,address)`.
        return _readWord(0xe985e9c5, uint160(nftOwner), uint160(operator)) != 0;
    }

    /// @dev Returns the owned token ids of `account` from the base DN404 contract.
    function ownedIds(address account, uint256 begin, uint256 end)
        public
        view
        virtual
        returns (uint256[] memory)
    {
        return _ownedIds(account, begin, end, false);
    }

    /// @dev Returns the locked token ids of `account` from the base DN404 contract.
    function lockedIds(address account, uint256 begin, uint256 end)
        public
        view
        virtual
        returns (uint256[] memory)
    {
        return _ownedIds(account, begin, end, true);
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function transferFrom(address from, address to, uint256 id) public virtual {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            from := shr(96, shl(96, from))
            to := shr(96, shl(96, to))
            let m := mload(0x40)
            mstore(m, 0xe5eb36c8) // `transferFromNFT(address,address,uint256,address)`.
            mstore(add(m, 0x20), from)
            mstore(add(m, 0x40), to)
            mstore(add(m, 0x60), id)
            mstore(add(m, 0x80), caller())
            if iszero(
                and(eq(mload(m), 1), call(gas(), base, callvalue(), add(m, 0x1c), 0x84, m, 0x20))
            ) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            // Emit the `from` unlock event.
            mstore(m, 0x00)
            log3(m, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, from, id)
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
            // Emit the `to` lock event
            mstore(m, 0x01)
            log3(m, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, to, id)
        }
    }

    /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`.
    function safeTransferFrom(address from, address to, uint256 id) public virtual {
        transferFrom(from, to, id);

        if (_hasCode(to)) _checkOnERC721Received(from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    /// - 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 id, bytes calldata data)
        public
        virtual
    {
        transferFrom(from, to, id);

        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    function updateLockState(uint256[] memory ids, bool lock) public virtual {
        address base = baseERC20();

        (bool success, bytes memory result) = base.call(
            abi.encodeWithSignature(
                "setNFTLockState(uint256,uint256[])",
                uint256(uint160(msg.sender)) << 96 | (lock ? 1 : 0),
                ids
            )
        );

        // @solidity memory-safe-assembly
        assembly {
            if iszero(and(eq(mload(add(result, 0x20)), 1), success)) {
                revert(add(result, 0x20), mload(result))
            }
            let idLen := mload(ids)

            mstore(0x00, lock)
            for {
                let s := add(ids, 0x20)
                let end := add(s, shl(5, idLen))
            } iszero(eq(s, end)) { s := add(s, 0x20) } {
                log3(0x00, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, caller(), mload(s))
            }
        }
    }

    struct NFTOrder {
        uint256 id;
        uint256 price;
    }

    /// @dev Returns true if this contract implements the interface defined by `interfaceId`.
    /// See: https://eips.ethereum.org/EIPS/eip-165
    /// This function call must use less than 30000 gas.
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let s := shr(224, interfaceId)
            // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f.
            result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f))
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                  OWNER SYNCING OPERATIONS                  */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns the `owner` of the contract, for marketplace signaling purposes.
    function owner() public view virtual returns (address) {
        return _getDN404NFTStorage().owner;
    }

    /// @dev Permissionless function to pull the owner from the base DN404 contract
    /// if it implements ownable, for marketplace signaling purposes.
    function pullOwner() public virtual {
        address newOwner;
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x8da5cb5b) // `owner()`.
            if and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x04, 0x00, 0x20)) {
                newOwner := shr(96, mload(0x0c))
            }
        }
        DN404NFTStorage storage $ = _getDN404NFTStorage();
        address oldOwner = $.owner;
        if (oldOwner != newOwner) {
            $.owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                     MIRROR OPERATIONS                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns the address of the base DN404 contract.
    function baseERC20() public view virtual returns (address base) {
        base = _getDN404NFTStorage().baseERC20;
        if (base == address(0)) revert NotLinked();
    }

    /// @dev Fallback modifier to execute calls from the base DN404 contract.
    modifier dn404NFTFallback() virtual {
        DN404NFTStorage storage $ = _getDN404NFTStorage();

        uint256 fnSelector = _calldataload(0x00) >> 224;

        // `logTransfer(uint256[])`.
        if (fnSelector == 0x263c69d6) {
            if (msg.sender != $.baseERC20) revert SenderNotBase();
            /// @solidity memory-safe-assembly
            assembly {
                // When returndatacopy copies 1 or more out-of-bounds bytes, it reverts.
                returndatacopy(0x00, returndatasize(), lt(calldatasize(), 0x20))
                let o := add(0x24, calldataload(0x04)) // Packed logs offset.
                returndatacopy(0x00, returndatasize(), lt(calldatasize(), o))
                let end := add(o, shl(5, calldataload(sub(o, 0x20))))
                returndatacopy(0x00, returndatasize(), lt(calldatasize(), end))

                for {} iszero(eq(o, end)) { o := add(0x20, o) } {
                    let d := calldataload(o) // Entry in the packed logs.
                    let a := shr(96, d) // The address.
                    let b := and(1, d) // Whether it is a burn.
                    log4(
                        codesize(),
                        0x00,
                        _TRANSFER_EVENT_SIGNATURE,
                        mul(a, b), // `from`.
                        mul(a, iszero(b)), // `to`.
                        shr(168, shl(160, d)) // `id`.
                    )
                }
                mstore(0x00, 0x01)
                return(0x00, 0x20)
            }
        }
        // `logDirectTransfer(address,address,uint256[])`.
        if (fnSelector == 0x144027d3) {
            if (msg.sender != $.baseERC20) revert SenderNotBase();
            /// @solidity memory-safe-assembly
            assembly {
                let from := calldataload(0x04)
                let to := calldataload(0x24)
                let o := add(0x24, calldataload(0x44)) // Direct logs offset.
                let end := add(o, shl(5, calldataload(sub(o, 0x20))))

                for {} iszero(eq(o, end)) { o := add(0x20, o) } {
                    log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, calldataload(o))
                }
                mstore(0x00, 0x01)
                return(0x00, 0x20)
            }
        }
        // `linkMirrorContract(address)`.
        if (fnSelector == 0x0f4599e5) {
            if ($.deployer != address(0)) {
                if (address(uint160(_calldataload(0x04))) != $.deployer) {
                    revert SenderNotDeployer();
                }
            }
            if ($.baseERC20 != address(0)) revert AlreadyLinked();
            $.baseERC20 = msg.sender;
            /// @solidity memory-safe-assembly
            assembly {
                mstore(0x00, 0x01)
                return(0x00, 0x20)
            }
        }
        _;
    }

    /// @dev Fallback function for calls from base DN404 contract.
    fallback() external payable virtual dn404NFTFallback {}

    receive() external payable virtual {}

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                      PRIVATE HELPERS                       */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Helper to read owned ids of a account from the base DN404 contract
    function _ownedIds(address account, uint256 begin, uint256 end, bool locked)
        private
        view
        returns (uint256[] memory result)
    {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            mstore(0x00, 0xf9b4b328) // `ownedIds(uint256,uint256,uint256)`.
            mstore(0x20, or(shl(96, account), iszero(iszero(locked))))
            mstore(0x40, begin)
            mstore(0x60, end)
            if iszero(staticcall(gas(), base, 0x1c, 0x64, 0x00, 0x00)) {
                returndatacopy(result, 0x00, returndatasize())
                revert(result, returndatasize())
            }
            returndatacopy(0x00, 0x00, 0x20) // Copy the offset of the array in returndata.
            returndatacopy(result, mload(0x00), 0x20) // Copy the length of the array.
            returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), shl(5, mload(result))) // Copy the array elements.
            mstore(0x40, add(add(result, 0x20), shl(5, mload(result)))) // Allocate memory.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /// @dev Helper to read a string from the base DN404 contract.
    function _readString(uint256 fnSelector, uint256 arg0)
        private
        view
        returns (string memory result)
    {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            mstore(0x00, fnSelector)
            mstore(0x20, arg0)
            if iszero(staticcall(gas(), base, 0x1c, 0x24, 0x00, 0x00)) {
                returndatacopy(result, 0x00, returndatasize())
                revert(result, returndatasize())
            }
            returndatacopy(0x00, 0x00, 0x20) // Copy the offset of the string in returndata.
            returndatacopy(result, mload(0x00), 0x20) // Copy the length of the string.
            returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), mload(result)) // Copy the string.
            mstore(0x40, add(add(result, 0x20), mload(result))) // Allocate memory.
        }
    }

    /// @dev Helper to read a word from the base DN404 contract.
    function _readWord(uint256 fnSelector, uint256 arg0, uint256 arg1)
        private
        view
        returns (uint256 result)
    {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(0x00, fnSelector)
            mstore(0x20, arg0)
            mstore(0x40, arg1)
            if iszero(
                and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x44, 0x00, 0x20))
            ) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            mstore(0x40, m) // Restore the free memory pointer.
            result := mload(0x00)
        }
    }

    /// @dev Helper to call a function and return a word value.
    function _callBaseRetWord(bytes memory _calldata) private returns (uint256 result) {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            if iszero(
                and(
                    gt(returndatasize(), 0x1f),
                    call(
                        gas(), base, callvalue(), add(_calldata, 0x20), mload(_calldata), 0x00, 0x20
                    )
                )
            ) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
            result := mload(0x00)
        }
    }

    /// @dev Returns the calldata value at `offset`.
    function _calldataload(uint256 offset) private pure returns (uint256 value) {
        /// @solidity memory-safe-assembly
        assembly {
            value := calldataload(offset)
        }
    }

    /// @dev Returns if `a` has bytecode of non-zero length.
    function _hasCode(address a) private view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := extcodesize(a) // Can handle dirty upper bits.
        }
    }

    /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`.
    /// Reverts if the target does not support the function correctly.
    function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data)
        private
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the calldata.
            let m := mload(0x40)
            let onERC721ReceivedSelector := 0x150b7a02
            mstore(m, onERC721ReceivedSelector)
            mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`.
            mstore(add(m, 0x40), shr(96, shl(96, from)))
            mstore(add(m, 0x60), id)
            mstore(add(m, 0x80), 0x80)
            let n := mload(data)
            mstore(add(m, 0xa0), n)
            if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) }
            // Revert if the call reverts.
            if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) {
                if returndatasize() {
                    // Bubble up the revert if the call reverts.
                    returndatacopy(m, 0x00, returndatasize())
                    revert(m, returndatasize())
                }
            }
            // Load the returndata and compare it.
            if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
                mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

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

pragma solidity ^0.8.24;

interface IDN404 {
    function setSkipNFTFor(address account, bool state) external;

    function enableLiquidityPoolTransfer() external;

    function returnSupplyLiquidity(uint256 _maxNumNfts) external;
}

File 18 of 23 : IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

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

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

    function deposit() external payable;

    function withdraw(uint) external;

    function approve(address, uint) external returns(bool);

    function transfer(address, uint) external returns(bool);

    function transferFrom(address, address, uint) external returns(bool);

    function balanceOf(address) external view returns(uint);

}

File 19 of 23 : LPManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "../thruster/INonfungiblePositionManager.sol";
import "../blast/BlastConstants.sol";
import "../thruster/TickMath.sol";
import "../interfaces/IWETH.sol";
import "../interfaces/IDN404.sol";

abstract contract LPManager {

    error DepositAlreadyExists();

    struct Deposit {
        uint256 positionId;
        address owner;
        uint128 liquidity;
        address token0;
        address token1;
    }

    INonfungiblePositionManager public immutable nonfungiblePositionManager;
    address public immutable weth;

    Deposit public floorLockDeposit;
    Deposit public supplyDeposit;

    constructor(address _nonfungiblePositionManager, address _weth) {
        nonfungiblePositionManager = INonfungiblePositionManager(_nonfungiblePositionManager);
        weth = _weth;
    }

    /// @dev collect the fees from the pool
    function _collectFees() internal returns (uint256 amount0, uint256 amount1) {
        (uint256 fla0, uint256 fla1) = nonfungiblePositionManager.collect(
            INonfungiblePositionManager.CollectParams({
                tokenId: floorLockDeposit.positionId,
                recipient: msg.sender,
                amount0Max: type(uint128).max,
                amount1Max: type(uint128).max
            }));
        (uint256 sla0, uint256 sla1) = nonfungiblePositionManager.collect(
            INonfungiblePositionManager.CollectParams({
                tokenId: supplyDeposit.positionId,
                recipient: msg.sender,
                amount0Max: type(uint128).max,
                amount1Max: type(uint128).max
            }));
        amount0 = fla0 + sla0;
        amount1 = fla1 + sla1;
    }

    /// @dev withdraw the liquidity from the pool
    function _withdrawLiquidity() internal {
        if (floorLockDeposit.positionId != 0) {
            nonfungiblePositionManager.transferFrom(address(this), msg.sender, floorLockDeposit.positionId);
            floorLockDeposit = Deposit({
                positionId: 0,
                owner: address(0),
                liquidity: 0,
                token0: address(0),
                token1: address(0)
            });
        }
        if (supplyDeposit.positionId != 0) {
            nonfungiblePositionManager.transferFrom(address(this), msg.sender, supplyDeposit.positionId);
            supplyDeposit = Deposit({
                positionId: 0,
                owner: address(0),
                liquidity: 0,
                token0: address(0),
                token1: address(0)
            });
        }
    }

    /// @dev place the liquidity in the pool
    function _placeLiquidity(address _baseERC20) internal {
        uint24 poolFee = 3000;
        bool isToken0 = _baseERC20 < weth;
        address token0 = isToken0 ? _baseERC20 : weth;
        address token1 = isToken0 ? weth : _baseERC20;

        (uint160 sqrtPriceX96, int24 flTickLower, int24 flTickUpper, int24 slTickLower, int24 slTickHigher) = _getLPParams(isToken0);

        // 1. Create pool if necessary
        address pool = nonfungiblePositionManager.createAndInitializePoolIfNecessary(
            token0,
            token1,
            poolFee,
            sqrtPriceX96
        );
        IDN404(_baseERC20).enableLiquidityPoolTransfer();
        IDN404(_baseERC20).setSkipNFTFor(pool, true);

        // 2. Create Thruster Position For Floor Lock
        _createFloorLock(isToken0, token0, token1, poolFee, flTickLower, flTickUpper);

        // 3. Create Thruster Position For Supply Lock
        _lockSupply(isToken0, token0, token1, _baseERC20, poolFee, slTickLower, slTickHigher);
    }

    /// @dev lock the remaining supply in the pool
    function _lockSupply(bool isToken0, address _token0, address _token1, address _baseERC20, uint24 _poolFee, int24 tickLower, int24 tickUpper) internal {
        if (supplyDeposit.positionId != 0) revert DepositAlreadyExists();

        uint256 amount = IERC20(_baseERC20).balanceOf(address(this));
        IERC20(_baseERC20).approve(address(nonfungiblePositionManager), amount);

        // 2. Create Thruster Position For Floor Lock
        INonfungiblePositionManager.MintParams memory params =
            INonfungiblePositionManager.MintParams({
                token0: _token0,
                token1: _token1,
                fee: _poolFee,
                tickLower: tickLower,
                tickUpper: tickUpper,
                amount0Desired: isToken0 ? amount : 0,
                amount1Desired: isToken0 ? 0 : amount ,
                amount0Min: isToken0 ? amount * 9 / 10 : 0,
                amount1Min: isToken0 ? 0 : amount * 9 / 10,
                recipient: address(this),
                deadline: block.timestamp
            });

        (uint256 tokenId, uint128 liquidity,,) = nonfungiblePositionManager.mint(params);

        supplyDeposit = Deposit({
            positionId: tokenId,
            owner: address(this),
            liquidity: liquidity,
            token0: _token0,
            token1: _token1
        });
    }

    /// @dev create the floor lock
    function _createFloorLock(bool isToken0, address _token0, address _token1, uint24 _poolFee, int24 tickLower, int24 tickUpper) internal {
        if (floorLockDeposit.positionId != 0) revert DepositAlreadyExists();

        uint256 amountToMint = address(this).balance;
        IWETH(weth).deposit{value: amountToMint}();
        IWETH(weth).approve(address(nonfungiblePositionManager), amountToMint);

        INonfungiblePositionManager.MintParams memory params =
            INonfungiblePositionManager.MintParams({
                token0: _token0,
                token1: _token1,
                fee: _poolFee,
                tickLower: tickLower,
                tickUpper: tickUpper,
                amount0Desired: isToken0 ? 0 : amountToMint,
                amount1Desired: isToken0 ? amountToMint : 0 ,
                amount0Min: isToken0 ? 0 : amountToMint,
                amount1Min: isToken0 ? amountToMint : 0 ,
                recipient: address(this),
                deadline: block.timestamp
            });

        (uint256 tokenId, uint128 liquidity,,) = nonfungiblePositionManager.mint(params);

        floorLockDeposit = Deposit({
            positionId: tokenId,
            owner: address(this),
            liquidity: liquidity,
            token0: _token0,
            token1: _token1
        });
    }

    /// @dev get the LP params for a 0.069 ETH mint price
    function _getLPParams(bool _isToken0) internal pure returns (uint160 sqrtPriceX96, int24 flTickLower, int24 flTickUpper, int24 slTickLower, int24 slTickHigher) {
        if (_isToken0) {
            sqrtPriceX96 = 658118545356139457330439066;

            flTickLower = -95880;
            flTickUpper = -95820;

            slTickLower = -95760;
            slTickHigher = 887220;
        } else {
            sqrtPriceX96 = 9537949932697673064997196578117;
            flTickLower = 95820;
            flTickUpper = 95880;
            slTickLower = -887220;
            slTickHigher = 95760;
        }
    }
}

File 20 of 23 : SignatureWhitelist.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";

abstract contract SignatureWhitelist is EIP712 {
    error InvalidSignature();

    bytes32 private constant _WHITELIST_HASH =
        keccak256("Whitelist(address account,uint256 amount,uint256 phase)");

    struct Whitelist {
        address account;
        uint256 amount;
        uint256 phase;
    }

    /// @dev Defines a signature
    struct Signature {
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    constructor() EIP712("SignatureWhitelist", "1") {}

    /// @dev Validates the whitelist data and signature
    function _validate(Whitelist calldata _whitelist, Signature calldata _signature, address _signer) internal view {
        bytes32 typedDataHash = _hashTypedDataV4(_hashWhitelist(_whitelist));
        address signer = ecrecover(typedDataHash, _signature.v, _signature.r, _signature.s);
        if (signer != _signer) {
            revert InvalidSignature();
        }
    }

    /// @dev Hashes the whitelist data
    function _hashWhitelist(Whitelist memory whitelist) internal pure returns (bytes32) {
        return keccak256(abi.encode(
            _WHITELIST_HASH,
            whitelist.account,
            whitelist.amount,
            whitelist.phase
        ));
    }
}

File 21 of 23 : INonfungiblePositionManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "./IPoolInitializer.sol";

/// @title Non-fungible token for positions
/// @notice Wraps Thruster CLMM positions in a non-fungible token interface which allows for them to be transferred
/// and authorized.
interface INonfungiblePositionManager is IPoolInitializer, IERC721 {
    /// @notice Returns the position information associated with a given token ID.
    /// @dev Throws if the token ID is not valid.
    /// @param tokenId The ID of the token that represents the position
    /// @return nonce The nonce for permits
    /// @return operator The address that is approved for spending
    /// @return token0 The address of the token0 for a specific pool
    /// @return token1 The address of the token1 for a specific pool
    /// @return fee The fee associated with the pool
    /// @return tickLower The lower end of the tick range for the position
    /// @return tickUpper The higher end of the tick range for the position
    /// @return liquidity The liquidity of the position
    /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position
    /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position
    /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation
    /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation
    function positions(uint256 tokenId)
        external
        view
        returns (
            uint96 nonce,
            address operator,
            address token0,
            address token1,
            uint24 fee,
            int24 tickLower,
            int24 tickUpper,
            uint128 liquidity,
            uint256 feeGrowthInside0LastX128,
            uint256 feeGrowthInside1LastX128,
            uint128 tokensOwed0,
            uint128 tokensOwed1
        );

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

    /// @notice Creates a new position wrapped in a NFT
    /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized
    /// a method does not exist, i.e. the pool is assumed to be initialized.
    /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata
    /// @return tokenId The ID of the token that represents the minted position
    /// @return liquidity The amount of liquidity for this position
    /// @return amount0 The amount of token0
    /// @return amount1 The amount of token1
    function mint(MintParams calldata params)
        external
        payable
        returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);

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

    /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender`
    /// @param params tokenId The ID of the token for which liquidity is being increased,
    /// amount0Desired The desired amount of token0 to be spent,
    /// amount1Desired The desired amount of token1 to be spent,
    /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check,
    /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check,
    /// deadline The time by which the transaction must be included to effect the change
    /// @return liquidity The new liquidity amount as a result of the increase
    /// @return amount0 The amount of token0 to acheive resulting liquidity
    /// @return amount1 The amount of token1 to acheive resulting liquidity
    function increaseLiquidity(IncreaseLiquidityParams calldata params)
        external
        payable
        returns (uint128 liquidity, uint256 amount0, uint256 amount1);

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

    /// @notice Decreases the amount of liquidity in a position and accounts it to the position
    /// @param params tokenId The ID of the token for which liquidity is being decreased,
    /// amount The amount by which liquidity will be decreased,
    /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity,
    /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity,
    /// deadline The time by which the transaction must be included to effect the change
    /// @return amount0 The amount of token0 accounted to the position's tokens owed
    /// @return amount1 The amount of token1 accounted to the position's tokens owed
    function decreaseLiquidity(DecreaseLiquidityParams calldata params)
        external
        payable
        returns (uint256 amount0, uint256 amount1);

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

    /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient
    /// @param params tokenId The ID of the NFT for which tokens are being collected,
    /// recipient The account that should receive the tokens,
    /// amount0Max The maximum amount of token0 to collect,
    /// amount1Max The maximum amount of token1 to collect
    /// @return amount0 The amount of fees collected in token0
    /// @return amount1 The amount of fees collected in token1
    function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1);

    /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens
    /// must be collected first.
    /// @param tokenId The ID of the token that is being burned
    function burn(uint256 tokenId) external payable;
}

File 22 of 23 : IPoolInitializer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @title Creates and initializes V3 Pools
/// @notice Provides a method for creating and initializing a pool, if necessary, for bundling with other methods that
/// require the pool to exist.
interface IPoolInitializer {
    /// @notice Creates a new pool if it does not exist, then initializes if not initialized
    /// @dev This method can be bundled with others via IMulticall for the first action (e.g. mint) performed against a pool
    /// @param token0 The contract address of token0 of the pool
    /// @param token1 The contract address of token1 of the pool
    /// @param fee The fee amount of the v3 pool for the specified token pair
    /// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value
    /// @return pool Returns the pool address based on the pair of tokens and fee, will return the newly created pool address if necessary
    function createAndInitializePoolIfNecessary(
        address token0,
        address token1,
        uint24 fee,
        uint160 sqrtPriceX96
    ) external payable returns (address pool);
}

File 23 of 23 : TickMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @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));
        require(absTick <= uint256(uint24(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": 10000
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"nonfungiblePositionManager","type":"address"},{"internalType":"address","name":"weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyLinked","type":"error"},{"inputs":[],"name":"CannotLink","type":"error"},{"inputs":[],"name":"DepositAlreadyExists","type":"error"},{"inputs":[],"name":"InsufficientAmountForMint","type":"error"},{"inputs":[],"name":"InvalidMinter","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidStage","type":"error"},{"inputs":[],"name":"LiquidityLocked","type":"error"},{"inputs":[],"name":"MaxMintExceeded","type":"error"},{"inputs":[],"name":"NotLinked","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"SenderNotBase","type":"error"},{"inputs":[],"name":"SenderNotDeployer","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","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":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"Bid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"Bought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"}],"name":"CancelBid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"CancelOffer","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"idX","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"idY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exchangeFee","type":"uint256"}],"name":"Exchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"minPrice","type":"uint256"}],"name":"Offer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bool","name":"lockStatus","type":"bool"}],"name":"UpdateLockState","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINT_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addressToNumMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftOwner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseERC20","outputs":[{"internalType":"address","name":"base","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collectFees","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createLpPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentPhase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"extendLiquidityLock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"floorLockDeposit","outputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftOwner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityLockedUntil","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"begin","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"lockedIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"phase","type":"uint256"}],"internalType":"struct SignatureWhitelist.Whitelist","name":"_whitelist","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureWhitelist.Signature","name":"_signature","type":"tuple"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonfungiblePositionManager","outputs":[{"internalType":"contract INonfungiblePositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"begin","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"ownedIds","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":"ownerAt","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"pullOwner","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":"uint256","name":"phase","type":"uint256"}],"name":"setPhase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyDeposit","outputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_max","type":"uint256"}],"name":"supplyMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bool","name":"lock","type":"bool"}],"name":"updateLockState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6102206040526127106101a05266f52322698080006101c0526103e86101e05261251c610200526000600c819055600d819055600e553480156200004257600080fd5b50604051620042773803806200427783398101604081905262000065916200032f565b81816040518060400160405280601281526020017114da59db985d1d5c9955da1a5d195b1a5cdd60721b815250604051806040016040528060018152602001603160f81b815250620000c2600083620001ba60201b90919060201c565b61012052620000d3816001620001ba565b61014052815160208084019190912060e052815190820120610100524660a0526200016160e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c0526001600160a01b03918216610160521661018052683602298b8c10b0123180546001600160a01b03191633179055620001a2620001f3565b620001ad3362000277565b50506000600d55620005b2565b6000602083511015620001da57620001d283620002c6565b9050620001ed565b81620001e784826200040e565b5060ff90505b92915050565b4662013e3103620002755760405163c8992e6160e01b815273430000000000000000000000000000000000000290819063c8992e61906200023f906002906001903390600401620004f0565b600060405180830381600087803b1580156200025a57600080fd5b505af11580156200026f573d6000803e3d6000fd5b50505050505b565b4662013e3103620002c3576040516336b91f2b60e01b81526001600160a01b0382166004820152732536fe9ab3f511540f2f9e2ec2a805005c3dd800906336b91f2b906024016200023f565b50565b600080829050601f81511115620002fd578260405163305a27a960e01b8152600401620002f491906200053c565b60405180910390fd5b80516200030a826200058d565b179392505050565b80516001600160a01b03811681146200032a57600080fd5b919050565b600080604083850312156200034357600080fd5b6200034e8362000312565b91506200035e6020840162000312565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200039257607f821691505b602082108103620003b357634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000409576000816000526020600020601f850160051c81016020861015620003e45750805b601f850160051c820191505b818110156200040557828155600101620003f0565b5050505b505050565b81516001600160401b038111156200042a576200042a62000367565b62000442816200043b84546200037d565b84620003b9565b602080601f8311600181146200047a5760008415620004615750858301515b600019600386901b1c1916600185901b17855562000405565b600085815260208120601f198616915b82811015620004ab578886015182559484019460019091019084016200048a565b5085821015620004ca5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052602160045260246000fd5b6060810160038510620005075762000507620004da565b848252600284106200051d576200051d620004da565b60208201939093526001600160a01b0391909116604090910152919050565b60006020808352835180602085015260005b818110156200056c578581018301518582016040015282016200054e565b506000604082860101526040601f19601f8301168501019250505092915050565b80516020808301519190811015620003b35760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051613ba3620006d460003960008181610e090152611814015260006117a80152600081816109fa01528181610e73015261173f01526000818161078f015281816110a901526119cd0152600081816107d80152818161255801528181612586015281816125bd015281816129c80152612a9601526000818161098601528181611e4901528181611f850152818161226f01528181612370015281816125fe01528181612a6701528181612bd501528181612e140152612f8d015260006121b80152600061218b015260006131f8015260006131d00152600061312b015260006131550152600061317f0152613ba36000f3fe6080604052600436106102bf5760003560e01c80636cef16e61161016e578063bf598e1e116100cb578063ce0785ee1161007f578063e985e9c511610064578063e985e9c514610abc578063ec6f7a3e14610adc578063f39c040e14610af1576102c6565b8063ce0785ee14610a7c578063e75c907214610aa9576102c6565b8063c1292cc3116100b0578063c1292cc314610a1c578063c879657214610a32578063c87b56dd14610a5c576102c6565b8063bf598e1e146109c8578063c002d23d146109e8576102c6565b806395d89b4111610122578063a22cb46511610107578063a22cb46514610954578063b44a272214610974578063b88d4fde146109a8576102c6565b806395d89b411461092a57806397e5311c1461093f576102c6565b80637ec82418116101535780637ec82418146108bc57806384b0196e146108dc5780638da5cb5b14610904576102c6565b80636cef16e61461088757806370a082311461089c576102c6565b8063243598791161021c5780633fc8cef3116101d057806345a42293116101b557806345a422931461081a5780636352211e1461083a578063680a9f1f1461085a576102c6565b80633fc8cef3146107c657806342842e0e146107fa576102c6565b80632db11544116102015780632db115441461076a57806332cb6b0c1461077d5780633ccfd60b146107b1576102c6565b8063243598791461072a5780632cc826551461074a576102c6565b80630a26cc2c1161027357806318160ddd1161025857806318160ddd14610667578063201886771461067c57806323b872dd1461070a576102c6565b80630a26cc2c1461063157806314669b8b14610651576102c6565b806306fdde03116102a457806306fdde03146105b7578063081812fc146105d9578063095ea7b314610611576102c6565b806301ffc9a714610541578063055ad42e14610593576102c6565b366102c657005b683602298b8c10b0123060003560e01c63263c69d68190036103ab5781546001600160a01b03163314610325576040517f363cb31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602036103d60003e6004356024018036103d60003e602081033560051b81018036103d60003e5b80821461039e5781358060601c816001168260a01b60a81c811583028284027fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a450505081602001915061034c565b5050600160005260206000f35b8063144027d30361045a5781546001600160a01b031633146103f9576040517f363cb31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600435602435604435602401602081033560051b81015b80821461044b57813583857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a4816020019150610410565b50505050600160005260206000f35b80630f4599e50361053f5760018201546001600160a01b0316156104c95760018201546001600160a01b03166004356001600160a01b0316146104c9576040517fc59ec47a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546001600160a01b03161561050b576040517fbf656a4600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317825560016000908152602090f35b005b34801561054d57600080fd5b5061057e61055c36600461328a565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b34801561059f57600080fd5b506105a9600e5481565b60405190815260200161058a565b3480156105c357600080fd5b506105cc610b38565b60405161058a9190613341565b3480156105e557600080fd5b506105f96105f4366004613354565b610b4e565b6040516001600160a01b03909116815260200161058a565b34801561061d57600080fd5b5061053f61062c366004613382565b610b66565b34801561063d57600080fd5b5061053f61064c366004613354565b610bec565b34801561065d57600080fd5b506105a9600d5481565b34801561067357600080fd5b506105a9610c40565b34801561068857600080fd5b506002546003546004546005546006546106c394936001600160a01b03908116936fffffffffffffffffffffffffffffffff16928116911685565b604080519586526001600160a01b0394851660208701526fffffffffffffffffffffffffffffffff909316928501929092528216606084015216608082015260a00161058a565b34801561071657600080fd5b5061053f6107253660046133ae565b610c52565b34801561073657600080fd5b506105f9610745366004613354565b610d37565b34801561075657600080fd5b5061053f610765366004613354565b610d49565b61053f610778366004613354565b610d56565b34801561078957600080fd5b506105a97f000000000000000000000000000000000000000000000000000000000000000081565b3480156107bd57600080fd5b5061053f610f92565b3480156107d257600080fd5b506105f97f000000000000000000000000000000000000000000000000000000000000000081565b34801561080657600080fd5b5061053f6108153660046133ae565b61102c565b34801561082657600080fd5b5061053f610835366004613354565b61105e565b34801561084657600080fd5b506105f9610855366004613354565b61117f565b34801561086657600080fd5b5061087a6108753660046133ef565b611191565b60405161058a9190613460565b34801561089357600080fd5b5061053f6111a8565b3480156108a857600080fd5b506105a96108b7366004613473565b611273565b3480156108c857600080fd5b5061053f6108d736600461352c565b61128e565b3480156108e857600080fd5b506108f161140e565b60405161058a97969594939291906135e4565b34801561091057600080fd5b50683602298b8c10b01232546001600160a01b03166105f9565b34801561093657600080fd5b506105cc611470565b34801561094b57600080fd5b506105f9611481565b34801561096057600080fd5b5061053f61096f36600461366e565b6114cf565b34801561098057600080fd5b506105f97f000000000000000000000000000000000000000000000000000000000000000081565b3480156109b457600080fd5b5061053f6109c33660046136a7565b611552565b3480156109d457600080fd5b5061087a6109e33660046133ef565b6115ad565b3480156109f457600080fd5b506105a97f000000000000000000000000000000000000000000000000000000000000000081565b348015610a2857600080fd5b506105a9600c5481565b348015610a3e57600080fd5b50610a476115bc565b6040805192835260208301919091520161058a565b348015610a6857600080fd5b506105cc610a77366004613354565b6115d8565b348015610a8857600080fd5b506105a9610a97366004613473565b600f6020526000908152604090205481565b61053f610ab736600461375e565b6115e8565b348015610ac857600080fd5b5061057e610ad736600461379c565b61192d565b348015610ae857600080fd5b5061053f611959565b348015610afd57600080fd5b50600754600854600954600a54600b546106c394936001600160a01b03908116936fffffffffffffffffffffffffffffffff16928116911685565b6060610b496306fdde036000611b72565b905090565b6000610b6063081812fc836000611bcf565b92915050565b6000610b70611481565b90508260601b60601c925060405163d10b6e0c600052836020528260405233606052602060006064601c34865af1601f3d1116610bb0573d6000823e3d81fd5b806040525060006060528183600c5160601c7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600038a4505050565b610bf4611c17565b42600d541115610c30576040517f8f4e75b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c3a81426137f9565b600d5550565b6000610b4963e2c79281600080611bcf565b6000610c5c611481565b90508360601b60601c93508260601b60601c925060405163e5eb36c881528460208201528360408201528260608201523360808201526020816084601c840134865af1600182511416610cb2573d6000823e3d81fd5b6000815282857fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac602084a38284867fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a46001815282847fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac602084a35050505050565b6000610b606324359879836000611bcf565b610d51611c17565b600e55565b600e54600314610d92576040517fe82a532900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003610dcc576040517fa0f8efc500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002811115610e07576040517f79d2bf0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081600c54610e3691906137f9565b1115610e6e576040517f79d2bf0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e987f00000000000000000000000000000000000000000000000000000000000000008261380c565b3414610ed0576040517fa0f8efc500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600f602052604081208054839290610eef9084906137f9565b90915550600090508167ffffffffffffffff811115610f1057610f10613490565b604051908082528060200260200182016040528015610f39578160200160208202803683370190505b50905060005b82811015610f8157600c60008154610f5690613823565b919050819055828281518110610f6e57610f6e61385b565b6020908102919091010152600101610f3f565b50610f8e33826000611c7a565b5050565b610f9a611c17565b42600d541115610fd6576040517f8f4e75b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b47801561102157683602298b8c10b01232546040516001600160a01b039091169082156108fc029083906000818181858888f1935050505015801561101f573d6000803e3d6000fd5b505b611029611e02565b50565b611037838383610c52565b813b15611059576110598383836040518060200160405280600081525061207b565b505050565b611066611c17565b600e546004146110a2576040517fe82a532900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c547f00000000000000000000000000000000000000000000000000000000000000006110d2919061388a565b9050818111156110df5750805b60008167ffffffffffffffff8111156110fa576110fa613490565b604051908082528060200260200182016040528015611123578160200160208202803683370190505b50905060005b8281101561116b57600c6000815461114090613823565b9190508190558282815181106111585761115861385b565b6020908102919091010152600101611129565b50611059611177611481565b826000611c7a565b6000610b60636352211e836000611bcf565b60606111a08484846001612107565b949350505050565b6000806111b3611481565b9050638da5cb5b600052602060006004601c845afa601f3d1116156111db57600c5160601c91505b683602298b8c10b0123254683602298b8c10b01230906001600160a01b03908116908416811461126d576002820180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0386811691821790925560405190918316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35b50505050565b6000610b6063f5b100ea836001600160a01b03166000611bcf565b6000611298611481565b9050600080826001600160a01b0316846112b35760006112b6565b60015b60ff166060336001600160a01b0316901b17866040516024016112da92919061389d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb79cc1bd000000000000000000000000000000000000000000000000000000001790525161135b91906138b6565b6000604051808303816000865af19150503d8060008114611398576040519150601f19603f3d011682016040523d82523d6000602084013e61139d565b606091505b5091509150816001602083015114166113b857805160208201fd5b845184600052602086018160051b81015b808214611404578151337fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60206000a36020820191506113c9565b5050505050505050565b600060608060008060006060611422612184565b61142a6121b1565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b6060610b496395d89b416000611b72565b683602298b8c10b01230546001600160a01b0316806114cc576040517f5b2a47ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b90565b60006114d9611481565b90508260601b60601c925060405163813500fc6000528360205282151560405233606052602060006064601c34865af16001600051141661151d573d6000823e3d81fd5b83337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206040a36040525050600060605250565b61155d858585610c52565b833b156115a6576115a685858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061207b92505050565b5050505050565b60606111a08484846000612107565b6000806115c7611c17565b6115cf6121de565b90939092509050565b6060610b6063c87b56dd83611b72565b61160c8282611607683602298b8c10b01232546001600160a01b031690565b612401565b82600003611646576040517fa0f8efc500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336116546020840184613473565b6001600160a01b031614611694576040517fd8d5894f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e54826040013511806116aa5750600e546004145b156116e1576040517fe82a532900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600f60209081526040909120549083013561170285836137f9565b111561173a576040517f79d2bf0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117647f00000000000000000000000000000000000000000000000000000000000000008561380c565b341461179c576040517fa0f8efc500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e54600003611812577f000000000000000000000000000000000000000000000000000000000000000084600c546117d591906137f9565b111561180d576040517f79d2bf0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611879565b7f000000000000000000000000000000000000000000000000000000000000000084600c5461184191906137f9565b1115611879576040517f79d2bf0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61188384826137f9565b336000908152600f60205260408120919091558467ffffffffffffffff8111156118af576118af613490565b6040519080825280602002602001820160405280156118d8578160200160208202803683370190505b50905060005b8581101561192057600c600081546118f590613823565b91905081905582828151811061190d5761190d61385b565b60209081029190910101526001016118de565b506115a633826000611c7a565b600061195063e985e9c5846001600160a01b0316846001600160a01b0316611bcf565b15159392505050565b611961611c17565b600e5460041461199d576040517fe82a532900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119a5611481565b6040517fb001bebf0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201526001600160a01b03919091169063b001bebf90602401600060405180830381600087803b158015611a2157600080fd5b505af1158015611a35573d6000803e3d6000fd5b50505050611a49611a44611481565b61254b565b6000611a53611481565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611ab2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad691906138d2565b9050801561102957611ae6611481565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018390526001600160a01b03919091169063a9059cbb906044016020604051808303816000875af1158015611b4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8e91906138eb565b60606000611b7e611481565b9050604051915083600052826020526000806024601c845afa611ba4573d6000833e3d82fd5b60206000803e6020600051833e8151602060005101602084013e815160208301016040525092915050565b600080611bda611481565b9050604051856000528460205283604052602060006044601c855afa601f3d1116611c08573d6000823e3d81fd5b60405250506000519392505050565b33611c32683602298b8c10b01232546001600160a01b031690565b6001600160a01b031614611c78576040517f118cdaa700000000000000000000000000000000000000000000000000000000815233600482015260240160405180910390fd5b565b6000611c84611481565b9050600080826001600160a01b031684611c9f576000611ca2565b60015b60ff166060886001600160a01b0316901b1786604051602401611cc692919061389d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f3e0446a10000000000000000000000000000000000000000000000000000000017905251611d4791906138b6565b6000604051808303816000865af19150503d8060008114611d84576040519150601f19603f3d011682016040523d82523d6000602084013e611d89565b606091505b509150915081600160208301511416611da457805160208201fd5b845184600052602086018160051b81015b808214611df75786611dec5781513360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a45b602082019150611db5565b505050505050505050565b60025415611f3e576002546040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015233602482015260448101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd90606401600060405180830381600087803b158015611e9557600080fd5b505af1158015611ea9573d6000803e3d6000fd5b50506040805160a081018252600080825260208201819052918101829052606081018290526080018190526002555050600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600480547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016905560058054821690556006805490911690555b60075415611c78576007546040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015233602482015260448101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd90606401600060405180830381600087803b158015611fd157600080fd5b505af1158015611fe5573d6000803e3d6000fd5b50506040805160a081018252600080825260208201819052918101829052606081018290526080018190526007555050600880547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600980547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169055600a805482169055600b80549091169055565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a084015280156120c2578060c08401826020870160045afa505b60208360a48301601c860160008a5af16120e5573d156120e5573d6000843e3d83fd5b508060e01b8251146120ff5763d1a57ed66000526004601cfd5b505050505050565b60606000612113611481565b9050604051915063f9b4b3286000528215158660601b1760205284604052836060526000806064601c845afa61214c573d6000833e3d82fd5b60206000803e6020600051833e815160051b602060005101602084013e815160051b6020830101604052600060605250949350505050565b6060610b497f000000000000000000000000000000000000000000000000000000000000000060006127b6565b6060610b497f000000000000000000000000000000000000000000000000000000000000000060016127b6565b60408051608081018252600254815233602082019081526fffffffffffffffffffffffffffffffff8284018181526060840182815294517ffc6f78650000000000000000000000000000000000000000000000000000000081529351600485015291516001600160a01b039081166024850152915181166044840152925190921660648201526000918291829182917f00000000000000000000000000000000000000000000000000000000000000009091169063fc6f78659060840160408051808303816000875af11580156122b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122dd9190613908565b60408051608081018252600754815233602082019081526fffffffffffffffffffffffffffffffff8284018181526060840182815294517ffc6f78650000000000000000000000000000000000000000000000000000000081529351600485015291516001600160a01b0390811660248501529151811660448401529251909216606482015292945090925060009182917f0000000000000000000000000000000000000000000000000000000000000000169063fc6f78659060840160408051808303816000875af11580156123b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123dc9190613908565b90925090506123eb82856137f9565b95506123f781846137f9565b9450505050509091565b600061248c6124876124183687900387018761392c565b805160208083015160409384015184517f1e03cf0c175e650b80d30d533afcaa4ec6c7589d3c102e13e2d16ad6c1b4686b818501526001600160a01b039094168486015260608401919091526080808401919091528351808403909101815260a0909201909252805191012090565b612861565b905060006001826124a0602087018761398e565b604080516000815260208181018084529490945260ff9092168282015291870135606082015290860135608082015260a0016020604051602081039080840390855afa1580156124f4573d6000803e3d6000fd5b505050602060405103519050826001600160a01b0316816001600160a01b0316146115a6576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bb86001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116908316106000816125aa577f00000000000000000000000000000000000000000000000000000000000000006125ac565b835b90506000826125bb57846125dd565b7f00000000000000000000000000000000000000000000000000000000000000005b905060008060008060006125f0886128a9565b9450945094509450945060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166313ead56289898d8a6040518563ffffffff1660e01b815260040161267994939291906001600160a01b039485168152928416602084015262ffffff919091166040830152909116606082015260800190565b6020604051808303816000875af1158015612698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126bc91906139b1565b90508a6001600160a01b031663a0ae8d056040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156126f957600080fd5b505af115801561270d573d6000803e3d6000fd5b50506040517f07a19f720000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152600160248301528e1692506307a19f729150604401600060405180830381600087803b15801561277457600080fd5b505af1158015612788573d6000803e3d6000fd5b5050505061279a8989898d8989612987565b6127a98989898e8e8888612d26565b5050505050505050505050565b606060ff83146127d0576127c9836130df565b9050610b60565b8180546127dc906139ce565b80601f0160208091040260200160405190810160405280929190818152602001828054612808906139ce565b80156128555780601f1061282a57610100808354040283529160200191612855565b820191906000526020600020905b81548152906001019060200180831161283857829003601f168201915b50505050509050610b60565b6000610b6061286e61311e565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6000806000806000851561293957506b02206205d4d70b66e052639a93507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe897892507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe89b491507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe89f09050620d89b461297e565b506c7862c74490707c52727f6abd4593506201764c92506201768891507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2764c9050620176105b91939590929450565b600254156129c1576040517fc44bd76500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60004790507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a2157600080fd5b505af1158015612a35573d6000803e3d6000fd5b50506040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063095ea7b3925060440190506020604051808303816000875af1158015612ae3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b0791906138eb565b506000604051806101600160405280886001600160a01b03168152602001876001600160a01b031681526020018662ffffff1681526020018560020b81526020018460020b815260200189612b5c5783612b5f565b60005b815260200189612b70576000612b72565b835b815260200189612b825783612b85565b60005b815260200189612b96576000612b98565b835b815230602082015242604091820152517f8831645600000000000000000000000000000000000000000000000000000000815290915060009081907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690638831645690612c12908690600401613a1b565b6080604051808303816000875af1158015612c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c559190613adf565b50506040805160a08101825283815230602082018190526fffffffffffffffffffffffffffffffff9093169181018290526001600160a01b039c8d16606082018190529b909c166080909c018c9052600292909255600380547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169092179055600480547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016909217909155600580548216909917909855505060068054909616909617909455505050505050565b60075415612d60576040517fc44bd76500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038616906370a0823190602401602060405180830381865afa158015612dc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de491906138d2565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390529192509086169063095ea7b3906044016020604051808303816000875af1158015612e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9491906138eb565b506000604051806101600160405280896001600160a01b03168152602001886001600160a01b031681526020018662ffffff1681526020018560020b81526020018460020b81526020018a612eea576000612eec565b835b81526020018a612efc5783612eff565b60005b81526020018a612f10576000612f27565b600a612f1d85600961380c565b612f279190613b32565b81526020018a612f4d57600a612f3e85600961380c565b612f489190613b32565b612f50565b60005b815230602082015242604091820152517f8831645600000000000000000000000000000000000000000000000000000000815290915060009081907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690638831645690612fca908690600401613a1b565b6080604051808303816000875af1158015612fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061300d9190613adf565b50506040805160a08101825283815230602082018190526fffffffffffffffffffffffffffffffff9093169181018290526001600160a01b039d8e16606082018190529c909d166080909d018d9052600792909255600880547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169092179055600980547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016909217909155600a80548216909a179099555050600b805490971690971790955550505050505050565b606060006130ec83613249565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561317757507f000000000000000000000000000000000000000000000000000000000000000046145b156131a157507f000000000000000000000000000000000000000000000000000000000000000090565b610b49604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b600060ff8216601f811115610b60576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561329c57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146132cc57600080fd5b9392505050565b60005b838110156132ee5781810151838201526020016132d6565b50506000910152565b6000815180845261330f8160208601602086016132d3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006132cc60208301846132f7565b60006020828403121561336657600080fd5b5035919050565b6001600160a01b038116811461102957600080fd5b6000806040838503121561339557600080fd5b82356133a08161336d565b946020939093013593505050565b6000806000606084860312156133c357600080fd5b83356133ce8161336d565b925060208401356133de8161336d565b929592945050506040919091013590565b60008060006060848603121561340457600080fd5b833561340f8161336d565b95602085013595506040909401359392505050565b60008151808452602080850194506020840160005b8381101561345557815187529582019590820190600101613439565b509495945050505050565b6020815260006132cc6020830184613424565b60006020828403121561348557600080fd5b81356132cc8161336d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561350657613506613490565b604052919050565b801515811461102957600080fd5b80356135278161350e565b919050565b6000806040838503121561353f57600080fd5b823567ffffffffffffffff8082111561355757600080fd5b818501915085601f83011261356b57600080fd5b813560208282111561357f5761357f613490565b8160051b92506135908184016134bf565b82815292840181019281810190898511156135aa57600080fd5b948201945b848610156135c8578535825294820194908201906135af565b96506135d7905087820161351c565b9450505050509250929050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e06020820152600061361f60e08301896132f7565b828103604084015261363181896132f7565b90508660608401526001600160a01b03861660808401528460a084015282810360c08401526136608185613424565b9a9950505050505050505050565b6000806040838503121561368157600080fd5b823561368c8161336d565b9150602083013561369c8161350e565b809150509250929050565b6000806000806000608086880312156136bf57600080fd5b85356136ca8161336d565b945060208601356136da8161336d565b935060408601359250606086013567ffffffffffffffff808211156136fe57600080fd5b818801915088601f83011261371257600080fd5b81358181111561372157600080fd5b89602082850101111561373357600080fd5b9699959850939650602001949392505050565b60006060828403121561375857600080fd5b50919050565b600080600060e0848603121561377357600080fd5b833592506137848560208601613746565b91506137938560808601613746565b90509250925092565b600080604083850312156137af57600080fd5b82356137ba8161336d565b9150602083013561369c8161336d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610b6057610b606137ca565b8082028115828204841417610b6057610b606137ca565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613854576138546137ca565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81810381811115610b6057610b606137ca565b8281526040602082015260006111a06040830184613424565b600082516138c88184602087016132d3565b9190910192915050565b6000602082840312156138e457600080fd5b5051919050565b6000602082840312156138fd57600080fd5b81516132cc8161350e565b6000806040838503121561391b57600080fd5b505080516020909101519092909150565b60006060828403121561393e57600080fd5b6040516060810181811067ffffffffffffffff8211171561396157613961613490565b604052823561396f8161336d565b8152602083810135908201526040928301359281019290925250919050565b6000602082840312156139a057600080fd5b813560ff811681146132cc57600080fd5b6000602082840312156139c357600080fd5b81516132cc8161336d565b600181811c908216806139e257607f821691505b602082108103613758577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b81516001600160a01b0316815261016081016020830151613a4760208401826001600160a01b03169052565b506040830151613a5e604084018262ffffff169052565b506060830151613a73606084018260020b9052565b506080830151613a88608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151613ace828501826001600160a01b03169052565b505061014092830151919092015290565b60008060008060808587031215613af557600080fd5b8451935060208501516fffffffffffffffffffffffffffffffff81168114613b1c57600080fd5b6040860151606090960151949790965092505050565b600082613b68577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea2646970667358221220085c6082360a24dae748cbd5d043c4bc6625cc86adfacf9fbe009518641e360264736f6c63430008180033000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f90000000000000000000000004300000000000000000000000000000000000004

Deployed Bytecode

0x6080604052600436106102bf5760003560e01c80636cef16e61161016e578063bf598e1e116100cb578063ce0785ee1161007f578063e985e9c511610064578063e985e9c514610abc578063ec6f7a3e14610adc578063f39c040e14610af1576102c6565b8063ce0785ee14610a7c578063e75c907214610aa9576102c6565b8063c1292cc3116100b0578063c1292cc314610a1c578063c879657214610a32578063c87b56dd14610a5c576102c6565b8063bf598e1e146109c8578063c002d23d146109e8576102c6565b806395d89b4111610122578063a22cb46511610107578063a22cb46514610954578063b44a272214610974578063b88d4fde146109a8576102c6565b806395d89b411461092a57806397e5311c1461093f576102c6565b80637ec82418116101535780637ec82418146108bc57806384b0196e146108dc5780638da5cb5b14610904576102c6565b80636cef16e61461088757806370a082311461089c576102c6565b8063243598791161021c5780633fc8cef3116101d057806345a42293116101b557806345a422931461081a5780636352211e1461083a578063680a9f1f1461085a576102c6565b80633fc8cef3146107c657806342842e0e146107fa576102c6565b80632db11544116102015780632db115441461076a57806332cb6b0c1461077d5780633ccfd60b146107b1576102c6565b8063243598791461072a5780632cc826551461074a576102c6565b80630a26cc2c1161027357806318160ddd1161025857806318160ddd14610667578063201886771461067c57806323b872dd1461070a576102c6565b80630a26cc2c1461063157806314669b8b14610651576102c6565b806306fdde03116102a457806306fdde03146105b7578063081812fc146105d9578063095ea7b314610611576102c6565b806301ffc9a714610541578063055ad42e14610593576102c6565b366102c657005b683602298b8c10b0123060003560e01c63263c69d68190036103ab5781546001600160a01b03163314610325576040517f363cb31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602036103d60003e6004356024018036103d60003e602081033560051b81018036103d60003e5b80821461039e5781358060601c816001168260a01b60a81c811583028284027fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a450505081602001915061034c565b5050600160005260206000f35b8063144027d30361045a5781546001600160a01b031633146103f9576040517f363cb31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600435602435604435602401602081033560051b81015b80821461044b57813583857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a4816020019150610410565b50505050600160005260206000f35b80630f4599e50361053f5760018201546001600160a01b0316156104c95760018201546001600160a01b03166004356001600160a01b0316146104c9576040517fc59ec47a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546001600160a01b03161561050b576040517fbf656a4600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317825560016000908152602090f35b005b34801561054d57600080fd5b5061057e61055c36600461328a565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b34801561059f57600080fd5b506105a9600e5481565b60405190815260200161058a565b3480156105c357600080fd5b506105cc610b38565b60405161058a9190613341565b3480156105e557600080fd5b506105f96105f4366004613354565b610b4e565b6040516001600160a01b03909116815260200161058a565b34801561061d57600080fd5b5061053f61062c366004613382565b610b66565b34801561063d57600080fd5b5061053f61064c366004613354565b610bec565b34801561065d57600080fd5b506105a9600d5481565b34801561067357600080fd5b506105a9610c40565b34801561068857600080fd5b506002546003546004546005546006546106c394936001600160a01b03908116936fffffffffffffffffffffffffffffffff16928116911685565b604080519586526001600160a01b0394851660208701526fffffffffffffffffffffffffffffffff909316928501929092528216606084015216608082015260a00161058a565b34801561071657600080fd5b5061053f6107253660046133ae565b610c52565b34801561073657600080fd5b506105f9610745366004613354565b610d37565b34801561075657600080fd5b5061053f610765366004613354565b610d49565b61053f610778366004613354565b610d56565b34801561078957600080fd5b506105a97f000000000000000000000000000000000000000000000000000000000000271081565b3480156107bd57600080fd5b5061053f610f92565b3480156107d257600080fd5b506105f97f000000000000000000000000430000000000000000000000000000000000000481565b34801561080657600080fd5b5061053f6108153660046133ae565b61102c565b34801561082657600080fd5b5061053f610835366004613354565b61105e565b34801561084657600080fd5b506105f9610855366004613354565b61117f565b34801561086657600080fd5b5061087a6108753660046133ef565b611191565b60405161058a9190613460565b34801561089357600080fd5b5061053f6111a8565b3480156108a857600080fd5b506105a96108b7366004613473565b611273565b3480156108c857600080fd5b5061053f6108d736600461352c565b61128e565b3480156108e857600080fd5b506108f161140e565b60405161058a97969594939291906135e4565b34801561091057600080fd5b50683602298b8c10b01232546001600160a01b03166105f9565b34801561093657600080fd5b506105cc611470565b34801561094b57600080fd5b506105f9611481565b34801561096057600080fd5b5061053f61096f36600461366e565b6114cf565b34801561098057600080fd5b506105f97f000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f981565b3480156109b457600080fd5b5061053f6109c33660046136a7565b611552565b3480156109d457600080fd5b5061087a6109e33660046133ef565b6115ad565b3480156109f457600080fd5b506105a97f00000000000000000000000000000000000000000000000000f523226980800081565b348015610a2857600080fd5b506105a9600c5481565b348015610a3e57600080fd5b50610a476115bc565b6040805192835260208301919091520161058a565b348015610a6857600080fd5b506105cc610a77366004613354565b6115d8565b348015610a8857600080fd5b506105a9610a97366004613473565b600f6020526000908152604090205481565b61053f610ab736600461375e565b6115e8565b348015610ac857600080fd5b5061057e610ad736600461379c565b61192d565b348015610ae857600080fd5b5061053f611959565b348015610afd57600080fd5b50600754600854600954600a54600b546106c394936001600160a01b03908116936fffffffffffffffffffffffffffffffff16928116911685565b6060610b496306fdde036000611b72565b905090565b6000610b6063081812fc836000611bcf565b92915050565b6000610b70611481565b90508260601b60601c925060405163d10b6e0c600052836020528260405233606052602060006064601c34865af1601f3d1116610bb0573d6000823e3d81fd5b806040525060006060528183600c5160601c7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600038a4505050565b610bf4611c17565b42600d541115610c30576040517f8f4e75b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c3a81426137f9565b600d5550565b6000610b4963e2c79281600080611bcf565b6000610c5c611481565b90508360601b60601c93508260601b60601c925060405163e5eb36c881528460208201528360408201528260608201523360808201526020816084601c840134865af1600182511416610cb2573d6000823e3d81fd5b6000815282857fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac602084a38284867fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a46001815282847fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac602084a35050505050565b6000610b606324359879836000611bcf565b610d51611c17565b600e55565b600e54600314610d92576040517fe82a532900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003610dcc576040517fa0f8efc500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002811115610e07576040517f79d2bf0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000251c81600c54610e3691906137f9565b1115610e6e576040517f79d2bf0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e987f00000000000000000000000000000000000000000000000000f52322698080008261380c565b3414610ed0576040517fa0f8efc500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600f602052604081208054839290610eef9084906137f9565b90915550600090508167ffffffffffffffff811115610f1057610f10613490565b604051908082528060200260200182016040528015610f39578160200160208202803683370190505b50905060005b82811015610f8157600c60008154610f5690613823565b919050819055828281518110610f6e57610f6e61385b565b6020908102919091010152600101610f3f565b50610f8e33826000611c7a565b5050565b610f9a611c17565b42600d541115610fd6576040517f8f4e75b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b47801561102157683602298b8c10b01232546040516001600160a01b039091169082156108fc029083906000818181858888f1935050505015801561101f573d6000803e3d6000fd5b505b611029611e02565b50565b611037838383610c52565b813b15611059576110598383836040518060200160405280600081525061207b565b505050565b611066611c17565b600e546004146110a2576040517fe82a532900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c547f00000000000000000000000000000000000000000000000000000000000027106110d2919061388a565b9050818111156110df5750805b60008167ffffffffffffffff8111156110fa576110fa613490565b604051908082528060200260200182016040528015611123578160200160208202803683370190505b50905060005b8281101561116b57600c6000815461114090613823565b9190508190558282815181106111585761115861385b565b6020908102919091010152600101611129565b50611059611177611481565b826000611c7a565b6000610b60636352211e836000611bcf565b60606111a08484846001612107565b949350505050565b6000806111b3611481565b9050638da5cb5b600052602060006004601c845afa601f3d1116156111db57600c5160601c91505b683602298b8c10b0123254683602298b8c10b01230906001600160a01b03908116908416811461126d576002820180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0386811691821790925560405190918316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35b50505050565b6000610b6063f5b100ea836001600160a01b03166000611bcf565b6000611298611481565b9050600080826001600160a01b0316846112b35760006112b6565b60015b60ff166060336001600160a01b0316901b17866040516024016112da92919061389d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb79cc1bd000000000000000000000000000000000000000000000000000000001790525161135b91906138b6565b6000604051808303816000865af19150503d8060008114611398576040519150601f19603f3d011682016040523d82523d6000602084013e61139d565b606091505b5091509150816001602083015114166113b857805160208201fd5b845184600052602086018160051b81015b808214611404578151337fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60206000a36020820191506113c9565b5050505050505050565b600060608060008060006060611422612184565b61142a6121b1565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b6060610b496395d89b416000611b72565b683602298b8c10b01230546001600160a01b0316806114cc576040517f5b2a47ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b90565b60006114d9611481565b90508260601b60601c925060405163813500fc6000528360205282151560405233606052602060006064601c34865af16001600051141661151d573d6000823e3d81fd5b83337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206040a36040525050600060605250565b61155d858585610c52565b833b156115a6576115a685858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061207b92505050565b5050505050565b60606111a08484846000612107565b6000806115c7611c17565b6115cf6121de565b90939092509050565b6060610b6063c87b56dd83611b72565b61160c8282611607683602298b8c10b01232546001600160a01b031690565b612401565b82600003611646576040517fa0f8efc500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336116546020840184613473565b6001600160a01b031614611694576040517fd8d5894f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e54826040013511806116aa5750600e546004145b156116e1576040517fe82a532900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600f60209081526040909120549083013561170285836137f9565b111561173a576040517f79d2bf0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117647f00000000000000000000000000000000000000000000000000f52322698080008561380c565b341461179c576040517fa0f8efc500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e54600003611812577f00000000000000000000000000000000000000000000000000000000000003e884600c546117d591906137f9565b111561180d576040517f79d2bf0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611879565b7f000000000000000000000000000000000000000000000000000000000000251c84600c5461184191906137f9565b1115611879576040517f79d2bf0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61188384826137f9565b336000908152600f60205260408120919091558467ffffffffffffffff8111156118af576118af613490565b6040519080825280602002602001820160405280156118d8578160200160208202803683370190505b50905060005b8581101561192057600c600081546118f590613823565b91905081905582828151811061190d5761190d61385b565b60209081029190910101526001016118de565b506115a633826000611c7a565b600061195063e985e9c5846001600160a01b0316846001600160a01b0316611bcf565b15159392505050565b611961611c17565b600e5460041461199d576040517fe82a532900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119a5611481565b6040517fb001bebf0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000271060048201526001600160a01b03919091169063b001bebf90602401600060405180830381600087803b158015611a2157600080fd5b505af1158015611a35573d6000803e3d6000fd5b50505050611a49611a44611481565b61254b565b6000611a53611481565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611ab2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad691906138d2565b9050801561102957611ae6611481565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018390526001600160a01b03919091169063a9059cbb906044016020604051808303816000875af1158015611b4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8e91906138eb565b60606000611b7e611481565b9050604051915083600052826020526000806024601c845afa611ba4573d6000833e3d82fd5b60206000803e6020600051833e8151602060005101602084013e815160208301016040525092915050565b600080611bda611481565b9050604051856000528460205283604052602060006044601c855afa601f3d1116611c08573d6000823e3d81fd5b60405250506000519392505050565b33611c32683602298b8c10b01232546001600160a01b031690565b6001600160a01b031614611c78576040517f118cdaa700000000000000000000000000000000000000000000000000000000815233600482015260240160405180910390fd5b565b6000611c84611481565b9050600080826001600160a01b031684611c9f576000611ca2565b60015b60ff166060886001600160a01b0316901b1786604051602401611cc692919061389d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f3e0446a10000000000000000000000000000000000000000000000000000000017905251611d4791906138b6565b6000604051808303816000865af19150503d8060008114611d84576040519150601f19603f3d011682016040523d82523d6000602084013e611d89565b606091505b509150915081600160208301511416611da457805160208201fd5b845184600052602086018160051b81015b808214611df75786611dec5781513360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a45b602082019150611db5565b505050505050505050565b60025415611f3e576002546040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015233602482015260448101919091527f000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f96001600160a01b0316906323b872dd90606401600060405180830381600087803b158015611e9557600080fd5b505af1158015611ea9573d6000803e3d6000fd5b50506040805160a081018252600080825260208201819052918101829052606081018290526080018190526002555050600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600480547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016905560058054821690556006805490911690555b60075415611c78576007546040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015233602482015260448101919091527f000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f96001600160a01b0316906323b872dd90606401600060405180830381600087803b158015611fd157600080fd5b505af1158015611fe5573d6000803e3d6000fd5b50506040805160a081018252600080825260208201819052918101829052606081018290526080018190526007555050600880547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600980547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169055600a805482169055600b80549091169055565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a084015280156120c2578060c08401826020870160045afa505b60208360a48301601c860160008a5af16120e5573d156120e5573d6000843e3d83fd5b508060e01b8251146120ff5763d1a57ed66000526004601cfd5b505050505050565b60606000612113611481565b9050604051915063f9b4b3286000528215158660601b1760205284604052836060526000806064601c845afa61214c573d6000833e3d82fd5b60206000803e6020600051833e815160051b602060005101602084013e815160051b6020830101604052600060605250949350505050565b6060610b497f5369676e617475726557686974656c697374000000000000000000000000001260006127b6565b6060610b497f310000000000000000000000000000000000000000000000000000000000000160016127b6565b60408051608081018252600254815233602082019081526fffffffffffffffffffffffffffffffff8284018181526060840182815294517ffc6f78650000000000000000000000000000000000000000000000000000000081529351600485015291516001600160a01b039081166024850152915181166044840152925190921660648201526000918291829182917f000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f99091169063fc6f78659060840160408051808303816000875af11580156122b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122dd9190613908565b60408051608081018252600754815233602082019081526fffffffffffffffffffffffffffffffff8284018181526060840182815294517ffc6f78650000000000000000000000000000000000000000000000000000000081529351600485015291516001600160a01b0390811660248501529151811660448401529251909216606482015292945090925060009182917f000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f9169063fc6f78659060840160408051808303816000875af11580156123b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123dc9190613908565b90925090506123eb82856137f9565b95506123f781846137f9565b9450505050509091565b600061248c6124876124183687900387018761392c565b805160208083015160409384015184517f1e03cf0c175e650b80d30d533afcaa4ec6c7589d3c102e13e2d16ad6c1b4686b818501526001600160a01b039094168486015260608401919091526080808401919091528351808403909101815260a0909201909252805191012090565b612861565b905060006001826124a0602087018761398e565b604080516000815260208181018084529490945260ff9092168282015291870135606082015290860135608082015260a0016020604051602081039080840390855afa1580156124f4573d6000803e3d6000fd5b505050602060405103519050826001600160a01b0316816001600160a01b0316146115a6576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bb86001600160a01b037f00000000000000000000000043000000000000000000000000000000000000048116908316106000816125aa577f00000000000000000000000043000000000000000000000000000000000000046125ac565b835b90506000826125bb57846125dd565b7f00000000000000000000000043000000000000000000000000000000000000045b905060008060008060006125f0886128a9565b9450945094509450945060007f000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f96001600160a01b03166313ead56289898d8a6040518563ffffffff1660e01b815260040161267994939291906001600160a01b039485168152928416602084015262ffffff919091166040830152909116606082015260800190565b6020604051808303816000875af1158015612698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126bc91906139b1565b90508a6001600160a01b031663a0ae8d056040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156126f957600080fd5b505af115801561270d573d6000803e3d6000fd5b50506040517f07a19f720000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152600160248301528e1692506307a19f729150604401600060405180830381600087803b15801561277457600080fd5b505af1158015612788573d6000803e3d6000fd5b5050505061279a8989898d8989612987565b6127a98989898e8e8888612d26565b5050505050505050505050565b606060ff83146127d0576127c9836130df565b9050610b60565b8180546127dc906139ce565b80601f0160208091040260200160405190810160405280929190818152602001828054612808906139ce565b80156128555780601f1061282a57610100808354040283529160200191612855565b820191906000526020600020905b81548152906001019060200180831161283857829003601f168201915b50505050509050610b60565b6000610b6061286e61311e565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6000806000806000851561293957506b02206205d4d70b66e052639a93507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe897892507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe89b491507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe89f09050620d89b461297e565b506c7862c74490707c52727f6abd4593506201764c92506201768891507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2764c9050620176105b91939590929450565b600254156129c1576040517fc44bd76500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60004790507f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a2157600080fd5b505af1158015612a35573d6000803e3d6000fd5b50506040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f981166004830152602482018690527f000000000000000000000000430000000000000000000000000000000000000416935063095ea7b3925060440190506020604051808303816000875af1158015612ae3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b0791906138eb565b506000604051806101600160405280886001600160a01b03168152602001876001600160a01b031681526020018662ffffff1681526020018560020b81526020018460020b815260200189612b5c5783612b5f565b60005b815260200189612b70576000612b72565b835b815260200189612b825783612b85565b60005b815260200189612b96576000612b98565b835b815230602082015242604091820152517f8831645600000000000000000000000000000000000000000000000000000000815290915060009081907f000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f96001600160a01b031690638831645690612c12908690600401613a1b565b6080604051808303816000875af1158015612c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c559190613adf565b50506040805160a08101825283815230602082018190526fffffffffffffffffffffffffffffffff9093169181018290526001600160a01b039c8d16606082018190529b909c166080909c018c9052600292909255600380547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169092179055600480547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016909217909155600580548216909917909855505060068054909616909617909455505050505050565b60075415612d60576040517fc44bd76500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038616906370a0823190602401602060405180830381865afa158015612dc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de491906138d2565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f981166004830152602482018390529192509086169063095ea7b3906044016020604051808303816000875af1158015612e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9491906138eb565b506000604051806101600160405280896001600160a01b03168152602001886001600160a01b031681526020018662ffffff1681526020018560020b81526020018460020b81526020018a612eea576000612eec565b835b81526020018a612efc5783612eff565b60005b81526020018a612f10576000612f27565b600a612f1d85600961380c565b612f279190613b32565b81526020018a612f4d57600a612f3e85600961380c565b612f489190613b32565b612f50565b60005b815230602082015242604091820152517f8831645600000000000000000000000000000000000000000000000000000000815290915060009081907f000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f96001600160a01b031690638831645690612fca908690600401613a1b565b6080604051808303816000875af1158015612fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061300d9190613adf565b50506040805160a08101825283815230602082018190526fffffffffffffffffffffffffffffffff9093169181018290526001600160a01b039d8e16606082018190529c909d166080909d018d9052600792909255600880547fffffffffffffffffffffffff00000000000000000000000000000000000000009081169092179055600980547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016909217909155600a80548216909a179099555050600b805490971690971790955550505050505050565b606060006130ec83613249565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000306001600160a01b037f0000000000000000000000000cd7e55f61d393866db74afd6fdf49d81b82b9be1614801561317757507f0000000000000000000000000000000000000000000000000000000000013e3146145b156131a157507f8ca41e6f22e3dd451ef2b86fb8a6092ab54c8e2371d331e53e9d2a379d050dfe90565b610b49604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0e0a761a71a154dcb4f8e6f2cf4085882f5f377cc69e752c9c2de35cff4faf4a918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b600060ff8216601f811115610b60576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561329c57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146132cc57600080fd5b9392505050565b60005b838110156132ee5781810151838201526020016132d6565b50506000910152565b6000815180845261330f8160208601602086016132d3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006132cc60208301846132f7565b60006020828403121561336657600080fd5b5035919050565b6001600160a01b038116811461102957600080fd5b6000806040838503121561339557600080fd5b82356133a08161336d565b946020939093013593505050565b6000806000606084860312156133c357600080fd5b83356133ce8161336d565b925060208401356133de8161336d565b929592945050506040919091013590565b60008060006060848603121561340457600080fd5b833561340f8161336d565b95602085013595506040909401359392505050565b60008151808452602080850194506020840160005b8381101561345557815187529582019590820190600101613439565b509495945050505050565b6020815260006132cc6020830184613424565b60006020828403121561348557600080fd5b81356132cc8161336d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561350657613506613490565b604052919050565b801515811461102957600080fd5b80356135278161350e565b919050565b6000806040838503121561353f57600080fd5b823567ffffffffffffffff8082111561355757600080fd5b818501915085601f83011261356b57600080fd5b813560208282111561357f5761357f613490565b8160051b92506135908184016134bf565b82815292840181019281810190898511156135aa57600080fd5b948201945b848610156135c8578535825294820194908201906135af565b96506135d7905087820161351c565b9450505050509250929050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e06020820152600061361f60e08301896132f7565b828103604084015261363181896132f7565b90508660608401526001600160a01b03861660808401528460a084015282810360c08401526136608185613424565b9a9950505050505050505050565b6000806040838503121561368157600080fd5b823561368c8161336d565b9150602083013561369c8161350e565b809150509250929050565b6000806000806000608086880312156136bf57600080fd5b85356136ca8161336d565b945060208601356136da8161336d565b935060408601359250606086013567ffffffffffffffff808211156136fe57600080fd5b818801915088601f83011261371257600080fd5b81358181111561372157600080fd5b89602082850101111561373357600080fd5b9699959850939650602001949392505050565b60006060828403121561375857600080fd5b50919050565b600080600060e0848603121561377357600080fd5b833592506137848560208601613746565b91506137938560808601613746565b90509250925092565b600080604083850312156137af57600080fd5b82356137ba8161336d565b9150602083013561369c8161336d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610b6057610b606137ca565b8082028115828204841417610b6057610b606137ca565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613854576138546137ca565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81810381811115610b6057610b606137ca565b8281526040602082015260006111a06040830184613424565b600082516138c88184602087016132d3565b9190910192915050565b6000602082840312156138e457600080fd5b5051919050565b6000602082840312156138fd57600080fd5b81516132cc8161350e565b6000806040838503121561391b57600080fd5b505080516020909101519092909150565b60006060828403121561393e57600080fd5b6040516060810181811067ffffffffffffffff8211171561396157613961613490565b604052823561396f8161336d565b8152602083810135908201526040928301359281019290925250919050565b6000602082840312156139a057600080fd5b813560ff811681146132cc57600080fd5b6000602082840312156139c357600080fd5b81516132cc8161336d565b600181811c908216806139e257607f821691505b602082108103613758577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b81516001600160a01b0316815261016081016020830151613a4760208401826001600160a01b03169052565b506040830151613a5e604084018262ffffff169052565b506060830151613a73606084018260020b9052565b506080830151613a88608084018260020b9052565b5060a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151613ace828501826001600160a01b03169052565b505061014092830151919092015290565b60008060008060808587031215613af557600080fd5b8451935060208501516fffffffffffffffffffffffffffffffff81168114613b1c57600080fd5b6040860151606090960151949790965092505050565b600082613b68577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea2646970667358221220085c6082360a24dae748cbd5d043c4bc6625cc86adfacf9fbe009518641e360264736f6c63430008180033

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

000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f90000000000000000000000004300000000000000000000000000000000000004

-----Decoded View---------------
Arg [0] : nonfungiblePositionManager (address): 0x434575EaEa081b735C985FA9bf63CD7b87e227F9
Arg [1] : weth (address): 0x4300000000000000000000000000000000000004

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000434575eaea081b735c985fa9bf63cd7b87e227f9
Arg [1] : 0000000000000000000000004300000000000000000000000000000000000004


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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