creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/example/Underworld.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {DN404} from \"../DN404.sol\";\nimport {Ownable} from \"solady/auth/Ownable.sol\";\nimport {UUPSUpgradeable} from \"solady/utils/UUPSUpgradeable.sol\";\nimport {LibString} from \"solady/utils/LibString.sol\";\nimport {SafeTransferLib} from \"solady/utils/SafeTransferLib.sol\";\n\n/**\n * @title SimpleDN404\n * @notice Sample DN404 contract that demonstrates the owner selling fungile tokens.\n * When a user has at least one base unit (10^18) amount of tokens, they will automatically receive an NFT.\n * NFTs are minted as an address accumulates each base unit amount of tokens.\n */\ncontract Underworld is DN404, Ownable, UUPSUpgradeable {\n    string private _name;\n    string private _symbol;\n    string private _baseURI;\n\n    constructor() payable {\n        _initializeOwner(address(1));\n    }\n\n    function _authorizeUpgrade(address) internal override onlyOwner {}\n\n    function _guardInitializeOwner() internal pure virtual override(Ownable) returns (bool) {\n        return true;\n    }\n\n    function initialize(\n        string memory name_,\n        string memory symbol_,\n        uint256 initialTokenSupply,\n        address initialSupplyOwner,\n        address mirror\n    ) public payable {\n        _initializeOwner(msg.sender);\n\n        _name = name_;\n        _symbol = symbol_;\n\n        _initializeDN404(initialTokenSupply, initialSupplyOwner, mirror);\n    }\n\n    function name() public view override returns (string memory) {\n        return _name;\n    }\n\n    function symbol() public view override returns (string memory) {\n        return _symbol;\n    }\n\n    function tokenURI(uint256 tokenId) public view override returns (string memory result) {\n        if (bytes(_baseURI).length != 0) {\n            result = string(abi.encodePacked(_baseURI, LibString.toString(tokenId)));\n        }\n    }\n\n    function setNameAndSymbol(string calldata name_, string calldata symbol_) public onlyOwner {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    function setBaseURI(string calldata baseURI_) public onlyOwner {\n        _baseURI = baseURI_;\n    }\n\n    function setSkipNFTFor(address account, bool state) public onlyOwner {\n        _setSkipNFT(account, state);\n    }\n\n    function setExchangeNFTFeeRate(uint256 feeBips) public onlyOwner {\n        _setExchangeNFTFeeRate(feeBips);\n    }\n\n    function withdraw() public onlyOwner {\n        SafeTransferLib.safeTransferAllETH(msg.sender);\n    }\n}\n"
      },
      "src/DN404.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {LibBitmap} from \"solady/utils/LibBitmap.sol\";\n\n/// @title DN404\n/// @notice DN404 is a hybrid ERC20 and ERC721 implementation that mints\n/// and burns NFTs based on an account's ERC20 token balance.\n///\n/// @author vectorized.eth (@optimizoor)\n/// @author Quit (@0xQuit)\n/// @author Michael Amadi (@AmadiMichaels)\n/// @author cygaar (@0xCygaar)\n/// @author Thomas (@0xjustadev)\n/// @author Harrison (@PopPunkOnChain)\n///\n/// @dev Note:\n/// - The ERC721 data is stored in this base DN404 contract, however a\n///   DN404Mirror contract ***MUST*** be deployed and linked during\n///   initialization.\nabstract contract DN404 {\n    using LibBitmap for LibBitmap.Bitmap;\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                           EVENTS                           */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Emitted when `amount` tokens is transferred from `from` to `to`.\n    event Transfer(address indexed from, address indexed to, uint256 amount);\n\n    /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n    /// @dev Emitted when `target` sets their skipNFT flag to `status`.\n    event SkipNFTSet(address indexed target, bool status);\n\n    /// @dev `keccak256(bytes(\"Transfer(address,address,uint256)\"))`.\n    uint256 private constant _TRANSFER_EVENT_SIGNATURE =\n        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;\n\n    /// @dev `keccak256(bytes(\"Approval(address,address,uint256)\"))`.\n    uint256 private constant _APPROVAL_EVENT_SIGNATURE =\n        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;\n\n    /// @dev `keccak256(bytes(\"SkipNFTSet(address,bool)\"))`.\n    uint256 private constant _SKIP_NFT_SET_EVENT_SIGNATURE =\n        0xb5a1de456fff688115a4f75380060c23c8532d14ff85f687cc871456d6420393;\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                        CUSTOM ERRORS                       */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Thrown when attempting to double-initialize the contract.\n    error DNAlreadyInitialized();\n\n    /// @dev Thrown when attempting to transfer or burn more tokens than sender's balance.\n    error InsufficientBalance();\n\n    /// @dev Thrown when a spender attempts to transfer tokens with an insufficient allowance.\n    error InsufficientAllowance();\n\n    /// @dev Thrown when minting an amount of tokens that would overflow the max tokens.\n    error TotalSupplyOverflow();\n\n    /// @dev The unit cannot be zero.\n    error InvalidUnit();\n\n    /// @dev Thrown when the caller for a fallback NFT function is not the mirror contract.\n    error SenderNotMirror();\n\n    /// @dev Thrown when attempting to transfer tokens to the zero address.\n    error TransferToZeroAddress();\n\n    /// @dev Thrown when the mirror address provided for initialization is the zero address.\n    error MirrorAddressIsZero();\n\n    /// @dev Thrown when the link call to the mirror contract reverts.\n    error LinkMirrorContractFailed();\n\n    /// @dev Thrown when setting an NFT token approval\n    /// and the caller is not the owner or an approved operator.\n    error ApprovalCallerNotOwnerNorApproved();\n\n    /// @dev Thrown when transferring an NFT\n    /// and the caller is not the owner or an approved operator.\n    error TransferCallerNotOwnerNorApproved();\n\n    /// @dev Thrown when transferring an NFT and the from address is not the current owner.\n    error TransferFromIncorrectOwner();\n\n    /// @dev Thrown when checking the owner or approved address for a non-existent NFT.\n    error TokenDoesNotExist();\n\n    /// @dev Thrown when exchanging the NFTs that locked.\n    error ExchangeTokenLocked();\n\n    /// @dev Thrown when exchanging the same NFTs\n    error ExchangeSameToken();\n\n    /// @dev Thrown when attempting to lock the NFTs that locked,\n    ///      or to unlock the NFTs that unlocked.\n    error TokenLockStatusNoChange();\n\n    /// @dev Thrown when transferring tokens but the balance is insufficient to to maintain locked NFTs.\n    error InsufficientBalanceToMaintainLockedTokens();\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                         CONSTANTS                          */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev The flag to denote that the address data is initialized.\n    uint8 internal constant _ADDRESS_DATA_INITIALIZED_FLAG = 1 << 0;\n\n    /// @dev The flag to denote that the address should skip NFTs.\n    uint8 internal constant _ADDRESS_DATA_SKIP_NFT_FLAG = 1 << 1;\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                          STORAGE                           */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Struct containing an address's token data and settings.\n    struct AddressData {\n        // Auxiliary data.\n        uint56 aux;\n        // Flags for `initialized` and `skipNFT`.\n        uint8 flags;\n        // The alias for the address. Zero means absence of an alias.\n        uint32 addressAlias;\n        // The number of NFT tokens locked.\n        uint32 lockedLength;\n        // The number of NFT tokens owned.\n        uint32 ownedLength;\n        // The token balance in wei.\n        uint96 balance;\n        // snapshot of `accFeePerNFT` when the account fee accrued\n        uint96 feePerNFTSnap;\n    }\n\n    /// @dev A uint32 map in storage.\n    struct Uint32Map {\n        mapping(uint256 => uint256) map;\n    }\n\n    /// @dev A struct to wrap a uint256 in storage.\n    struct Uint256Ref {\n        uint256 value;\n    }\n\n    /// @dev Struct containing the base token contract storage.\n    struct DN404Storage {\n        // Current number of address aliases assigned.\n        uint32 numAliases;\n        // Next NFT ID to assign for a mint.\n        uint32 nextTokenId;\n        // Total number of NFT IDs in the burned pool.\n        uint32 burnedPoolSize;\n        // Total supply of minted NFTs.\n        uint32 totalNFTSupply;\n        // Total supply of tokens.\n        uint96 totalSupply;\n        // Address of the NFT mirror contract.\n        address mirrorERC721;\n        // Mapping of a user alias number to their address.\n        mapping(uint32 => address) aliasToAddress;\n        // Mapping of user operator approvals for NFTs.\n        mapping(address => mapping(address => Uint256Ref)) operatorApprovals;\n        // Mapping of NFT approvals to approved operators.\n        mapping(uint256 => address) nftApprovals;\n        // Bitmap of whether an non-zero NFT approval may exist.\n        LibBitmap.Bitmap mayHaveNFTApproval;\n        // Mapping of user allowances for ERC20 spenders.\n        mapping(address => mapping(address => Uint256Ref)) allowance;\n        // Mapping of NFT IDs owned by an address.\n        mapping(address => Uint32Map) owned;\n        // Mapping of NFT token IDs locked by an address.\n        mapping(address => Uint32Map) locked;\n        // The pool of burned NFT IDs.\n        Uint32Map burnedPool;\n        // Even indices: owner aliases. Odd indices: owned indices.\n        // if NFT token was locked, owned indices are ref to `locked`, otherwise `owned`\n        Uint32Map oo;\n        // Mapping of user account AddressData.\n        mapping(address => AddressData) addressData;\n        // Mapping of NFT token to locked flag\n        LibBitmap.Bitmap tokenLocks;\n        // The number of NFT tokens locked globally.\n        uint32 numLockedNFT;\n        // The number of NFT tokens approved to `this` globally.\n        uint32 numExchangableNFT;\n        // Fee rate to charged per NFT when exchange unlocking NFTs\n        uint16 exchangeNFTFeeBips;\n        // accumulated fee per unlocked NFT should receive\n        uint96 accFeePerNFT;\n    }\n\n    /// @dev Returns a storage pointer for DN404Storage.\n    function _getDN404Storage() internal pure virtual returns (DN404Storage storage $) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // `uint72(bytes9(keccak256(\"DN404_STORAGE\")))`.\n            $.slot := 0xa20d6e21d0e5255308 // Truncate to 9 bytes to reduce bytecode size.\n        }\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                         INITIALIZER                        */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Initializes the DN404 contract with an\n    /// `initialTokenSupply`, `initialTokenOwner` and `mirror` NFT contract address.\n    function _initializeDN404(\n        uint256 initialTokenSupply,\n        address initialSupplyOwner,\n        address mirror\n    ) internal virtual {\n        DN404Storage storage $ = _getDN404Storage();\n\n        if ($.mirrorERC721 != address(0)) revert DNAlreadyInitialized();\n\n        if (mirror == address(0)) revert MirrorAddressIsZero();\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Make the call to link the mirror contract.\n            mstore(0x00, 0x0f4599e5) // `linkMirrorContract(address)`.\n            mstore(0x20, caller())\n            if iszero(and(eq(mload(0x00), 1), call(gas(), mirror, 0, 0x1c, 0x24, 0x00, 0x20))) {\n                mstore(0x00, 0xd125259c) // `LinkMirrorContractFailed()`.\n                revert(0x1c, 0x04)\n            }\n        }\n\n        $.mirrorERC721 = mirror;\n\n        if (_unit() < 10 ** decimals() || _unit() > 10 ** 24) revert InvalidUnit();\n\n        if (initialTokenSupply != 0) {\n            if (initialSupplyOwner == address(0)) {\n                revert TransferToZeroAddress();\n            }\n            if (_totalSupplyOverflows(initialTokenSupply)) {\n                revert TotalSupplyOverflow();\n            }\n\n            $.totalSupply = uint96(initialTokenSupply);\n            AddressData storage initialOwnerAddressData = _addressData(initialSupplyOwner);\n            initialOwnerAddressData.balance = uint96(initialTokenSupply);\n\n            /// @solidity memory-safe-assembly\n            assembly {\n                // Emit the {Transfer} event.\n                mstore(0x00, initialTokenSupply)\n                log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, shl(96, initialSupplyOwner)))\n            }\n\n            _setSkipNFT(initialSupplyOwner, true);\n        }\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*               BASE UNIT FUNCTION TO OVERRIDE               */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Amount of token balance that is equal to one NFT.\n    function _unit() internal view virtual returns (uint256) {\n        return 10 ** 18;\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*               METADATA FUNCTIONS TO OVERRIDE               */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns the name of the token.\n    function name() public view virtual returns (string memory);\n\n    /// @dev Returns the symbol of the token.\n    function symbol() public view virtual returns (string memory);\n\n    /// @dev Returns the Uniform Resource Identifier (URI) for token `id`.\n    function tokenURI(uint256 id) public view virtual returns (string memory);\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                      ERC20 OPERATIONS                      */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns the decimals places of the token. Always 18.\n    function decimals() public pure returns (uint8) {\n        return 18;\n    }\n\n    /// @dev Returns the amount of tokens in existence.\n    function totalSupply() public view virtual returns (uint256) {\n        return uint256(_getDN404Storage().totalSupply);\n    }\n\n    /// @dev Returns the amount of tokens owned by `owner`.\n    function balanceOf(address owner) public view virtual returns (uint256) {\n        return _getDN404Storage().addressData[owner].balance;\n    }\n\n    /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.\n    function allowance(address owner, address spender) public view returns (uint256) {\n        return _getDN404Storage().allowance[owner][spender].value;\n    }\n\n    /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n    ///\n    /// Emits a {Approval} event.\n    function approve(address spender, uint256 amount) public virtual returns (bool) {\n        _approve(msg.sender, spender, amount);\n        return true;\n    }\n\n    /// @dev Transfer `amount` tokens from the caller to `to`.\n    ///\n    /// Will burn sender NFTs if balance after transfer is less than\n    /// the amount required to support the current NFT balance.\n    ///\n    /// Will mint NFTs to `to` if the recipient's new balance supports\n    /// additional NFTs ***AND*** the `to` address's skipNFT flag is\n    /// set to false.\n    ///\n    /// Requirements:\n    /// - `from` must at least have `amount`.\n    ///\n    /// Emits a {Transfer} event.\n    function transfer(address to, uint256 amount) public virtual returns (bool) {\n        DN404Storage storage $ = _getDN404Storage();\n        _pullFeeForTwo($, msg.sender, to);\n        _transfer(msg.sender, to, amount);\n        return true;\n    }\n\n    /// @dev Transfers `amount` tokens from `from` to `to`.\n    ///\n    /// Note: Does not update the allowance if it is the maximum uint256 value.\n    ///\n    /// Will burn sender NFTs if balance after transfer is less than\n    /// the amount required to support the current NFT balance.\n    ///\n    /// Will mint NFTs to `to` if the recipient's new balance supports\n    /// additional NFTs ***AND*** the `to` address's skipNFT flag is\n    /// set to false.\n    ///\n    /// Requirements:\n    /// - `from` must at least have `amount`.\n    /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.\n    ///\n    /// Emits a {Transfer} event.\n    function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {\n        DN404Storage storage $ = _getDN404Storage();\n        Uint256Ref storage a = $.allowance[from][msg.sender];\n\n        uint256 allowed = a.value;\n        if (allowed != type(uint256).max) {\n            if (amount > allowed) revert InsufficientAllowance();\n            unchecked {\n                a.value = allowed - amount;\n            }\n        }\n        _pullFeeForTwo($, from, to);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                INTERNAL TRANSFER FUNCTIONS                 */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Moves `amount` of tokens from `from` to `to`.\n    ///\n    /// Will burn sender NFTs if balance after transfer is less than\n    /// the amount required to support the current NFT balance.\n    ///\n    /// Will mint NFTs to `to` if the recipient's new balance supports\n    /// additional NFTs ***AND*** the `to` address's skipNFT flag is\n    /// set to false.\n    ///\n    /// Emits a {Transfer} event.\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        if (to == address(0)) revert TransferToZeroAddress();\n\n        DN404Storage storage $ = _getDN404Storage();\n\n        AddressData storage fromAddressData = _addressData(from);\n        AddressData storage toAddressData = _addressData(to);\n\n        _TransferTemps memory t;\n        t.fromOwnedLength = fromAddressData.ownedLength;\n        t.toOwnedLength = toAddressData.ownedLength;\n        t.totalSupply = $.totalSupply;\n\n        if (amount > (t.fromBalance = fromAddressData.balance)) {\n            revert InsufficientBalance();\n        }\n\n        unchecked {\n            t.fromBalance -= amount;\n\n            t.fromLockedLength = fromAddressData.lockedLength;\n            // need enough token to maintain locked NFTs\n            if (t.fromBalance < t.fromLockedLength * _unit()) {\n                revert InsufficientBalanceToMaintainLockedTokens();\n            }\n\n            fromAddressData.balance = uint96(t.fromBalance);\n            toAddressData.balance = uint96(t.toBalance = toAddressData.balance + amount);\n\n            t.numNFTBurns =\n                _zeroFloorSub(t.fromOwnedLength + t.fromLockedLength, t.fromBalance / _unit());\n\n            if (toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG == 0) {\n                if (from == to) t.toOwnedLength = t.fromOwnedLength - t.numNFTBurns;\n                t.numNFTMints = _zeroFloorSub(\n                    t.toBalance / _unit(),\n                    t.toOwnedLength + toAddressData.lockedLength // balance needed for locked and owned\n                );\n            }\n\n            {\n                // cache `address(this)` approvals\n                mapping(address => Uint256Ref) storage thisOperatorApprovals =\n                    $.operatorApprovals[address(this)];\n                // `from` burns NFTs\n                if (thisOperatorApprovals[from].value != 0) {\n                    $.numExchangableNFT -= uint32(t.numNFTBurns);\n                }\n                // `to`mints NFTs\n                if (thisOperatorApprovals[to].value != 0) {\n                    $.numExchangableNFT += uint32(t.numNFTMints);\n                }\n            }\n\n            $.totalNFTSupply = uint32(uint256($.totalNFTSupply) + t.numNFTMints - t.numNFTBurns);\n            Uint32Map storage oo = $.oo;\n            {\n                uint256 n = _min(t.numNFTBurns, t.numNFTMints);\n                if (n != 0) {\n                    t.numNFTBurns -= n;\n                    t.numNFTMints -= n;\n\n                    if (from == to) {\n                        t.toOwnedLength += n;\n                    } else {\n                        _DNDirectLogs memory directLogs = _directLogsMalloc(n, from, to);\n                        Uint32Map storage fromOwned = $.owned[from];\n                        Uint32Map storage toOwned = $.owned[to];\n                        uint32 toAlias = _registerAndResolveAlias(toAddressData, to);\n                        // Direct transfer loop.\n                        do {\n                            uint256 id = _get(fromOwned, --t.fromOwnedLength);\n                            _set(toOwned, t.toOwnedLength, uint32(id));\n                            _setOwnerAliasAndOwnedIndex(oo, id, toAlias, uint32(t.toOwnedLength++));\n                            _removeNFTApproval($, id);\n                            _directLogsAppend(directLogs, id);\n                        } while (--n != 0);\n\n                        _directLogsSend(directLogs, $.mirrorERC721);\n                        fromAddressData.ownedLength = uint32(t.fromOwnedLength);\n                        toAddressData.ownedLength = uint32(t.toOwnedLength);\n                    }\n                }\n            }\n\n            _PackedLogs memory packedLogs = _packedLogsMalloc(t.numNFTBurns + t.numNFTMints);\n            uint256 burnedPoolSize = $.burnedPoolSize;\n            if (t.numNFTBurns != 0) {\n                _packedLogsSet(packedLogs, from, 1);\n                Uint32Map storage fromOwned = $.owned[from];\n                uint256 fromIndex = t.fromOwnedLength;\n                uint256 fromEnd = fromIndex - t.numNFTBurns;\n                fromAddressData.ownedLength = uint32(fromEnd);\n                // Burn loop.\n                do {\n                    uint256 id = _get(fromOwned, --fromIndex);\n                    _setOwnerAliasAndOwnedIndex(oo, id, 0, 0);\n                    _set($.burnedPool, burnedPoolSize++, uint32(id));\n                    _removeNFTApproval($, id);\n                    _packedLogsAppend(packedLogs, id);\n                } while (fromIndex != fromEnd);\n            }\n\n            if (t.numNFTMints != 0) {\n                _packedLogsSet(packedLogs, to, 0);\n                uint256 nextTokenId = $.nextTokenId;\n                Uint32Map storage toOwned = $.owned[to];\n                uint256 toIndex = t.toOwnedLength;\n                uint256 toEnd = toIndex + t.numNFTMints;\n                uint32 toAlias = _registerAndResolveAlias(toAddressData, to);\n                toAddressData.ownedLength = uint32(toEnd);\n                // Mint loop.\n                do {\n                    uint256 id;\n                    if (burnedPoolSize != 0) {\n                        id = _get($.burnedPool, --burnedPoolSize);\n                    } else {\n                        id = nextTokenId;\n                        nextTokenId = id + 1;\n                    }\n                    _set(toOwned, toIndex, uint32(id));\n                    _setOwnerAliasAndOwnedIndex(oo, id, toAlias, uint32(toIndex++));\n                    _packedLogsAppend(packedLogs, id);\n                } while (toIndex != toEnd);\n\n                $.nextTokenId = uint32(nextTokenId);\n            }\n\n            if (packedLogs.logs.length != 0) {\n                $.burnedPoolSize = uint32(burnedPoolSize);\n                _packedLogsSend(packedLogs, $.mirrorERC721);\n            }\n            /// @solidity memory-safe-assembly\n            assembly {\n                // Emit the {Transfer} event.\n                mstore(0x00, amount)\n                // forgefmt: disable-next-item\n                log3(\n                    0x00,\n                    0x20,\n                    _TRANSFER_EVENT_SIGNATURE,\n                    shr(96, shl(96, from)),\n                    shr(96, shl(96, to))\n                )\n            }\n        }\n    }\n\n    /// @dev Transfers token `id` from `from` to `to`.\n    ///\n    /// Requirements:\n    ///\n    /// - Call must originate from the mirror contract.\n    /// - Token `id` must exist.\n    /// - `from` must be the owner of the token.\n    /// - `to` cannot be the zero address.\n    ///   `msgSender` must be the owner of the token, or be approved to manage the token.\n    ///\n    /// Emits a {Transfer} event.\n    function _transferFromNFT(address from, address to, uint256 id, address msgSender)\n        internal\n        virtual\n    {\n        if (to == address(0)) revert TransferToZeroAddress();\n\n        DN404Storage storage $ = _getDN404Storage();\n        Uint32Map storage oo = $.oo;\n\n        if (from != $.aliasToAddress[_get(oo, _ownershipIndex(id))]) {\n            revert TransferFromIncorrectOwner();\n        }\n\n        if (msgSender != from) {\n            if ($.operatorApprovals[msgSender][from].value == 0) {\n                if (msgSender != $.nftApprovals[id]) {\n                    revert TransferCallerNotOwnerNorApproved();\n                }\n            }\n        }\n\n        AddressData storage fromAddressData = _addressData(from);\n        AddressData storage toAddressData = _addressData(to);\n\n        uint256 unit = _unit();\n\n        fromAddressData.balance -= uint96(unit);\n\n        unchecked {\n            toAddressData.balance += uint96(unit);\n\n            _removeNFTApproval($, id);\n\n            uint32 toTransferIdx = _get(oo, _ownedIndex(id));\n            if (LibBitmap.get($.tokenLocks, id)) {\n                // operate `locked` map\n                // delete transferred NFT\n                _delNFTAt($.locked[from], oo, toTransferIdx, --fromAddressData.lockedLength);\n            } else {\n                if ($.operatorApprovals[address(this)][from].value != 0) {\n                    // The unlocked NFTs amount of account `from` will decrease, collecting fees first\n                    _pullFeeForTwo($, from, from);\n                    // `from` lock 1 NFT\n                    --$.numExchangableNFT;\n                }\n\n                // operate `owned` map\n                // delete transferred NFT\n                _delNFTAt($.owned[from], oo, toTransferIdx, --fromAddressData.ownedLength);\n\n                // lock\n                LibBitmap.setTo($.tokenLocks, id, true);\n                ++$.numLockedNFT;\n            }\n\n            // transfer ownership\n            // lock the NFT by default for ERC721 transfer\n            uint256 n = toAddressData.lockedLength++;\n            _set($.locked[to], n, uint32(id));\n            _setOwnerAliasAndOwnedIndex(\n                oo, id, _registerAndResolveAlias(toAddressData, to), uint32(n)\n            );\n        }\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Emit the {Transfer} event.\n            mstore(0x00, unit)\n            // forgefmt: disable-next-item\n            log3(\n                0x00,\n                0x20,\n                _TRANSFER_EVENT_SIGNATURE,\n                shr(96, shl(96, from)),\n                shr(96, shl(96, to))\n            )\n        }\n    }\n\n    function _exchangeNFT(uint256 idX, uint256 idY, address msgSender)\n        internal\n        virtual\n        returns (address x, address y, uint256 exchangeFee)\n    {\n        if (idX == idY) revert ExchangeSameToken();\n\n        DN404Storage storage $ = _getDN404Storage();\n\n        LibBitmap.Bitmap storage tokenLocks = $.tokenLocks;\n        if (_toUint(LibBitmap.get(tokenLocks, idX)) | _toUint(LibBitmap.get(tokenLocks, idY)) != 0)\n        {\n            revert ExchangeTokenLocked();\n        }\n\n        x = _ownerOf(idX);\n        y = _ownerOf(idY);\n        // Only owner or spender can operate the token `idX`\n        if (msgSender != x) {\n            if ($.operatorApprovals[msgSender][x].value == 0) {\n                if (msgSender != $.nftApprovals[idX]) {\n                    revert TransferCallerNotOwnerNorApproved();\n                }\n            }\n        }\n\n        mapping(address => Uint256Ref) storage thisOperatorApprovals =\n            $.operatorApprovals[address(this)];\n        if (thisOperatorApprovals[y].value == 0) {\n            revert ApprovalCallerNotOwnerNorApproved();\n        }\n\n        _removeNFTApproval($, idX);\n        _removeNFTApproval($, idY);\n\n        // collecting fees for account `x` and `y` first\n        _pullFeeForTwo($, x, y);\n\n        Uint32Map storage oo = $.oo;\n\n        // idY to account x, then lock\n        // must transfer `idY` firstly, otherwise the ownedIndex of `idX` is wrong\n        AddressData storage xAddressData = _addressData(x);\n        {\n            uint256 xIndex = _get(oo, _ownedIndex(idX));\n            // remove NFT `idX` from account `x`\n            _delNFTAt($.owned[x], oo, xIndex, --xAddressData.ownedLength);\n        }\n\n        // snapshot owned index of `idY`\n        uint256 yIndex = _get(oo, _ownedIndex(idY));\n\n        {\n            // append `idY` to `locked`\n            uint256 n = xAddressData.lockedLength++;\n            _set($.locked[x], n, uint32(idY));\n            _setOwnerAliasAndOwnedIndex(oo, idY, xAddressData.addressAlias, uint32(n));\n\n            // lock `idY`\n            LibBitmap.setTo(tokenLocks, idY, true);\n            ++$.numLockedNFT;\n        }\n\n        // idX to account y\n        AddressData storage yAddressData = _addressData(y);\n        _setOwnerAliasAndOwnedIndex(oo, idX, yAddressData.addressAlias, uint32(yIndex));\n        _set($.owned[y], yIndex, uint32(idX));\n\n        // transfer nft first, then token, otherwise specified NFT transfer may not success\n        // fee charges in percentage of the unit\n        exchangeFee = $.exchangeNFTFeeBips;\n        if (exchangeFee > 0) {\n            // Only refresh when the balance of `msgSender` will be changed.\n            if (msgSender != x) _pullFeeForTwo($, msgSender, msgSender);\n            unchecked {\n                exchangeFee *= _unit() / 10000;\n                _transfer(msgSender, address(this), exchangeFee);\n                $.accFeePerNFT += uint96(exchangeFee / $.numExchangableNFT);\n            }\n        }\n\n        // If `msgSender` exchanged on behalf of `x`, `msgSender` receive the NFT.\n        if (msgSender != x) _transferFromNFT(x, msgSender, idY, x);\n        // x lock 1 NFT\n        if (thisOperatorApprovals[x].value != 0) {\n            --$.numExchangableNFT;\n        }\n    }\n\n    function _pullFeeForTwo(DN404Storage storage $, address account1, address account2)\n        internal\n        virtual\n    {\n        // Cannot receive fee if `address(this)` has no operator approvals\n        mapping(address => Uint256Ref) storage thisOperatorApprovals =\n            $.operatorApprovals[address(this)];\n        uint256 accFeePerNFT;\n        uint256 accruedFee1;\n        if (thisOperatorApprovals[account1].value > 0) {\n            accFeePerNFT = $.accFeePerNFT;\n            AddressData storage addressData = $.addressData[account1];\n            // only unlocked NFTs receive fee\n            accruedFee1 = (accFeePerNFT - addressData.feePerNFTSnap) * (addressData.ownedLength);\n            addressData.feePerNFTSnap = uint96(accFeePerNFT);\n        }\n        if (account2 != account1) {\n            if (thisOperatorApprovals[account2].value > 0) {\n                if (accFeePerNFT == 0) {\n                    accFeePerNFT = $.accFeePerNFT;\n                }\n                AddressData storage addressData = $.addressData[account2];\n                // only unlocked NFTs receive fee\n                uint256 accrued =\n                    (accFeePerNFT - addressData.feePerNFTSnap) * (addressData.ownedLength);\n                addressData.feePerNFTSnap = uint96(accFeePerNFT);\n                if (accrued > 0) {\n                    _transfer(address(this), account2, accrued);\n                }\n            }\n        }\n        if (accruedFee1 > 0) {\n            _transfer(address(this), account1, accruedFee1);\n        }\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                 INTERNAL APPROVE FUNCTIONS                 */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`.\n    ///\n    /// Emits a {Approval} event.\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        Uint256Ref storage ref = _getDN404Storage().allowance[owner][spender];\n        if (amount > 0 && ref.value > 0) revert();\n\n        ref.value = amount;\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Emit the {Approval} event.\n            mstore(0x00, amount)\n            // forgefmt: disable-next-item\n            log3(\n                0x00,\n                0x20,\n                _APPROVAL_EVENT_SIGNATURE,\n                shr(96, shl(96, owner)),\n                shr(96, shl(96, spender))\n            )\n        }\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                 DATA HITCHHIKING FUNCTIONS                 */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns the auxiliary data for `owner`.\n    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.\n    /// Auxiliary data can be set for any address, even if it does not have any tokens.\n    function _getAux(address owner) internal view virtual returns (uint56) {\n        return _getDN404Storage().addressData[owner].aux;\n    }\n\n    /// @dev Set the auxiliary data for `owner` to `value`.\n    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.\n    /// Auxiliary data can be set for any address, even if it does not have any tokens.\n    function _setAux(address owner, uint56 value) internal virtual {\n        _getDN404Storage().addressData[owner].aux = value;\n    }\n\n    function _setExchangeNFTFeeRate(uint256 feeBips) internal virtual {\n        if (feeBips > 10000) revert();\n        _getDN404Storage().exchangeNFTFeeBips = uint16(feeBips);\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                     SKIP NFT FUNCTIONS                     */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns true if minting and transferring ERC20s to `owner` will skip minting NFTs.\n    /// Returns false otherwise.\n    function getSkipNFT(address owner) public view virtual returns (bool) {\n        AddressData storage d = _getDN404Storage().addressData[owner];\n        if (d.flags & _ADDRESS_DATA_INITIALIZED_FLAG == 0) {\n            return _hasCode(owner);\n        }\n        return d.flags & _ADDRESS_DATA_SKIP_NFT_FLAG != 0;\n    }\n\n    /// @dev Sets the caller's skipNFT flag to `skipNFT`. Returns true.\n    ///\n    /// Emits a {SkipNFTSet} event.\n    function setSkipNFT(bool skipNFT) public virtual returns (bool) {\n        _setSkipNFT(msg.sender, skipNFT);\n        return true;\n    }\n\n    /// @dev Internal function to set account `owner` skipNFT flag to `state`\n    ///\n    /// Initializes account `owner` AddressData if it is not currently initialized.\n    ///\n    /// Emits a {SkipNFTSet} event.\n    function _setSkipNFT(address owner, bool state) internal virtual {\n        AddressData storage d = _addressData(owner);\n        if ((d.flags & _ADDRESS_DATA_SKIP_NFT_FLAG != 0) != state) {\n            d.flags ^= _ADDRESS_DATA_SKIP_NFT_FLAG;\n        }\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, iszero(iszero(state)))\n            log2(0x00, 0x20, _SKIP_NFT_SET_EVENT_SIGNATURE, shr(96, shl(96, owner)))\n        }\n    }\n\n    /// @dev Returns a storage data pointer for account `owner` AddressData\n    ///\n    /// Initializes account `owner` AddressData if it is not currently initialized.\n    function _addressData(address owner) internal virtual returns (AddressData storage d) {\n        d = _getDN404Storage().addressData[owner];\n        unchecked {\n            if (d.flags & _ADDRESS_DATA_INITIALIZED_FLAG == 0) {\n                uint256 skipNFT = (_toUint(_hasCode(owner)) * _ADDRESS_DATA_SKIP_NFT_FLAG);\n                d.flags = uint8(skipNFT | _ADDRESS_DATA_INITIALIZED_FLAG);\n            }\n        }\n    }\n\n    /// @dev Returns the `addressAlias` of account `to`.\n    ///\n    /// Assigns and registers the next alias if `to` alias was not previously registered.\n    function _registerAndResolveAlias(AddressData storage toAddressData, address to)\n        internal\n        virtual\n        returns (uint32 addressAlias)\n    {\n        DN404Storage storage $ = _getDN404Storage();\n        addressAlias = toAddressData.addressAlias;\n        if (addressAlias == 0) {\n            unchecked {\n                addressAlias = ++$.numAliases;\n            }\n            toAddressData.addressAlias = addressAlias;\n            $.aliasToAddress[addressAlias] = to;\n            if (addressAlias == 0) revert(); // Overflow.\n        }\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                     MIRROR OPERATIONS                      */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns the address of the mirror NFT contract.\n    function mirrorERC721() public view virtual returns (address) {\n        return _getDN404Storage().mirrorERC721;\n    }\n\n    /// @dev Returns the total NFT supply.\n    function _totalNFTSupply() internal view virtual returns (uint256) {\n        return _getDN404Storage().totalNFTSupply;\n    }\n\n    /// @dev Returns `owner` NFT balance.\n    function _balanceOfNFT(address owner) internal view virtual returns (uint256) {\n        AddressData storage addressData = _getDN404Storage().addressData[owner];\n        return addressData.ownedLength + addressData.lockedLength;\n    }\n\n    /// @dev Returns the owner of token `id`.\n    /// Returns the zero address instead of reverting if the token does not exist.\n    function _ownerAt(uint256 id) internal view virtual returns (address) {\n        DN404Storage storage $ = _getDN404Storage();\n        return $.aliasToAddress[_get($.oo, _ownershipIndex(id))];\n    }\n\n    /// @dev Returns the owner of token `id`.\n    ///\n    /// Requirements:\n    /// - Token `id` must exist.\n    function _ownerOf(uint256 id) internal view virtual returns (address) {\n        if (!_exists(id)) revert TokenDoesNotExist();\n        return _ownerAt(id);\n    }\n\n    /// @dev Returns if token `id` exists.\n    function _exists(uint256 id) internal view virtual returns (bool) {\n        return _ownerAt(id) != address(0);\n    }\n\n    /// @dev Returns the account approved to manage token `id`.\n    ///\n    /// Requirements:\n    /// - Token `id` must exist.\n    function _getApproved(uint256 id) internal view virtual returns (address) {\n        if (!_exists(id)) revert TokenDoesNotExist();\n        return _getDN404Storage().nftApprovals[id];\n    }\n\n    /// @dev Sets `spender` as the approved account to manage token `id`, using `msgSender`.\n    ///\n    /// Requirements:\n    /// - `msgSender` must be the owner or an approved operator for the token owner.\n    function _approveNFT(address spender, uint256 id, address msgSender)\n        internal\n        virtual\n        returns (address owner)\n    {\n        DN404Storage storage $ = _getDN404Storage();\n\n        owner = $.aliasToAddress[_get($.oo, _ownershipIndex(id))];\n\n        if (msgSender != owner) {\n            if ($.operatorApprovals[msgSender][owner].value == 0) {\n                revert ApprovalCallerNotOwnerNorApproved();\n            }\n        }\n\n        $.nftApprovals[id] = spender;\n        LibBitmap.setTo($.mayHaveNFTApproval, id, spender != address(0));\n    }\n\n    function _removeNFTApproval(DN404Storage storage $, uint256 id) internal virtual {\n        if (LibBitmap.get($.mayHaveNFTApproval, id)) {\n            LibBitmap.setTo($.mayHaveNFTApproval, id, false);\n            delete $.nftApprovals[id];\n        }\n    }\n\n    /// @dev Approve or remove the `operator` as an operator for `msgSender`,\n    /// without authorization checks.\n    function _setApprovalForAll(address operator, bool approved, address msgSender)\n        internal\n        virtual\n    {\n        DN404Storage storage $ = _getDN404Storage();\n        Uint256Ref storage ref = $.operatorApprovals[operator][msgSender];\n        if (operator == address(this)) {\n            bool status = ref.value != 0;\n            AddressData storage senderAddressData = $.addressData[msgSender];\n            if (_toUint(approved) & _toUint(!status) != 0) {\n                // initialize when approving\n                senderAddressData.feePerNFTSnap = $.accFeePerNFT;\n                $.numExchangableNFT += senderAddressData.ownedLength;\n            } else if (_toUint(!approved) & _toUint(status) != 0) {\n                // refresh when removing approval\n                _pullFeeForTwo($, msgSender, msgSender);\n                $.numExchangableNFT -= senderAddressData.ownedLength;\n            }\n        }\n        ref.value = _toUint(approved); // `approved ? 1 : 0`\n    }\n\n    /// @dev Lock or unlock the `id`,\n    /// `msgSener` should be authorized as the operator of the owner of the NFT\n    function _setNFTLockState(uint256[] memory ids, bool lock, address msgSender)\n        internal\n        virtual\n    {\n        DN404Storage storage $ = _getDN404Storage();\n        _pullFeeForTwo($, msgSender, msgSender);\n\n        Uint32Map storage oo = $.oo;\n        LibBitmap.Bitmap storage tokenLocks = $.tokenLocks;\n\n        AddressData storage ownerAddressData = $.addressData[msgSender];\n        Uint32Map storage ownerLocked = $.locked[msgSender];\n        Uint32Map storage ownerOwned = $.owned[msgSender];\n        uint32 ownerAlias = ownerAddressData.addressAlias;\n        uint256 idLen = ids.length;\n\n        for (uint256 i; i < idLen; ++i) {\n            uint256 id = ids[i];\n\n            if (_get(oo, _ownershipIndex(id)) != ownerAlias) {\n                revert ApprovalCallerNotOwnerNorApproved();\n            }\n\n            uint32 ownedIndex = _get(oo, _ownedIndex(id));\n\n            if (LibBitmap.get(tokenLocks, id) == lock) revert TokenLockStatusNoChange();\n\n            if (!lock) {\n                // already locked, to unlock\n                LibBitmap.setTo(tokenLocks, id, false);\n\n                // swap with last NFT and pop the last\n                _delNFTAt(ownerLocked, oo, ownedIndex, --ownerAddressData.lockedLength);\n\n                uint256 n = ownerAddressData.ownedLength++;\n                _set(ownerOwned, n, uint32(id));\n                _set(oo, _ownedIndex(id), uint32(n));\n            } else {\n                // not locked, to lock\n                LibBitmap.setTo(tokenLocks, id, true);\n\n                // swap with last NFT and pop the last\n                _delNFTAt(ownerOwned, oo, ownedIndex, --ownerAddressData.ownedLength);\n\n                uint256 n = ownerAddressData.lockedLength++;\n                _set(ownerLocked, n, uint32(id));\n                _set(oo, _ownedIndex(id), uint32(n));\n            }\n        }\n\n        if (lock) $.numLockedNFT += uint32(idLen);\n        else $.numLockedNFT -= uint32(idLen);\n\n        if ($.operatorApprovals[address(this)][msgSender].value != 0) {\n            if (lock) $.numExchangableNFT -= uint32(ids.length);\n            else $.numExchangableNFT += uint32(ids.length);\n        }\n    }\n\n    /// @dev Returns the NFT IDs of `owner` in range `[begin, end)`.\n    /// Optimized for smaller bytecode size, as this function is intended for off-chain calling.\n    function _ownedIds(address owner, uint256 begin, uint256 end, bool locked)\n        internal\n        view\n        virtual\n        returns (uint256[] memory ids)\n    {\n        DN404Storage storage $ = _getDN404Storage();\n        (Uint32Map storage owned, uint256 n) = locked\n            ? ($.locked[owner], $.addressData[owner].lockedLength)\n            : ($.owned[owner], $.addressData[owner].ownedLength);\n        n = _min(n, end);\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Allocate one more word to store the offset when returning with assembly.\n            ids := mload(0x40)\n            mstore(0x20, owned.slot)\n            let i := begin\n            for {} lt(i, n) { i := add(i, 1) } {\n                mstore(0x00, shr(3, i))\n                let s := keccak256(0x00, 0x40) // Storage slot.\n                let id := and(0xffffffff, shr(shl(5, and(i, 7)), sload(s)))\n                mstore(add(add(ids, 0x20), shl(5, sub(i, begin))), id) // Append to.\n            }\n            mstore(ids, sub(i, begin)) // Store the length.\n            mstore(0x40, add(add(ids, 0x20), shl(5, sub(i, begin)))) // Allocate memory.\n        }\n    }\n\n    /// @dev Fallback modifier to dispatch calls from the mirror NFT contract\n    /// to internal functions in this contract.\n    modifier dn404Fallback() virtual {\n        DN404Storage storage $ = _getDN404Storage();\n\n        uint256 fnSelector = _calldataload(0x00) >> 224;\n        address mirror = $.mirrorERC721;\n\n        // `transferFromNFT(address,address,uint256,address)`.\n        if (fnSelector == 0xe5eb36c8) {\n            if (msg.sender != $.mirrorERC721) revert SenderNotMirror();\n            _transferFromNFT(\n                address(uint160(_calldataload(0x04))), // `from`.\n                address(uint160(_calldataload(0x24))), // `to`.\n                _calldataload(0x44), // `id`.\n                address(uint160(_calldataload(0x64))) // `msgSender`.\n            );\n            _return(1);\n        }\n        // `setApprovalForAll(address,bool,address)`.\n        if (fnSelector == 0x813500fc) {\n            if (msg.sender != $.mirrorERC721) revert SenderNotMirror();\n            _setApprovalForAll(\n                address(uint160(_calldataload(0x04))), // `spender`.\n                _calldataload(0x24) != 0, // `status`.\n                address(uint160(_calldataload(0x44))) // `msgSender`.\n            );\n            _return(1);\n        }\n        // `exchangeNFT(uint256,uint256,address)`.\n        if (fnSelector == 0x2c5966af) {\n            if (msg.sender != $.mirrorERC721) revert SenderNotMirror();\n            (address x, address y, uint256 fee) = _exchangeNFT(\n                _calldataload(0x04), // `idX`\n                _calldataload(0x24), // `idY`\n                address(uint160(_calldataload(0x44))) // `msgSender`\n            );\n\n            /// @solidity memory-safe-assembly\n            assembly {\n                mstore(0x00, x)\n                mstore(0x20, y)\n                mstore(0x40, fee)\n                return(0x00, 0x60)\n            }\n        }\n        // `setNFTLockState(uint256,uint256[])`.\n        if (fnSelector == 0xb79cc1bd) {\n            if (msg.sender != $.mirrorERC721) revert SenderNotMirror();\n\n            uint256 senderAndLockFlag = _calldataload(0x04);\n            uint256[] memory ids;\n            assembly {\n                let offset := add(0x24, calldataload(0x24))\n                let length := calldataload(sub(offset, 0x20))\n                ids := mload(0x40)\n                mstore(0x40, add(add(ids, 0x20), shl(5, length))) // Allocate memory.\n\n                mstore(ids, length) // Store array length\n                calldatacopy(add(ids, 0x20), offset, shl(5, length)) // Copy array elements\n            }\n\n            _setNFTLockState(\n                ids, // `ids`\n                uint8(senderAndLockFlag) != 0, // `lock`\n                address(uint160(senderAndLockFlag >> 96)) // `msgSender`\n            );\n            _return(1);\n        }\n        // `isApprovedForAll(address,address)`.\n        if (fnSelector == 0xe985e9c5) {\n            address owner = address(uint160(_calldataload(0x04)));\n            address spender = address(uint160(_calldataload(0x24)));\n            Uint256Ref storage ref = $.operatorApprovals[spender][owner];\n\n            _return(ref.value);\n        }\n        // `ownerOf(uint256)`.\n        if (fnSelector == 0x6352211e) {\n            _return(uint160(_ownerOf(_calldataload(0x04))));\n        }\n        // `ownerAt(uint256)`.\n        if (fnSelector == 0x24359879) {\n            _return(uint160(_ownerAt(_calldataload(0x04))));\n        }\n        // `approveNFT(address,uint256,address)`.\n        if (fnSelector == 0xd10b6e0c) {\n            if (msg.sender != $.mirrorERC721) revert SenderNotMirror();\n            address owner = _approveNFT(\n                address(uint160(_calldataload(0x04))), // `spender`.\n                _calldataload(0x24), // `id`.\n                address(uint160(_calldataload(0x44))) // `msgSender`.\n            );\n            _return(uint160(owner));\n        }\n        // `ownedIds(uint256,uint256,uint256)`.\n        if (fnSelector == 0xf9b4b328) {\n            uint256 addrAndFlag = _calldataload(0x04);\n            /// @solidity memory-safe-assembly\n            assembly {\n                // Allocate one word to store the offset of the array in returndata.\n                mstore(0x40, add(mload(0x40), 0x20))\n            }\n\n            uint256[] memory ids = _ownedIds(\n                address(uint160(addrAndFlag >> 96)),\n                _calldataload(0x24),\n                _calldataload(0x44),\n                uint8(addrAndFlag) != 0\n            );\n            /// @solidity memory-safe-assembly\n            assembly {\n                // Memory safe, as we've advanced the free memory pointer by a word.\n                let p := sub(ids, 0x20)\n                mstore(p, 0x20) // Store the offset of the array in returndata.\n                return(p, add(0x40, shl(5, mload(ids))))\n            }\n        }\n        // `getApproved(uint256)`.\n        if (fnSelector == 0x081812fc) {\n            _return(uint160(_getApproved(_calldataload(0x04))));\n        }\n        // `balanceOfNFT(address)`.\n        if (fnSelector == 0xf5b100ea) {\n            _return(_balanceOfNFT(address(uint160(_calldataload(0x04)))));\n        }\n        // `totalNFTSupply()`.\n        if (fnSelector == 0xe2c79281) {\n            _return(_totalNFTSupply());\n        }\n        // `implementsDN404()`.\n        if (fnSelector == 0xb7a94eb8) {\n            _return(1);\n        }\n        _;\n    }\n\n    /// @dev Fallback function for calls from mirror NFT contract.\n    fallback() external payable virtual dn404Fallback {}\n\n    receive() external payable virtual {}\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                 INTERNAL / PRIVATE HELPERS                 */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns `i << 1`.\n    function _ownershipIndex(uint256 i) internal pure returns (uint256) {\n        unchecked {\n            return i << 1;\n        }\n    }\n\n    /// @dev Returns `(i << 1) + 1`.\n    function _ownedIndex(uint256 i) internal pure returns (uint256) {\n        unchecked {\n            return (i << 1) + 1;\n        }\n    }\n\n    function _delNFTAt(\n        Uint32Map storage owned,\n        Uint32Map storage oo,\n        uint256 toDelIndex,\n        uint256 lastIndex\n    ) internal {\n        if (toDelIndex != lastIndex) {\n            uint256 updatedId = _get(owned, lastIndex);\n            _set(owned, toDelIndex, uint32(updatedId));\n            _set(oo, _ownedIndex(updatedId), uint32(toDelIndex));\n        }\n    }\n\n    /// @dev Returns whether `amount` is a valid `totalSupply`.\n    function _totalSupplyOverflows(uint256 amount) internal view returns (bool result) {\n        uint256 unit = _unit();\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := iszero(iszero(or(shr(96, amount), lt(0xfffffffe, div(amount, unit)))))\n        }\n    }\n\n    /// @dev Struct containing direct transfer log data for {Transfer} events to be\n    /// emitted by the mirror NFT contract.\n    struct _DNDirectLogs {\n        uint256 offset;\n        address from;\n        address to;\n        uint256[] logs;\n    }\n\n    /// @dev Initiates memory allocation for direct logs with `n` log items.\n    function _directLogsMalloc(uint256 n, address from, address to)\n        private\n        pure\n        returns (_DNDirectLogs memory p)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Note that `p` implicitly allocates and advances the free memory pointer by\n            // 4 words, which we can safely mutate in `_packedLogsSend`.\n            let logs := mload(0x40)\n            mstore(logs, n) // Store the length.\n            let offset := add(0x20, logs) // Skip the word for `p.logs.length`.\n            mstore(0x40, add(offset, shl(5, n))) // Allocate memory.\n            mstore(add(0x60, p), logs) // Set `p.logs`.\n            mstore(add(0x40, p), shr(96, shl(96, to))) // Set `p.to`.\n            mstore(add(0x20, p), shr(96, shl(96, from))) // Set `p.from`.\n            mstore(p, offset) // Set `p.offset`.\n        }\n    }\n\n    /// @dev Adds a direct log item to `p` with token `id`.\n    function _directLogsAppend(_DNDirectLogs memory p, uint256 id) private pure {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let offset := mload(p)\n            mstore(offset, id)\n            mstore(p, add(offset, 0x20))\n        }\n    }\n\n    /// @dev Calls the `mirror` NFT contract to emit {Transfer} events for packed logs `p`.\n    function _directLogsSend(_DNDirectLogs memory p, address mirror) private {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let logs := mload(add(p, 0x60))\n            let n := add(0x84, shl(5, mload(logs))) // Length of calldata to send.\n            let o := sub(logs, 0x80) // Start of calldata to send.\n            mstore(o, 0x144027d3) // `logDirectTransfer(address,address,uint256[])`.\n            mstore(add(o, 0x20), mload(add(0x20, p)))\n            mstore(add(o, 0x40), mload(add(0x40, p)))\n            mstore(add(o, 0x60), 0x60) // Offset of `logs` in the calldata to send.\n            if iszero(and(eq(mload(o), 1), call(gas(), mirror, 0, add(o, 0x1c), n, o, 0x20))) {\n                revert(o, 0x00)\n            }\n        }\n    }\n\n    /// emitted by the mirror NFT contract.\n    struct _PackedLogs {\n        uint256 offset;\n        uint256 addressAndBit;\n        uint256[] logs;\n    }\n\n    /// @dev Initiates memory allocation for packed logs with `n` log items.\n    function _packedLogsMalloc(uint256 n) internal pure returns (_PackedLogs memory p) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Note that `p` implicitly allocates and advances the free memory pointer by\n            // 2 words, which we can safely mutate in `_packedLogsSend`.\n            let logs := mload(0x40)\n            mstore(logs, n) // Store the length.\n            let offset := add(0x20, logs)\n            mstore(0x40, add(offset, shl(5, n))) // Allocate memory.\n            mstore(add(0x40, p), logs) // Set `p.logs`.\n            mstore(p, offset) // Set `p.offset`.\n        }\n    }\n\n    /// @dev Set the current address and the burn bit.\n    function _packedLogsSet(_PackedLogs memory p, address a, uint256 burnBit) internal pure {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(add(p, 0x20), or(shl(96, a), burnBit))\n        }\n    }\n\n    /// @dev Adds a packed log item to `p` with token `id`.\n    function _packedLogsAppend(_PackedLogs memory p, uint256 id) internal pure {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let offset := mload(p)\n            mstore(offset, or(mload(add(p, 0x20)), shl(8, id)))\n            mstore(p, add(offset, 0x20))\n        }\n    }\n\n    function _packedLogsSend(_PackedLogs memory p, address mirror) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let logs := mload(add(p, 0x40))\n            let o := sub(logs, 0x40) // Start of calldata to send.\n            mstore(o, 0x263c69d6) // `logTransfer(uint256[])`.\n            mstore(add(o, 0x20), 0x20) // Offset of `logs` in the calldata to send.\n            let n := add(0x44, shl(5, mload(logs))) // Length of calldata to send.\n            if iszero(and(eq(mload(o), 1), call(gas(), mirror, 0, add(o, 0x1c), n, o, 0x20))) {\n                revert(o, 0x00)\n            }\n        }\n    }\n\n    /// @dev Struct of temporary variables for transfers.\n    struct _TransferTemps {\n        uint256 numNFTBurns;\n        uint256 numNFTMints;\n        uint256 fromBalance;\n        uint256 toBalance;\n        uint256 fromOwnedLength;\n        uint256 toOwnedLength;\n        uint256 totalSupply;\n        uint256 fromLockedLength;\n        uint256 toLockedLength;\n    }\n\n    /// @dev Returns if `a` has bytecode of non-zero length.\n    function _hasCode(address a) private view returns (bool result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := extcodesize(a) // Can handle dirty upper bits.\n        }\n    }\n\n    /// @dev Returns the calldata value at `offset`.\n    function _calldataload(uint256 offset) private pure returns (uint256 value) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            value := calldataload(offset)\n        }\n    }\n\n    /// @dev Executes a return opcode to return `x` and end the current call frame.\n    function _return(uint256 x) private pure {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, x)\n            return(0x00, 0x20)\n        }\n    }\n\n    /// @dev Returns `max(0, x - y)`.\n    function _zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := mul(gt(x, y), sub(x, y))\n        }\n    }\n\n    /// @dev Returns `x < y ? x : y`.\n    function _min(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := xor(x, mul(xor(x, y), lt(y, x)))\n        }\n    }\n\n    /// @dev Returns `b ? 1 : 0`.\n    function _toUint(bool b) internal pure returns (uint256 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := iszero(iszero(b))\n        }\n    }\n\n    /// @dev Returns the uint32 value at `index` in `map`.\n    function _get(Uint32Map storage map, uint256 index) internal view returns (uint32 result) {\n        result = uint32(map.map[index >> 3] >> ((index & 7) << 5));\n    }\n\n    /// @dev Updates the uint32 value at `index` in `map`.\n    function _set(Uint32Map storage map, uint256 index, uint32 value) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x20, map.slot)\n            mstore(0x00, shr(3, index))\n            let s := keccak256(0x00, 0x40) // Storage slot.\n            let o := shl(5, and(index, 7)) // Storage slot offset (bits).\n            let v := sload(s) // Storage slot value.\n            let m := 0xffffffff // Value mask.\n            sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))\n        }\n    }\n\n    /// @dev Sets the owner alias and the owned index together.\n    function _setOwnerAliasAndOwnedIndex(\n        Uint32Map storage map,\n        uint256 id,\n        uint32 ownership,\n        uint32 ownedIndex\n    ) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let value := or(shl(32, ownedIndex), and(0xffffffff, ownership))\n            mstore(0x20, map.slot)\n            mstore(0x00, shr(2, id))\n            let s := keccak256(0x00, 0x40) // Storage slot.\n            let o := shl(6, and(id, 3)) // Storage slot offset (bits).\n            let v := sload(s) // Storage slot value.\n            let m := 0xffffffffffffffff // Value mask.\n            sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))\n        }\n    }\n}\n"
      },
      "lib/solady/src/auth/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)\n///\n/// @dev Note:\n/// This implementation does NOT auto-initialize the owner to `msg.sender`.\n/// You MUST call the `_initializeOwner` in the constructor / initializer.\n///\n/// While the ownable portion follows\n/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,\n/// the nomenclature for the 2-step ownership handover may be unique to this codebase.\nabstract contract Ownable {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       CUSTOM ERRORS                        */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The caller is not authorized to call the function.\n    error Unauthorized();\n\n    /// @dev The `newOwner` cannot be the zero address.\n    error NewOwnerIsZeroAddress();\n\n    /// @dev The `pendingOwner` does not have a valid handover request.\n    error NoHandoverRequest();\n\n    /// @dev Cannot double-initialize.\n    error AlreadyInitialized();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                           EVENTS                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.\n    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be\n    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),\n    /// despite it not being as lightweight as a single argument event.\n    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);\n\n    /// @dev An ownership handover to `pendingOwner` has been requested.\n    event OwnershipHandoverRequested(address indexed pendingOwner);\n\n    /// @dev The ownership handover to `pendingOwner` has been canceled.\n    event OwnershipHandoverCanceled(address indexed pendingOwner);\n\n    /// @dev `keccak256(bytes(\"OwnershipTransferred(address,address)\"))`.\n    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =\n        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;\n\n    /// @dev `keccak256(bytes(\"OwnershipHandoverRequested(address)\"))`.\n    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =\n        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;\n\n    /// @dev `keccak256(bytes(\"OwnershipHandoverCanceled(address)\"))`.\n    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =\n        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                          STORAGE                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The owner slot is given by:\n    /// `bytes32(~uint256(uint32(bytes4(keccak256(\"_OWNER_SLOT_NOT\")))))`.\n    /// It is intentionally chosen to be a high value\n    /// to avoid collision with lower slots.\n    /// The choice of manual storage layout is to enable compatibility\n    /// with both regular and upgradeable contracts.\n    bytes32 internal constant _OWNER_SLOT =\n        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;\n\n    /// The ownership handover slot of `newOwner` is given by:\n    /// ```\n    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))\n    ///     let handoverSlot := keccak256(0x00, 0x20)\n    /// ```\n    /// It stores the expiry timestamp of the two-step ownership handover.\n    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                     INTERNAL FUNCTIONS                     */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.\n    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}\n\n    /// @dev Initializes the owner directly without authorization guard.\n    /// This function must be called upon initialization,\n    /// regardless of whether the contract is upgradeable or not.\n    /// This is to enable generalization to both regular and upgradeable contracts,\n    /// and to save gas in case the initial owner is not the caller.\n    /// For performance reasons, this function will not check if there\n    /// is an existing owner.\n    function _initializeOwner(address newOwner) internal virtual {\n        if (_guardInitializeOwner()) {\n            /// @solidity memory-safe-assembly\n            assembly {\n                let ownerSlot := _OWNER_SLOT\n                if sload(ownerSlot) {\n                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.\n                    revert(0x1c, 0x04)\n                }\n                // Clean the upper 96 bits.\n                newOwner := shr(96, shl(96, newOwner))\n                // Store the new value.\n                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))\n                // Emit the {OwnershipTransferred} event.\n                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)\n            }\n        } else {\n            /// @solidity memory-safe-assembly\n            assembly {\n                // Clean the upper 96 bits.\n                newOwner := shr(96, shl(96, newOwner))\n                // Store the new value.\n                sstore(_OWNER_SLOT, newOwner)\n                // Emit the {OwnershipTransferred} event.\n                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)\n            }\n        }\n    }\n\n    /// @dev Sets the owner directly without authorization guard.\n    function _setOwner(address newOwner) internal virtual {\n        if (_guardInitializeOwner()) {\n            /// @solidity memory-safe-assembly\n            assembly {\n                let ownerSlot := _OWNER_SLOT\n                // Clean the upper 96 bits.\n                newOwner := shr(96, shl(96, newOwner))\n                // Emit the {OwnershipTransferred} event.\n                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)\n                // Store the new value.\n                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))\n            }\n        } else {\n            /// @solidity memory-safe-assembly\n            assembly {\n                let ownerSlot := _OWNER_SLOT\n                // Clean the upper 96 bits.\n                newOwner := shr(96, shl(96, newOwner))\n                // Emit the {OwnershipTransferred} event.\n                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)\n                // Store the new value.\n                sstore(ownerSlot, newOwner)\n            }\n        }\n    }\n\n    /// @dev Throws if the sender is not the owner.\n    function _checkOwner() internal view virtual {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // If the caller is not the stored owner, revert.\n            if iszero(eq(caller(), sload(_OWNER_SLOT))) {\n                mstore(0x00, 0x82b42900) // `Unauthorized()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n\n    /// @dev Returns how long a two-step ownership handover is valid for in seconds.\n    /// Override to return a different value if needed.\n    /// Made internal to conserve bytecode. Wrap it in a public function if needed.\n    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {\n        return 48 * 3600;\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                  PUBLIC UPDATE FUNCTIONS                   */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Allows the owner to transfer the ownership to `newOwner`.\n    function transferOwnership(address newOwner) public payable virtual onlyOwner {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(shl(96, newOwner)) {\n                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.\n                revert(0x1c, 0x04)\n            }\n        }\n        _setOwner(newOwner);\n    }\n\n    /// @dev Allows the owner to renounce their ownership.\n    function renounceOwnership() public payable virtual onlyOwner {\n        _setOwner(address(0));\n    }\n\n    /// @dev Request a two-step ownership handover to the caller.\n    /// The request will automatically expire in 48 hours (172800 seconds) by default.\n    function requestOwnershipHandover() public payable virtual {\n        unchecked {\n            uint256 expires = block.timestamp + _ownershipHandoverValidFor();\n            /// @solidity memory-safe-assembly\n            assembly {\n                // Compute and set the handover slot to `expires`.\n                mstore(0x0c, _HANDOVER_SLOT_SEED)\n                mstore(0x00, caller())\n                sstore(keccak256(0x0c, 0x20), expires)\n                // Emit the {OwnershipHandoverRequested} event.\n                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())\n            }\n        }\n    }\n\n    /// @dev Cancels the two-step ownership handover to the caller, if any.\n    function cancelOwnershipHandover() public payable virtual {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute and set the handover slot to 0.\n            mstore(0x0c, _HANDOVER_SLOT_SEED)\n            mstore(0x00, caller())\n            sstore(keccak256(0x0c, 0x20), 0)\n            // Emit the {OwnershipHandoverCanceled} event.\n            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())\n        }\n    }\n\n    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.\n    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.\n    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute and set the handover slot to 0.\n            mstore(0x0c, _HANDOVER_SLOT_SEED)\n            mstore(0x00, pendingOwner)\n            let handoverSlot := keccak256(0x0c, 0x20)\n            // If the handover does not exist, or has expired.\n            if gt(timestamp(), sload(handoverSlot)) {\n                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.\n                revert(0x1c, 0x04)\n            }\n            // Set the handover slot to 0.\n            sstore(handoverSlot, 0)\n        }\n        _setOwner(pendingOwner);\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                   PUBLIC READ FUNCTIONS                    */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Returns the owner of the contract.\n    function owner() public view virtual returns (address result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := sload(_OWNER_SLOT)\n        }\n    }\n\n    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.\n    function ownershipHandoverExpiresAt(address pendingOwner)\n        public\n        view\n        virtual\n        returns (uint256 result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Compute the handover slot.\n            mstore(0x0c, _HANDOVER_SLOT_SEED)\n            mstore(0x00, pendingOwner)\n            // Load the handover slot.\n            result := sload(keccak256(0x0c, 0x20))\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         MODIFIERS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Marks a function as only callable by the owner.\n    modifier onlyOwner() virtual {\n        _checkOwner();\n        _;\n    }\n}\n"
      },
      "lib/solady/src/utils/UUPSUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice UUPS proxy mixin.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/UUPSUpgradeable.sol)\n/// @author Modified from OpenZeppelin\n/// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol)\n///\n/// Note:\n/// - This implementation is intended to be used with ERC1967 proxies.\n/// See: `LibClone.deployERC1967` and related functions.\n/// - This implementation is NOT compatible with legacy OpenZeppelin proxies\n/// which do not store the implementation at `_ERC1967_IMPLEMENTATION_SLOT`.\nabstract contract UUPSUpgradeable {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       CUSTOM ERRORS                        */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The upgrade failed.\n    error UpgradeFailed();\n\n    /// @dev The call is from an unauthorized call context.\n    error UnauthorizedCallContext();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         IMMUTABLES                         */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev For checking if the context is a delegate call.\n    uint256 private immutable __self = uint256(uint160(address(this)));\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                           EVENTS                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Emitted when the proxy's implementation is upgraded.\n    event Upgraded(address indexed implementation);\n\n    /// @dev `keccak256(bytes(\"Upgraded(address)\"))`.\n    uint256 private constant _UPGRADED_EVENT_SIGNATURE =\n        0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                          STORAGE                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The ERC-1967 storage slot for the implementation in the proxy.\n    /// `uint256(keccak256(\"eip1967.proxy.implementation\")) - 1`.\n    bytes32 internal constant _ERC1967_IMPLEMENTATION_SLOT =\n        0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                      UUPS OPERATIONS                       */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Please override this function to check if `msg.sender` is authorized\n    /// to upgrade the proxy to `newImplementation`, reverting if not.\n    /// ```\n    ///     function _authorizeUpgrade(address) internal override onlyOwner {}\n    /// ```\n    function _authorizeUpgrade(address newImplementation) internal virtual;\n\n    /// @dev Returns the storage slot used by the implementation,\n    /// as specified in [ERC1822](https://eips.ethereum.org/EIPS/eip-1822).\n    ///\n    /// Note: The `notDelegated` modifier prevents accidental upgrades to\n    /// an implementation that is a proxy contract.\n    function proxiableUUID() public view virtual notDelegated returns (bytes32) {\n        // This function must always return `_ERC1967_IMPLEMENTATION_SLOT` to comply with ERC1967.\n        return _ERC1967_IMPLEMENTATION_SLOT;\n    }\n\n    /// @dev Upgrades the proxy's implementation to `newImplementation`.\n    /// Emits a {Upgraded} event.\n    ///\n    /// Note: Passing in empty `data` skips the delegatecall to `newImplementation`.\n    function upgradeToAndCall(address newImplementation, bytes calldata data)\n        public\n        payable\n        virtual\n        onlyProxy\n    {\n        _authorizeUpgrade(newImplementation);\n        /// @solidity memory-safe-assembly\n        assembly {\n            newImplementation := shr(96, shl(96, newImplementation)) // Clears upper 96 bits.\n            mstore(0x01, 0x52d1902d) // `proxiableUUID()`.\n            let s := _ERC1967_IMPLEMENTATION_SLOT\n            // Check if `newImplementation` implements `proxiableUUID` correctly.\n            if iszero(eq(mload(staticcall(gas(), newImplementation, 0x1d, 0x04, 0x01, 0x20)), s)) {\n                mstore(0x01, 0x55299b49) // `UpgradeFailed()`.\n                revert(0x1d, 0x04)\n            }\n            // Emit the {Upgraded} event.\n            log2(codesize(), 0x00, _UPGRADED_EVENT_SIGNATURE, newImplementation)\n            sstore(s, newImplementation) // Updates the implementation.\n\n            // Perform a delegatecall to `newImplementation` if `data` is non-empty.\n            if data.length {\n                // Forwards the `data` to `newImplementation` via delegatecall.\n                let m := mload(0x40)\n                calldatacopy(m, data.offset, data.length)\n                if iszero(delegatecall(gas(), newImplementation, m, data.length, codesize(), 0x00))\n                {\n                    // Bubble up the revert if the call reverts.\n                    returndatacopy(m, 0x00, returndatasize())\n                    revert(m, returndatasize())\n                }\n            }\n        }\n    }\n\n    /// @dev Requires that the execution is performed through a proxy.\n    modifier onlyProxy() {\n        uint256 s = __self;\n        /// @solidity memory-safe-assembly\n        assembly {\n            // To enable use cases with an immutable default implementation in the bytecode,\n            // (see: ERC6551Proxy), we don't require that the proxy address must match the\n            // value stored in the implementation slot, which may not be initialized.\n            if eq(s, address()) {\n                mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`.\n                revert(0x1c, 0x04)\n            }\n        }\n        _;\n    }\n\n    /// @dev Requires that the execution is NOT performed via delegatecall.\n    /// This is the opposite of `onlyProxy`.\n    modifier notDelegated() {\n        uint256 s = __self;\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(eq(s, address())) {\n                mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`.\n                revert(0x1c, 0x04)\n            }\n        }\n        _;\n    }\n}\n"
      },
      "lib/solady/src/utils/LibString.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for converting numbers into strings and other string operations.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)\n///\n/// @dev Note:\n/// For performance and bytecode compactness, most of the string operations are restricted to\n/// byte strings (7-bit ASCII), except where otherwise specified.\n/// Usage of byte string operations on charsets with runes spanning two or more bytes\n/// can lead to undefined behavior.\nlibrary LibString {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                        CUSTOM ERRORS                       */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The length of the output is too small to contain all the hex digits.\n    error HexLengthInsufficient();\n\n    /// @dev The length of the string is more than 32 bytes.\n    error TooBigForSmallString();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         CONSTANTS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The constant returned when the `search` is not found in the string.\n    uint256 internal constant NOT_FOUND = type(uint256).max;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                     DECIMAL OPERATIONS                     */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Returns the base 10 decimal representation of `value`.\n    function toString(uint256 value) internal pure returns (string memory str) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\n            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\n            // We will need 1 word for the trailing zeros padding, 1 word for the length,\n            // and 3 words for a maximum of 78 digits.\n            str := add(mload(0x40), 0x80)\n            // Update the free memory pointer to allocate.\n            mstore(0x40, add(str, 0x20))\n            // Zeroize the slot after the string.\n            mstore(str, 0)\n\n            // Cache the end of the memory to calculate the length later.\n            let end := str\n\n            let w := not(0) // Tsk.\n            // We write the string from rightmost digit to leftmost digit.\n            // The following is essentially a do-while loop that also handles the zero case.\n            for { let temp := value } 1 {} {\n                str := add(str, w) // `sub(str, 1)`.\n                // Write the character to the pointer.\n                // The ASCII index of the '0' character is 48.\n                mstore8(str, add(48, mod(temp, 10)))\n                // Keep dividing `temp` until zero.\n                temp := div(temp, 10)\n                if iszero(temp) { break }\n            }\n\n            let length := sub(end, str)\n            // Move the pointer 32 bytes leftwards to make room for the length.\n            str := sub(str, 0x20)\n            // Store the length.\n            mstore(str, length)\n        }\n    }\n\n    /// @dev Returns the base 10 decimal representation of `value`.\n    function toString(int256 value) internal pure returns (string memory str) {\n        if (value >= 0) {\n            return toString(uint256(value));\n        }\n        unchecked {\n            str = toString(~uint256(value) + 1);\n        }\n        /// @solidity memory-safe-assembly\n        assembly {\n            // We still have some spare memory space on the left,\n            // as we have allocated 3 words (96 bytes) for up to 78 digits.\n            let length := mload(str) // Load the string length.\n            mstore(str, 0x2d) // Store the '-' character.\n            str := sub(str, 1) // Move back the string pointer by a byte.\n            mstore(str, add(length, 1)) // Update the string length.\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                   HEXADECIMAL OPERATIONS                   */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Returns the hexadecimal representation of `value`,\n    /// left-padded to an input length of `length` bytes.\n    /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n    /// giving a total length of `length * 2 + 2` bytes.\n    /// Reverts if `length` is too small for the output to contain all the digits.\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {\n        str = toHexStringNoPrefix(value, length);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let strLength := add(mload(str), 2) // Compute the length.\n            mstore(str, 0x3078) // Write the \"0x\" prefix.\n            str := sub(str, 2) // Move the pointer.\n            mstore(str, strLength) // Write the length.\n        }\n    }\n\n    /// @dev Returns the hexadecimal representation of `value`,\n    /// left-padded to an input length of `length` bytes.\n    /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n    /// giving a total length of `length * 2` bytes.\n    /// Reverts if `length` is too small for the output to contain all the digits.\n    function toHexStringNoPrefix(uint256 value, uint256 length)\n        internal\n        pure\n        returns (string memory str)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes\n            // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.\n            // We add 0x20 to the total and round down to a multiple of 0x20.\n            // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.\n            str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))\n            // Allocate the memory.\n            mstore(0x40, add(str, 0x20))\n            // Zeroize the slot after the string.\n            mstore(str, 0)\n\n            // Cache the end to calculate the length later.\n            let end := str\n            // Store \"0123456789abcdef\" in scratch space.\n            mstore(0x0f, 0x30313233343536373839616263646566)\n\n            let start := sub(str, add(length, length))\n            let w := not(1) // Tsk.\n            let temp := value\n            // We write the string from rightmost digit to leftmost digit.\n            // The following is essentially a do-while loop that also handles the zero case.\n            for {} 1 {} {\n                str := add(str, w) // `sub(str, 2)`.\n                mstore8(add(str, 1), mload(and(temp, 15)))\n                mstore8(str, mload(and(shr(4, temp), 15)))\n                temp := shr(8, temp)\n                if iszero(xor(str, start)) { break }\n            }\n\n            if temp {\n                mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.\n                revert(0x1c, 0x04)\n            }\n\n            // Compute the string's length.\n            let strLength := sub(end, str)\n            // Move the pointer and write the length.\n            str := sub(str, 0x20)\n            mstore(str, strLength)\n        }\n    }\n\n    /// @dev Returns the hexadecimal representation of `value`.\n    /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n    /// As address are 20 bytes long, the output will left-padded to have\n    /// a length of `20 * 2 + 2` bytes.\n    function toHexString(uint256 value) internal pure returns (string memory str) {\n        str = toHexStringNoPrefix(value);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let strLength := add(mload(str), 2) // Compute the length.\n            mstore(str, 0x3078) // Write the \"0x\" prefix.\n            str := sub(str, 2) // Move the pointer.\n            mstore(str, strLength) // Write the length.\n        }\n    }\n\n    /// @dev Returns the hexadecimal representation of `value`.\n    /// The output is prefixed with \"0x\".\n    /// The output excludes leading \"0\" from the `toHexString` output.\n    /// `0x00: \"0x0\", 0x01: \"0x1\", 0x12: \"0x12\", 0x123: \"0x123\"`.\n    function toMinimalHexString(uint256 value) internal pure returns (string memory str) {\n        str = toHexStringNoPrefix(value);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n            let strLength := add(mload(str), 2) // Compute the length.\n            mstore(add(str, o), 0x3078) // Write the \"0x\" prefix, accounting for leading zero.\n            str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.\n            mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n        }\n    }\n\n    /// @dev Returns the hexadecimal representation of `value`.\n    /// The output excludes leading \"0\" from the `toHexStringNoPrefix` output.\n    /// `0x00: \"0\", 0x01: \"1\", 0x12: \"12\", 0x123: \"123\"`.\n    function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n        str = toHexStringNoPrefix(value);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n            let strLength := mload(str) // Get the length.\n            str := add(str, o) // Move the pointer, accounting for leading zero.\n            mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n        }\n    }\n\n    /// @dev Returns the hexadecimal representation of `value`.\n    /// The output is encoded using 2 hexadecimal digits per byte.\n    /// As address are 20 bytes long, the output will left-padded to have\n    /// a length of `20 * 2` bytes.\n    function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n            // 0x02 bytes for the prefix, and 0x40 bytes for the digits.\n            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.\n            str := add(mload(0x40), 0x80)\n            // Allocate the memory.\n            mstore(0x40, add(str, 0x20))\n            // Zeroize the slot after the string.\n            mstore(str, 0)\n\n            // Cache the end to calculate the length later.\n            let end := str\n            // Store \"0123456789abcdef\" in scratch space.\n            mstore(0x0f, 0x30313233343536373839616263646566)\n\n            let w := not(1) // Tsk.\n            // We write the string from rightmost digit to leftmost digit.\n            // The following is essentially a do-while loop that also handles the zero case.\n            for { let temp := value } 1 {} {\n                str := add(str, w) // `sub(str, 2)`.\n                mstore8(add(str, 1), mload(and(temp, 15)))\n                mstore8(str, mload(and(shr(4, temp), 15)))\n                temp := shr(8, temp)\n                if iszero(temp) { break }\n            }\n\n            // Compute the string's length.\n            let strLength := sub(end, str)\n            // Move the pointer and write the length.\n            str := sub(str, 0x20)\n            mstore(str, strLength)\n        }\n    }\n\n    /// @dev Returns the hexadecimal representation of `value`.\n    /// The output is prefixed with \"0x\", encoded using 2 hexadecimal digits per byte,\n    /// and the alphabets are capitalized conditionally according to\n    /// https://eips.ethereum.org/EIPS/eip-55\n    function toHexStringChecksummed(address value) internal pure returns (string memory str) {\n        str = toHexString(value);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`\n            let o := add(str, 0x22)\n            let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `\n            let t := shl(240, 136) // `0b10001000 << 240`\n            for { let i := 0 } 1 {} {\n                mstore(add(i, i), mul(t, byte(i, hashed)))\n                i := add(i, 1)\n                if eq(i, 20) { break }\n            }\n            mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))\n            o := add(o, 0x20)\n            mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))\n        }\n    }\n\n    /// @dev Returns the hexadecimal representation of `value`.\n    /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n    function toHexString(address value) internal pure returns (string memory str) {\n        str = toHexStringNoPrefix(value);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let strLength := add(mload(str), 2) // Compute the length.\n            mstore(str, 0x3078) // Write the \"0x\" prefix.\n            str := sub(str, 2) // Move the pointer.\n            mstore(str, strLength) // Write the length.\n        }\n    }\n\n    /// @dev Returns the hexadecimal representation of `value`.\n    /// The output is encoded using 2 hexadecimal digits per byte.\n    function toHexStringNoPrefix(address value) internal pure returns (string memory str) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            str := mload(0x40)\n\n            // Allocate the memory.\n            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n            // 0x02 bytes for the prefix, and 0x28 bytes for the digits.\n            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.\n            mstore(0x40, add(str, 0x80))\n\n            // Store \"0123456789abcdef\" in scratch space.\n            mstore(0x0f, 0x30313233343536373839616263646566)\n\n            str := add(str, 2)\n            mstore(str, 40)\n\n            let o := add(str, 0x20)\n            mstore(add(o, 40), 0)\n\n            value := shl(96, value)\n\n            // We write the string from rightmost digit to leftmost digit.\n            // The following is essentially a do-while loop that also handles the zero case.\n            for { let i := 0 } 1 {} {\n                let p := add(o, add(i, i))\n                let temp := byte(i, value)\n                mstore8(add(p, 1), mload(and(temp, 15)))\n                mstore8(p, mload(shr(4, temp)))\n                i := add(i, 1)\n                if eq(i, 20) { break }\n            }\n        }\n    }\n\n    /// @dev Returns the hex encoded string from the raw bytes.\n    /// The output is encoded using 2 hexadecimal digits per byte.\n    function toHexString(bytes memory raw) internal pure returns (string memory str) {\n        str = toHexStringNoPrefix(raw);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let strLength := add(mload(str), 2) // Compute the length.\n            mstore(str, 0x3078) // Write the \"0x\" prefix.\n            str := sub(str, 2) // Move the pointer.\n            mstore(str, strLength) // Write the length.\n        }\n    }\n\n    /// @dev Returns the hex encoded string from the raw bytes.\n    /// The output is encoded using 2 hexadecimal digits per byte.\n    function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let length := mload(raw)\n            str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.\n            mstore(str, add(length, length)) // Store the length of the output.\n\n            // Store \"0123456789abcdef\" in scratch space.\n            mstore(0x0f, 0x30313233343536373839616263646566)\n\n            let o := add(str, 0x20)\n            let end := add(raw, length)\n\n            for {} iszero(eq(raw, end)) {} {\n                raw := add(raw, 1)\n                mstore8(add(o, 1), mload(and(mload(raw), 15)))\n                mstore8(o, mload(and(shr(4, mload(raw)), 15)))\n                o := add(o, 2)\n            }\n            mstore(o, 0) // Zeroize the slot after the string.\n            mstore(0x40, add(o, 0x20)) // Allocate the memory.\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                   RUNE STRING OPERATIONS                   */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Returns the number of UTF characters in the string.\n    function runeCount(string memory s) internal pure returns (uint256 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if mload(s) {\n                mstore(0x00, div(not(0), 255))\n                mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)\n                let o := add(s, 0x20)\n                let end := add(o, mload(s))\n                for { result := 1 } 1 { result := add(result, 1) } {\n                    o := add(o, byte(0, mload(shr(250, mload(o)))))\n                    if iszero(lt(o, end)) { break }\n                }\n            }\n        }\n    }\n\n    /// @dev Returns if this string is a 7-bit ASCII string.\n    /// (i.e. all characters codes are in [0..127])\n    function is7BitASCII(string memory s) internal pure returns (bool result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let mask := shl(7, div(not(0), 255))\n            result := 1\n            let n := mload(s)\n            if n {\n                let o := add(s, 0x20)\n                let end := add(o, n)\n                let last := mload(end)\n                mstore(end, 0)\n                for {} 1 {} {\n                    if and(mask, mload(o)) {\n                        result := 0\n                        break\n                    }\n                    o := add(o, 0x20)\n                    if iszero(lt(o, end)) { break }\n                }\n                mstore(end, last)\n            }\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                   BYTE STRING OPERATIONS                   */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    // For performance and bytecode compactness, byte string operations are restricted\n    // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.\n    // Usage of byte string operations on charsets with runes spanning two or more bytes\n    // can lead to undefined behavior.\n\n    /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.\n    function replace(string memory subject, string memory search, string memory replacement)\n        internal\n        pure\n        returns (string memory result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let subjectLength := mload(subject)\n            let searchLength := mload(search)\n            let replacementLength := mload(replacement)\n\n            subject := add(subject, 0x20)\n            search := add(search, 0x20)\n            replacement := add(replacement, 0x20)\n            result := add(mload(0x40), 0x20)\n\n            let subjectEnd := add(subject, subjectLength)\n            if iszero(gt(searchLength, subjectLength)) {\n                let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)\n                let h := 0\n                if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n                let s := mload(search)\n                for {} 1 {} {\n                    let t := mload(subject)\n                    // Whether the first `searchLength % 32` bytes of\n                    // `subject` and `search` matches.\n                    if iszero(shr(m, xor(t, s))) {\n                        if h {\n                            if iszero(eq(keccak256(subject, searchLength), h)) {\n                                mstore(result, t)\n                                result := add(result, 1)\n                                subject := add(subject, 1)\n                                if iszero(lt(subject, subjectSearchEnd)) { break }\n                                continue\n                            }\n                        }\n                        // Copy the `replacement` one word at a time.\n                        for { let o := 0 } 1 {} {\n                            mstore(add(result, o), mload(add(replacement, o)))\n                            o := add(o, 0x20)\n                            if iszero(lt(o, replacementLength)) { break }\n                        }\n                        result := add(result, replacementLength)\n                        subject := add(subject, searchLength)\n                        if searchLength {\n                            if iszero(lt(subject, subjectSearchEnd)) { break }\n                            continue\n                        }\n                    }\n                    mstore(result, t)\n                    result := add(result, 1)\n                    subject := add(subject, 1)\n                    if iszero(lt(subject, subjectSearchEnd)) { break }\n                }\n            }\n\n            let resultRemainder := result\n            result := add(mload(0x40), 0x20)\n            let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))\n            // Copy the rest of the string one word at a time.\n            for {} lt(subject, subjectEnd) {} {\n                mstore(resultRemainder, mload(subject))\n                resultRemainder := add(resultRemainder, 0x20)\n                subject := add(subject, 0x20)\n            }\n            result := sub(result, 0x20)\n            let last := add(add(result, 0x20), k) // Zeroize the slot after the string.\n            mstore(last, 0)\n            mstore(0x40, add(last, 0x20)) // Allocate the memory.\n            mstore(result, k) // Store the length.\n        }\n    }\n\n    /// @dev Returns the byte index of the first location of `search` in `subject`,\n    /// searching from left to right, starting from `from`.\n    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n    function indexOf(string memory subject, string memory search, uint256 from)\n        internal\n        pure\n        returns (uint256 result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            for { let subjectLength := mload(subject) } 1 {} {\n                if iszero(mload(search)) {\n                    if iszero(gt(from, subjectLength)) {\n                        result := from\n                        break\n                    }\n                    result := subjectLength\n                    break\n                }\n                let searchLength := mload(search)\n                let subjectStart := add(subject, 0x20)\n\n                result := not(0) // Initialize to `NOT_FOUND`.\n\n                subject := add(subjectStart, from)\n                let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)\n\n                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n                let s := mload(add(search, 0x20))\n\n                if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }\n\n                if iszero(lt(searchLength, 0x20)) {\n                    for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n                        if iszero(shr(m, xor(mload(subject), s))) {\n                            if eq(keccak256(subject, searchLength), h) {\n                                result := sub(subject, subjectStart)\n                                break\n                            }\n                        }\n                        subject := add(subject, 1)\n                        if iszero(lt(subject, end)) { break }\n                    }\n                    break\n                }\n                for {} 1 {} {\n                    if iszero(shr(m, xor(mload(subject), s))) {\n                        result := sub(subject, subjectStart)\n                        break\n                    }\n                    subject := add(subject, 1)\n                    if iszero(lt(subject, end)) { break }\n                }\n                break\n            }\n        }\n    }\n\n    /// @dev Returns the byte index of the first location of `search` in `subject`,\n    /// searching from left to right.\n    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n    function indexOf(string memory subject, string memory search)\n        internal\n        pure\n        returns (uint256 result)\n    {\n        result = indexOf(subject, search, 0);\n    }\n\n    /// @dev Returns the byte index of the first location of `search` in `subject`,\n    /// searching from right to left, starting from `from`.\n    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n    function lastIndexOf(string memory subject, string memory search, uint256 from)\n        internal\n        pure\n        returns (uint256 result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            for {} 1 {} {\n                result := not(0) // Initialize to `NOT_FOUND`.\n                let searchLength := mload(search)\n                if gt(searchLength, mload(subject)) { break }\n                let w := result\n\n                let fromMax := sub(mload(subject), searchLength)\n                if iszero(gt(fromMax, from)) { from := fromMax }\n\n                let end := add(add(subject, 0x20), w)\n                subject := add(add(subject, 0x20), from)\n                if iszero(gt(subject, end)) { break }\n                // As this function is not too often used,\n                // we shall simply use keccak256 for smaller bytecode size.\n                for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n                    if eq(keccak256(subject, searchLength), h) {\n                        result := sub(subject, add(end, 1))\n                        break\n                    }\n                    subject := add(subject, w) // `sub(subject, 1)`.\n                    if iszero(gt(subject, end)) { break }\n                }\n                break\n            }\n        }\n    }\n\n    /// @dev Returns the byte index of the first location of `search` in `subject`,\n    /// searching from right to left.\n    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n    function lastIndexOf(string memory subject, string memory search)\n        internal\n        pure\n        returns (uint256 result)\n    {\n        result = lastIndexOf(subject, search, uint256(int256(-1)));\n    }\n\n    /// @dev Returns true if `search` is found in `subject`, false otherwise.\n    function contains(string memory subject, string memory search) internal pure returns (bool) {\n        return indexOf(subject, search) != NOT_FOUND;\n    }\n\n    /// @dev Returns whether `subject` starts with `search`.\n    function startsWith(string memory subject, string memory search)\n        internal\n        pure\n        returns (bool result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let searchLength := mload(search)\n            // Just using keccak256 directly is actually cheaper.\n            // forgefmt: disable-next-item\n            result := and(\n                iszero(gt(searchLength, mload(subject))),\n                eq(\n                    keccak256(add(subject, 0x20), searchLength),\n                    keccak256(add(search, 0x20), searchLength)\n                )\n            )\n        }\n    }\n\n    /// @dev Returns whether `subject` ends with `search`.\n    function endsWith(string memory subject, string memory search)\n        internal\n        pure\n        returns (bool result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let searchLength := mload(search)\n            let subjectLength := mload(subject)\n            // Whether `search` is not longer than `subject`.\n            let withinRange := iszero(gt(searchLength, subjectLength))\n            // Just using keccak256 directly is actually cheaper.\n            // forgefmt: disable-next-item\n            result := and(\n                withinRange,\n                eq(\n                    keccak256(\n                        // `subject + 0x20 + max(subjectLength - searchLength, 0)`.\n                        add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),\n                        searchLength\n                    ),\n                    keccak256(add(search, 0x20), searchLength)\n                )\n            )\n        }\n    }\n\n    /// @dev Returns `subject` repeated `times`.\n    function repeat(string memory subject, uint256 times)\n        internal\n        pure\n        returns (string memory result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let subjectLength := mload(subject)\n            if iszero(or(iszero(times), iszero(subjectLength))) {\n                subject := add(subject, 0x20)\n                result := mload(0x40)\n                let output := add(result, 0x20)\n                for {} 1 {} {\n                    // Copy the `subject` one word at a time.\n                    for { let o := 0 } 1 {} {\n                        mstore(add(output, o), mload(add(subject, o)))\n                        o := add(o, 0x20)\n                        if iszero(lt(o, subjectLength)) { break }\n                    }\n                    output := add(output, subjectLength)\n                    times := sub(times, 1)\n                    if iszero(times) { break }\n                }\n                mstore(output, 0) // Zeroize the slot after the string.\n                let resultLength := sub(output, add(result, 0x20))\n                mstore(result, resultLength) // Store the length.\n                // Allocate the memory.\n                mstore(0x40, add(result, add(resultLength, 0x20)))\n            }\n        }\n    }\n\n    /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).\n    /// `start` and `end` are byte offsets.\n    function slice(string memory subject, uint256 start, uint256 end)\n        internal\n        pure\n        returns (string memory result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let subjectLength := mload(subject)\n            if iszero(gt(subjectLength, end)) { end := subjectLength }\n            if iszero(gt(subjectLength, start)) { start := subjectLength }\n            if lt(start, end) {\n                result := mload(0x40)\n                let resultLength := sub(end, start)\n                mstore(result, resultLength)\n                subject := add(subject, start)\n                let w := not(0x1f)\n                // Copy the `subject` one word at a time, backwards.\n                for { let o := and(add(resultLength, 0x1f), w) } 1 {} {\n                    mstore(add(result, o), mload(add(subject, o)))\n                    o := add(o, w) // `sub(o, 0x20)`.\n                    if iszero(o) { break }\n                }\n                // Zeroize the slot after the string.\n                mstore(add(add(result, 0x20), resultLength), 0)\n                // Allocate memory for the length and the bytes,\n                // rounded up to a multiple of 32.\n                mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))\n            }\n        }\n    }\n\n    /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.\n    /// `start` is a byte offset.\n    function slice(string memory subject, uint256 start)\n        internal\n        pure\n        returns (string memory result)\n    {\n        result = slice(subject, start, uint256(int256(-1)));\n    }\n\n    /// @dev Returns all the indices of `search` in `subject`.\n    /// The indices are byte offsets.\n    function indicesOf(string memory subject, string memory search)\n        internal\n        pure\n        returns (uint256[] memory result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let subjectLength := mload(subject)\n            let searchLength := mload(search)\n\n            if iszero(gt(searchLength, subjectLength)) {\n                subject := add(subject, 0x20)\n                search := add(search, 0x20)\n                result := add(mload(0x40), 0x20)\n\n                let subjectStart := subject\n                let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)\n                let h := 0\n                if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n                let s := mload(search)\n                for {} 1 {} {\n                    let t := mload(subject)\n                    // Whether the first `searchLength % 32` bytes of\n                    // `subject` and `search` matches.\n                    if iszero(shr(m, xor(t, s))) {\n                        if h {\n                            if iszero(eq(keccak256(subject, searchLength), h)) {\n                                subject := add(subject, 1)\n                                if iszero(lt(subject, subjectSearchEnd)) { break }\n                                continue\n                            }\n                        }\n                        // Append to `result`.\n                        mstore(result, sub(subject, subjectStart))\n                        result := add(result, 0x20)\n                        // Advance `subject` by `searchLength`.\n                        subject := add(subject, searchLength)\n                        if searchLength {\n                            if iszero(lt(subject, subjectSearchEnd)) { break }\n                            continue\n                        }\n                    }\n                    subject := add(subject, 1)\n                    if iszero(lt(subject, subjectSearchEnd)) { break }\n                }\n                let resultEnd := result\n                // Assign `result` to the free memory pointer.\n                result := mload(0x40)\n                // Store the length of `result`.\n                mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))\n                // Allocate memory for result.\n                // We allocate one more word, so this array can be recycled for {split}.\n                mstore(0x40, add(resultEnd, 0x20))\n            }\n        }\n    }\n\n    /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.\n    function split(string memory subject, string memory delimiter)\n        internal\n        pure\n        returns (string[] memory result)\n    {\n        uint256[] memory indices = indicesOf(subject, delimiter);\n        /// @solidity memory-safe-assembly\n        assembly {\n            let w := not(0x1f)\n            let indexPtr := add(indices, 0x20)\n            let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))\n            mstore(add(indicesEnd, w), mload(subject))\n            mstore(indices, add(mload(indices), 1))\n            let prevIndex := 0\n            for {} 1 {} {\n                let index := mload(indexPtr)\n                mstore(indexPtr, 0x60)\n                if iszero(eq(index, prevIndex)) {\n                    let element := mload(0x40)\n                    let elementLength := sub(index, prevIndex)\n                    mstore(element, elementLength)\n                    // Copy the `subject` one word at a time, backwards.\n                    for { let o := and(add(elementLength, 0x1f), w) } 1 {} {\n                        mstore(add(element, o), mload(add(add(subject, prevIndex), o)))\n                        o := add(o, w) // `sub(o, 0x20)`.\n                        if iszero(o) { break }\n                    }\n                    // Zeroize the slot after the string.\n                    mstore(add(add(element, 0x20), elementLength), 0)\n                    // Allocate memory for the length and the bytes,\n                    // rounded up to a multiple of 32.\n                    mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))\n                    // Store the `element` into the array.\n                    mstore(indexPtr, element)\n                }\n                prevIndex := add(index, mload(delimiter))\n                indexPtr := add(indexPtr, 0x20)\n                if iszero(lt(indexPtr, indicesEnd)) { break }\n            }\n            result := indices\n            if iszero(mload(delimiter)) {\n                result := add(indices, 0x20)\n                mstore(result, sub(mload(indices), 2))\n            }\n        }\n    }\n\n    /// @dev Returns a concatenated string of `a` and `b`.\n    /// Cheaper than `string.concat()` and does not de-align the free memory pointer.\n    function concat(string memory a, string memory b)\n        internal\n        pure\n        returns (string memory result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let w := not(0x1f)\n            result := mload(0x40)\n            let aLength := mload(a)\n            // Copy `a` one word at a time, backwards.\n            for { let o := and(add(aLength, 0x20), w) } 1 {} {\n                mstore(add(result, o), mload(add(a, o)))\n                o := add(o, w) // `sub(o, 0x20)`.\n                if iszero(o) { break }\n            }\n            let bLength := mload(b)\n            let output := add(result, aLength)\n            // Copy `b` one word at a time, backwards.\n            for { let o := and(add(bLength, 0x20), w) } 1 {} {\n                mstore(add(output, o), mload(add(b, o)))\n                o := add(o, w) // `sub(o, 0x20)`.\n                if iszero(o) { break }\n            }\n            let totalLength := add(aLength, bLength)\n            let last := add(add(result, 0x20), totalLength)\n            // Zeroize the slot after the string.\n            mstore(last, 0)\n            // Stores the length.\n            mstore(result, totalLength)\n            // Allocate memory for the length and the bytes,\n            // rounded up to a multiple of 32.\n            mstore(0x40, and(add(last, 0x1f), w))\n        }\n    }\n\n    /// @dev Returns a copy of the string in either lowercase or UPPERCASE.\n    /// WARNING! This function is only compatible with 7-bit ASCII strings.\n    function toCase(string memory subject, bool toUpper)\n        internal\n        pure\n        returns (string memory result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let length := mload(subject)\n            if length {\n                result := add(mload(0x40), 0x20)\n                subject := add(subject, 1)\n                let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)\n                let w := not(0)\n                for { let o := length } 1 {} {\n                    o := add(o, w)\n                    let b := and(0xff, mload(add(subject, o)))\n                    mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))\n                    if iszero(o) { break }\n                }\n                result := mload(0x40)\n                mstore(result, length) // Store the length.\n                let last := add(add(result, 0x20), length)\n                mstore(last, 0) // Zeroize the slot after the string.\n                mstore(0x40, add(last, 0x20)) // Allocate the memory.\n            }\n        }\n    }\n\n    /// @dev Returns a string from a small bytes32 string.\n    /// `s` must be null-terminated, or behavior will be undefined.\n    function fromSmallString(bytes32 s) internal pure returns (string memory result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := mload(0x40)\n            let n := 0\n            for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\\0'.\n            mstore(result, n)\n            let o := add(result, 0x20)\n            mstore(o, s)\n            mstore(add(o, n), 0)\n            mstore(0x40, add(result, 0x40))\n        }\n    }\n\n    /// @dev Returns the small string, with all bytes after the first null byte zeroized.\n    function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\\0'.\n            mstore(0x00, s)\n            mstore(result, 0x00)\n            result := mload(0x00)\n        }\n    }\n\n    /// @dev Returns the string as a normalized null-terminated small string.\n    function toSmallString(string memory s) internal pure returns (bytes32 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := mload(s)\n            if iszero(lt(result, 33)) {\n                mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.\n                revert(0x1c, 0x04)\n            }\n            result := shl(shl(3, sub(32, result)), mload(add(s, result)))\n        }\n    }\n\n    /// @dev Returns a lowercased copy of the string.\n    /// WARNING! This function is only compatible with 7-bit ASCII strings.\n    function lower(string memory subject) internal pure returns (string memory result) {\n        result = toCase(subject, false);\n    }\n\n    /// @dev Returns an UPPERCASED copy of the string.\n    /// WARNING! This function is only compatible with 7-bit ASCII strings.\n    function upper(string memory subject) internal pure returns (string memory result) {\n        result = toCase(subject, true);\n    }\n\n    /// @dev Escapes the string to be used within HTML tags.\n    function escapeHTML(string memory s) internal pure returns (string memory result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let end := add(s, mload(s))\n            result := add(mload(0x40), 0x20)\n            // Store the bytes of the packed offsets and strides into the scratch space.\n            // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.\n            mstore(0x1f, 0x900094)\n            mstore(0x08, 0xc0000000a6ab)\n            // Store \"&quot;&amp;&#39;&lt;&gt;\" into the scratch space.\n            mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))\n            for {} iszero(eq(s, end)) {} {\n                s := add(s, 1)\n                let c := and(mload(s), 0xff)\n                // Not in `[\"\\\"\",\"'\",\"&\",\"<\",\">\"]`.\n                if iszero(and(shl(c, 1), 0x500000c400000000)) {\n                    mstore8(result, c)\n                    result := add(result, 1)\n                    continue\n                }\n                let t := shr(248, mload(c))\n                mstore(result, mload(and(t, 0x1f)))\n                result := add(result, shr(5, t))\n            }\n            let last := result\n            mstore(last, 0) // Zeroize the slot after the string.\n            result := mload(0x40)\n            mstore(result, sub(last, add(result, 0x20))) // Store the length.\n            mstore(0x40, add(last, 0x20)) // Allocate the memory.\n        }\n    }\n\n    /// @dev Escapes the string to be used within double-quotes in a JSON.\n    /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.\n    function escapeJSON(string memory s, bool addDoubleQuotes)\n        internal\n        pure\n        returns (string memory result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let end := add(s, mload(s))\n            result := add(mload(0x40), 0x20)\n            if addDoubleQuotes {\n                mstore8(result, 34)\n                result := add(1, result)\n            }\n            // Store \"\\\\u0000\" in scratch space.\n            // Store \"0123456789abcdef\" in scratch space.\n            // Also, store `{0x08:\"b\", 0x09:\"t\", 0x0a:\"n\", 0x0c:\"f\", 0x0d:\"r\"}`.\n            // into the scratch space.\n            mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)\n            // Bitmask for detecting `[\"\\\"\",\"\\\\\"]`.\n            let e := or(shl(0x22, 1), shl(0x5c, 1))\n            for {} iszero(eq(s, end)) {} {\n                s := add(s, 1)\n                let c := and(mload(s), 0xff)\n                if iszero(lt(c, 0x20)) {\n                    if iszero(and(shl(c, 1), e)) {\n                        // Not in `[\"\\\"\",\"\\\\\"]`.\n                        mstore8(result, c)\n                        result := add(result, 1)\n                        continue\n                    }\n                    mstore8(result, 0x5c) // \"\\\\\".\n                    mstore8(add(result, 1), c)\n                    result := add(result, 2)\n                    continue\n                }\n                if iszero(and(shl(c, 1), 0x3700)) {\n                    // Not in `[\"\\b\",\"\\t\",\"\\n\",\"\\f\",\"\\d\"]`.\n                    mstore8(0x1d, mload(shr(4, c))) // Hex value.\n                    mstore8(0x1e, mload(and(c, 15))) // Hex value.\n                    mstore(result, mload(0x19)) // \"\\\\u00XX\".\n                    result := add(result, 6)\n                    continue\n                }\n                mstore8(result, 0x5c) // \"\\\\\".\n                mstore8(add(result, 1), mload(add(c, 8)))\n                result := add(result, 2)\n            }\n            if addDoubleQuotes {\n                mstore8(result, 34)\n                result := add(1, result)\n            }\n            let last := result\n            mstore(last, 0) // Zeroize the slot after the string.\n            result := mload(0x40)\n            mstore(result, sub(last, add(result, 0x20))) // Store the length.\n            mstore(0x40, add(last, 0x20)) // Allocate the memory.\n        }\n    }\n\n    /// @dev Escapes the string to be used within double-quotes in a JSON.\n    function escapeJSON(string memory s) internal pure returns (string memory result) {\n        result = escapeJSON(s, false);\n    }\n\n    /// @dev Returns whether `a` equals `b`.\n    function eq(string memory a, string memory b) internal pure returns (bool result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))\n        }\n    }\n\n    /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.\n    function eqs(string memory a, bytes32 b) internal pure returns (bool result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // These should be evaluated on compile time, as far as possible.\n            let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.\n            let x := not(or(m, or(b, add(m, and(b, m)))))\n            let r := shl(7, iszero(iszero(shr(128, x))))\n            r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))\n            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n            r := or(r, shl(4, lt(0xffff, shr(r, x))))\n            r := or(r, shl(3, lt(0xff, shr(r, x))))\n            // forgefmt: disable-next-item\n            result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),\n                xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))\n        }\n    }\n\n    /// @dev Packs a single string with its length into a single word.\n    /// Returns `bytes32(0)` if the length is zero or greater than 31.\n    function packOne(string memory a) internal pure returns (bytes32 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // We don't need to zero right pad the string,\n            // since this is our own custom non-standard packing scheme.\n            result :=\n                mul(\n                    // Load the length and the bytes.\n                    mload(add(a, 0x1f)),\n                    // `length != 0 && length < 32`. Abuses underflow.\n                    // Assumes that the length is valid and within the block gas limit.\n                    lt(sub(mload(a), 1), 0x1f)\n                )\n        }\n    }\n\n    /// @dev Unpacks a string packed using {packOne}.\n    /// Returns the empty string if `packed` is `bytes32(0)`.\n    /// If `packed` is not an output of {packOne}, the output behavior is undefined.\n    function unpackOne(bytes32 packed) internal pure returns (string memory result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Grab the free memory pointer.\n            result := mload(0x40)\n            // Allocate 2 words (1 for the length, 1 for the bytes).\n            mstore(0x40, add(result, 0x40))\n            // Zeroize the length slot.\n            mstore(result, 0)\n            // Store the length and bytes.\n            mstore(add(result, 0x1f), packed)\n            // Right pad with zeroes.\n            mstore(add(add(result, 0x20), mload(result)), 0)\n        }\n    }\n\n    /// @dev Packs two strings with their lengths into a single word.\n    /// Returns `bytes32(0)` if combined length is zero or greater than 30.\n    function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let aLength := mload(a)\n            // We don't need to zero right pad the strings,\n            // since this is our own custom non-standard packing scheme.\n            result :=\n                mul(\n                    // Load the length and the bytes of `a` and `b`.\n                    or(\n                        shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),\n                        mload(sub(add(b, 0x1e), aLength))\n                    ),\n                    // `totalLength != 0 && totalLength < 31`. Abuses underflow.\n                    // Assumes that the lengths are valid and within the block gas limit.\n                    lt(sub(add(aLength, mload(b)), 1), 0x1e)\n                )\n        }\n    }\n\n    /// @dev Unpacks strings packed using {packTwo}.\n    /// Returns the empty strings if `packed` is `bytes32(0)`.\n    /// If `packed` is not an output of {packTwo}, the output behavior is undefined.\n    function unpackTwo(bytes32 packed)\n        internal\n        pure\n        returns (string memory resultA, string memory resultB)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Grab the free memory pointer.\n            resultA := mload(0x40)\n            resultB := add(resultA, 0x40)\n            // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.\n            mstore(0x40, add(resultB, 0x40))\n            // Zeroize the length slots.\n            mstore(resultA, 0)\n            mstore(resultB, 0)\n            // Store the lengths and bytes.\n            mstore(add(resultA, 0x1f), packed)\n            mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))\n            // Right pad with zeroes.\n            mstore(add(add(resultA, 0x20), mload(resultA)), 0)\n            mstore(add(add(resultB, 0x20), mload(resultB)), 0)\n        }\n    }\n\n    /// @dev Directly returns `a` without copying.\n    function directReturn(string memory a) internal pure {\n        assembly {\n            // Assumes that the string does not start from the scratch space.\n            let retStart := sub(a, 0x20)\n            let retSize := add(mload(a), 0x40)\n            // Right pad with zeroes. Just in case the string is produced\n            // by a method that doesn't zero right pad.\n            mstore(add(retStart, retSize), 0)\n            // Store the return offset.\n            mstore(retStart, 0x20)\n            // End the transaction, returning the string.\n            return(retStart, retSize)\n        }\n    }\n}\n"
      },
      "lib/solady/src/utils/SafeTransferLib.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)\n///\n/// @dev Note:\n/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.\n/// - For ERC20s, this implementation won't check that a token has code,\n///   responsibility is delegated to the caller.\nlibrary SafeTransferLib {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       CUSTOM ERRORS                        */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The ETH transfer has failed.\n    error ETHTransferFailed();\n\n    /// @dev The ERC20 `transferFrom` has failed.\n    error TransferFromFailed();\n\n    /// @dev The ERC20 `transfer` has failed.\n    error TransferFailed();\n\n    /// @dev The ERC20 `approve` has failed.\n    error ApproveFailed();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         CONSTANTS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.\n    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;\n\n    /// @dev Suggested gas stipend for contract receiving ETH to perform a few\n    /// storage reads and writes, but low enough to prevent griefing.\n    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       ETH OPERATIONS                       */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.\n    //\n    // The regular variants:\n    // - Forwards all remaining gas to the target.\n    // - Reverts if the target reverts.\n    // - Reverts if the current contract has insufficient balance.\n    //\n    // The force variants:\n    // - Forwards with an optional gas stipend\n    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).\n    // - If the target reverts, or if the gas stipend is exhausted,\n    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.\n    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.\n    // - Reverts if the current contract has insufficient balance.\n    //\n    // The try variants:\n    // - Forwards with a mandatory gas stipend.\n    // - Instead of reverting, returns whether the transfer succeeded.\n\n    /// @dev Sends `amount` (in wei) ETH to `to`.\n    function safeTransferETH(address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n\n    /// @dev Sends all the ETH in the current contract to `to`.\n    function safeTransferAllETH(address to) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Transfer all the ETH and check if it succeeded or not.\n            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n\n    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.\n    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if lt(selfbalance(), amount) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.\n    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.\n    function forceSafeTransferETH(address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if lt(selfbalance(), amount) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.\n    function forceSafeTransferAllETH(address to) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // forgefmt: disable-next-item\n            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.\n    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)\n        internal\n        returns (bool success)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)\n        }\n    }\n\n    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.\n    function trySafeTransferAllETH(address to, uint256 gasStipend)\n        internal\n        returns (bool success)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                      ERC20 OPERATIONS                      */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.\n    /// Reverts upon failure.\n    ///\n    /// The `from` account must have at least `amount` approved for\n    /// the current contract to manage.\n    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40) // Cache the free memory pointer.\n            mstore(0x60, amount) // Store the `amount` argument.\n            mstore(0x40, to) // Store the `to` argument.\n            mstore(0x2c, shl(96, from)) // Store the `from` argument.\n            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x60, 0) // Restore the zero slot to zero.\n            mstore(0x40, m) // Restore the free memory pointer.\n        }\n    }\n\n    /// @dev Sends all of ERC20 `token` from `from` to `to`.\n    /// Reverts upon failure.\n    ///\n    /// The `from` account must have their entire balance approved for\n    /// the current contract to manage.\n    function safeTransferAllFrom(address token, address from, address to)\n        internal\n        returns (uint256 amount)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40) // Cache the free memory pointer.\n            mstore(0x40, to) // Store the `to` argument.\n            mstore(0x2c, shl(96, from)) // Store the `from` argument.\n            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.\n            // Read the balance, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.\n            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x60, 0) // Restore the zero slot to zero.\n            mstore(0x40, m) // Restore the free memory pointer.\n        }\n    }\n\n    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.\n    /// Reverts upon failure.\n    function safeTransfer(address token, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, to) // Store the `to` argument.\n            mstore(0x34, amount) // Store the `amount` argument.\n            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Sends all of ERC20 `token` from the current contract to `to`.\n    /// Reverts upon failure.\n    function safeTransferAll(address token, address to) internal returns (uint256 amount) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.\n            mstore(0x20, address()) // Store the address of the current contract.\n            // Read the balance, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x14, to) // Store the `to` argument.\n            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.\n            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.\n    /// Reverts upon failure.\n    function safeApprove(address token, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, to) // Store the `to` argument.\n            mstore(0x34, amount) // Store the `amount` argument.\n            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n            // Perform the approval, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.\n    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,\n    /// then retries the approval again (some tokens, e.g. USDT, requires this).\n    /// Reverts upon failure.\n    function safeApproveWithRetry(address token, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, to) // Store the `to` argument.\n            mstore(0x34, amount) // Store the `amount` argument.\n            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n            // Perform the approval, retrying upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x34, 0) // Store 0 for the `amount`.\n                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.\n                mstore(0x34, amount) // Store back the original `amount`.\n                // Retry the approval, reverting upon failure.\n                if iszero(\n                    and(\n                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                    )\n                ) {\n                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.\n                    revert(0x1c, 0x04)\n                }\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Returns the amount of ERC20 `token` owned by `account`.\n    /// Returns zero if the `token` does not exist.\n    function balanceOf(address token, address account) internal view returns (uint256 amount) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, account) // Store the `account` argument.\n            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.\n            amount :=\n                mul(\n                    mload(0x20),\n                    and( // The arguments of `and` are evaluated from right to left.\n                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)\n                    )\n                )\n        }\n    }\n}\n"
      },
      "lib/solady/src/utils/LibBitmap.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {LibBit} from \"./LibBit.sol\";\n\n/// @notice Library for storage of packed unsigned booleans.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol)\n/// @author Modified from Solidity-Bits (https://github.com/estarriolvetch/solidity-bits/blob/main/contracts/BitMaps.sol)\nlibrary LibBitmap {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         CONSTANTS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The constant returned when a bitmap scan does not find a result.\n    uint256 internal constant NOT_FOUND = type(uint256).max;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                          STRUCTS                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev A bitmap in storage.\n    struct Bitmap {\n        mapping(uint256 => uint256) map;\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         OPERATIONS                         */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Returns the boolean value of the bit at `index` in `bitmap`.\n    function get(Bitmap storage bitmap, uint256 index) internal view returns (bool isSet) {\n        // It is better to set `isSet` to either 0 or 1, than zero vs non-zero.\n        // Both cost the same amount of gas, but the former allows the returned value\n        // to be reused without cleaning the upper bits.\n        uint256 b = (bitmap.map[index >> 8] >> (index & 0xff)) & 1;\n        /// @solidity memory-safe-assembly\n        assembly {\n            isSet := b\n        }\n    }\n\n    /// @dev Updates the bit at `index` in `bitmap` to true.\n    function set(Bitmap storage bitmap, uint256 index) internal {\n        bitmap.map[index >> 8] |= (1 << (index & 0xff));\n    }\n\n    /// @dev Updates the bit at `index` in `bitmap` to false.\n    function unset(Bitmap storage bitmap, uint256 index) internal {\n        bitmap.map[index >> 8] &= ~(1 << (index & 0xff));\n    }\n\n    /// @dev Flips the bit at `index` in `bitmap`.\n    /// Returns the boolean result of the flipped bit.\n    function toggle(Bitmap storage bitmap, uint256 index) internal returns (bool newIsSet) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x20, bitmap.slot)\n            mstore(0x00, shr(8, index))\n            let storageSlot := keccak256(0x00, 0x40)\n            let shift := and(index, 0xff)\n            let storageValue := xor(sload(storageSlot), shl(shift, 1))\n            // It makes sense to return the `newIsSet`,\n            // as it allow us to skip an additional warm `sload`,\n            // and it costs minimal gas (about 15),\n            // which may be optimized away if the returned value is unused.\n            newIsSet := and(1, shr(shift, storageValue))\n            sstore(storageSlot, storageValue)\n        }\n    }\n\n    /// @dev Updates the bit at `index` in `bitmap` to `shouldSet`.\n    function setTo(Bitmap storage bitmap, uint256 index, bool shouldSet) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x20, bitmap.slot)\n            mstore(0x00, shr(8, index))\n            let storageSlot := keccak256(0x00, 0x40)\n            let storageValue := sload(storageSlot)\n            let shift := and(index, 0xff)\n            sstore(\n                storageSlot,\n                // Unsets the bit at `shift` via `and`, then sets its new value via `or`.\n                or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet))))\n            )\n        }\n    }\n\n    /// @dev Consecutively sets `amount` of bits starting from the bit at `start`.\n    function setBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let max := not(0)\n            let shift := and(start, 0xff)\n            mstore(0x20, bitmap.slot)\n            mstore(0x00, shr(8, start))\n            if iszero(lt(add(shift, amount), 257)) {\n                let storageSlot := keccak256(0x00, 0x40)\n                sstore(storageSlot, or(sload(storageSlot), shl(shift, max)))\n                let bucket := add(mload(0x00), 1)\n                let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))\n                amount := and(add(amount, shift), 0xff)\n                shift := 0\n                for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {\n                    mstore(0x00, bucket)\n                    sstore(keccak256(0x00, 0x40), max)\n                }\n                mstore(0x00, bucket)\n            }\n            let storageSlot := keccak256(0x00, 0x40)\n            sstore(storageSlot, or(sload(storageSlot), shl(shift, shr(sub(256, amount), max))))\n        }\n    }\n\n    /// @dev Consecutively unsets `amount` of bits starting from the bit at `start`.\n    function unsetBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let shift := and(start, 0xff)\n            mstore(0x20, bitmap.slot)\n            mstore(0x00, shr(8, start))\n            if iszero(lt(add(shift, amount), 257)) {\n                let storageSlot := keccak256(0x00, 0x40)\n                sstore(storageSlot, and(sload(storageSlot), not(shl(shift, not(0)))))\n                let bucket := add(mload(0x00), 1)\n                let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))\n                amount := and(add(amount, shift), 0xff)\n                shift := 0\n                for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {\n                    mstore(0x00, bucket)\n                    sstore(keccak256(0x00, 0x40), 0)\n                }\n                mstore(0x00, bucket)\n            }\n            let storageSlot := keccak256(0x00, 0x40)\n            sstore(\n                storageSlot, and(sload(storageSlot), not(shl(shift, shr(sub(256, amount), not(0)))))\n            )\n        }\n    }\n\n    /// @dev Returns number of set bits within a range by\n    /// scanning `amount` of bits starting from the bit at `start`.\n    function popCount(Bitmap storage bitmap, uint256 start, uint256 amount)\n        internal\n        view\n        returns (uint256 count)\n    {\n        unchecked {\n            uint256 bucket = start >> 8;\n            uint256 shift = start & 0xff;\n            if (!(amount + shift < 257)) {\n                count = LibBit.popCount(bitmap.map[bucket] >> shift);\n                uint256 bucketEnd = bucket + ((amount + shift) >> 8);\n                amount = (amount + shift) & 0xff;\n                shift = 0;\n                for (++bucket; bucket != bucketEnd; ++bucket) {\n                    count += LibBit.popCount(bitmap.map[bucket]);\n                }\n            }\n            count += LibBit.popCount((bitmap.map[bucket] >> shift) << (256 - amount));\n        }\n    }\n\n    /// @dev Returns the index of the most significant set bit before the bit at `before`.\n    /// If no set bit is found, returns `NOT_FOUND`.\n    function findLastSet(Bitmap storage bitmap, uint256 before)\n        internal\n        view\n        returns (uint256 setBitIndex)\n    {\n        uint256 bucket;\n        uint256 bucketBits;\n        /// @solidity memory-safe-assembly\n        assembly {\n            setBitIndex := not(0)\n            bucket := shr(8, before)\n            mstore(0x00, bucket)\n            mstore(0x20, bitmap.slot)\n            let offset := and(0xff, not(before)) // `256 - (255 & before) - 1`.\n            bucketBits := shr(offset, shl(offset, sload(keccak256(0x00, 0x40))))\n            if iszero(or(bucketBits, iszero(bucket))) {\n                for {} 1 {} {\n                    bucket := add(bucket, setBitIndex) // `sub(bucket, 1)`.\n                    mstore(0x00, bucket)\n                    bucketBits := sload(keccak256(0x00, 0x40))\n                    if or(bucketBits, iszero(bucket)) { break }\n                }\n            }\n        }\n        if (bucketBits != 0) {\n            setBitIndex = (bucket << 8) | LibBit.fls(bucketBits);\n            /// @solidity memory-safe-assembly\n            assembly {\n                setBitIndex := or(setBitIndex, sub(0, gt(setBitIndex, before)))\n            }\n        }\n    }\n}\n"
      },
      "lib/solady/src/utils/LibBit.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for bit twiddling and boolean operations.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol)\n/// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html)\nlibrary LibBit {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                  BIT TWIDDLING OPERATIONS                  */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Find last set.\n    /// Returns the index of the most significant bit of `x`,\n    /// counting from the least significant bit position.\n    /// If `x` is zero, returns 256.\n    function fls(uint256 x) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x)))\n            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))\n            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n            r := or(r, shl(4, lt(0xffff, shr(r, x))))\n            r := or(r, shl(3, lt(0xff, shr(r, x))))\n            // forgefmt: disable-next-item\n            r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),\n                0x0706060506020504060203020504030106050205030304010505030400000000))\n        }\n    }\n\n    /// @dev Count leading zeros.\n    /// Returns the number of zeros preceding the most significant one bit.\n    /// If `x` is zero, returns 256.\n    function clz(uint256 x) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))\n            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))\n            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n            r := or(r, shl(4, lt(0xffff, shr(r, x))))\n            r := or(r, shl(3, lt(0xff, shr(r, x))))\n            // forgefmt: disable-next-item\n            r := add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),\n                0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x))\n        }\n    }\n\n    /// @dev Find first set.\n    /// Returns the index of the least significant bit of `x`,\n    /// counting from the least significant bit position.\n    /// If `x` is zero, returns 256.\n    /// Equivalent to `ctz` (count trailing zeros), which gives\n    /// the number of zeros following the least significant one bit.\n    function ffs(uint256 x) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Isolate the least significant bit.\n            let b := and(x, add(not(x), 1))\n\n            r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, b)))\n            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, b))))\n            r := or(r, shl(5, lt(0xffffffff, shr(r, b))))\n\n            // For the remaining 32 bits, use a De Bruijn lookup.\n            // forgefmt: disable-next-item\n            r := or(r, byte(and(div(0xd76453e0, shr(r, b)), 0x1f),\n                0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))\n        }\n    }\n\n    /// @dev Returns the number of set bits in `x`.\n    function popCount(uint256 x) internal pure returns (uint256 c) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let max := not(0)\n            let isMax := eq(x, max)\n            x := sub(x, and(shr(1, x), div(max, 3)))\n            x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5)))\n            x := and(add(x, shr(4, x)), div(max, 17))\n            c := or(shl(8, isMax), shr(248, mul(x, div(max, 255))))\n        }\n    }\n\n    /// @dev Returns whether `x` is a power of 2.\n    function isPo2(uint256 x) internal pure returns (bool result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to `x && !(x & (x - 1))`.\n            result := iszero(add(and(x, sub(x, 1)), iszero(x)))\n        }\n    }\n\n    /// @dev Returns `x` reversed at the bit level.\n    function reverseBits(uint256 x) internal pure returns (uint256 r) {\n        uint256 m0 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n        uint256 m1 = m0 ^ (m0 << 2);\n        uint256 m2 = m1 ^ (m1 << 1);\n        r = reverseBytes(x);\n        r = (m2 & (r >> 1)) | ((m2 & r) << 1);\n        r = (m1 & (r >> 2)) | ((m1 & r) << 2);\n        r = (m0 & (r >> 4)) | ((m0 & r) << 4);\n    }\n\n    /// @dev Returns `x` reversed at the byte level.\n    function reverseBytes(uint256 x) internal pure returns (uint256 r) {\n        unchecked {\n            // Computing masks on-the-fly reduces bytecode size by about 200 bytes.\n            uint256 m0 = 0x100000000000000000000000000000001 * (~toUint(x == 0) >> 192);\n            uint256 m1 = m0 ^ (m0 << 32);\n            uint256 m2 = m1 ^ (m1 << 16);\n            uint256 m3 = m2 ^ (m2 << 8);\n            r = (m3 & (x >> 8)) | ((m3 & x) << 8);\n            r = (m2 & (r >> 16)) | ((m2 & r) << 16);\n            r = (m1 & (r >> 32)) | ((m1 & r) << 32);\n            r = (m0 & (r >> 64)) | ((m0 & r) << 64);\n            r = (r >> 128) | (r << 128);\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                     BOOLEAN OPERATIONS                     */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    // A Solidity bool on the stack or memory is represented as a 256-bit word.\n    // Non-zero values are true, zero is false.\n    // A clean bool is either 0 (false) or 1 (true) under the hood.\n    // Usually, if not always, the bool result of a regular Solidity expression,\n    // or the argument of a public/external function will be a clean bool.\n    // You can usually use the raw variants for more performance.\n    // If uncertain, test (best with exact compiler settings).\n    // Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s).\n\n    /// @dev Returns `x & y`. Inputs must be clean.\n    function rawAnd(bool x, bool y) internal pure returns (bool z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := and(x, y)\n        }\n    }\n\n    /// @dev Returns `x & y`.\n    function and(bool x, bool y) internal pure returns (bool z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := and(iszero(iszero(x)), iszero(iszero(y)))\n        }\n    }\n\n    /// @dev Returns `x | y`. Inputs must be clean.\n    function rawOr(bool x, bool y) internal pure returns (bool z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := or(x, y)\n        }\n    }\n\n    /// @dev Returns `x | y`.\n    function or(bool x, bool y) internal pure returns (bool z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := or(iszero(iszero(x)), iszero(iszero(y)))\n        }\n    }\n\n    /// @dev Returns 1 if `b` is true, else 0. Input must be clean.\n    function rawToUint(bool b) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := b\n        }\n    }\n\n    /// @dev Returns 1 if `b` is true, else 0.\n    function toUint(bool b) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := iszero(iszero(b))\n        }\n    }\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "forge-std/=test/utils/forge-std/",
        "murky/=lib/murky/",
        "solady/=lib/solady/src/",
        "@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
        "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
        "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
        "forge-std/=lib/forge-std/src/",
        "murky/=lib/murky/",
        "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
        "openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/",
        "solady/=lib/solady/src/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 1000
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "viaIR": false,
      "libraries": {}
    }
  }}