creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/ERC404/ERC404TokenFactory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.23;\n\nimport {BaseFactory, IERC20, IUniswapV2Factory, IUniswapV2Router02} from \"../BaseFactory.sol\";\n\nimport {BaseERC404} from \"./BaseERC404.sol\";\n\n/// @title ERC404TokenFactory\n/// @notice A factory contract to create new non-ruggable ERC404 tokens\ncontract ERC404TokenFactory is BaseFactory {\n    // ============================================================================================\n    // Constructor\n    // ============================================================================================\n\n    constructor(\n        IERC20 _wnt,\n        IUniswapV2Router02 _univ2router,\n        IUniswapV2Factory _univ2factory,\n        address _treasury\n    ) BaseFactory(_wnt, _univ2router, _univ2factory, _treasury) {}\n\n    // ============================================================================================\n    // External Functions\n    // ============================================================================================\n\n    /// @notice Create a new ERC404 token, add liquidity and burn the LP tokens\n    /// @param _name The token name\n    /// @param _symbol The token symbol\n    /// @param _baseURI The base URI\n    /// @param _totalSupply The total supply\n    /// @param _tokenLiquidityThreshold_ The token liquidity threshold\n\n    /// @return The pair address and the token address\n    function createERC404(\n        string memory _name,\n        string memory _symbol,\n        string memory _baseURI,\n        uint96 _totalSupply,\n        uint256 _tokenLiquidityThreshold\n    ) external payable nonReentrant returns (address, address) {\n        require(_tokenLiquidityThreshold >= _totalSupply * 2/ 10000 && _tokenLiquidityThreshold <= _totalSupply / 100, \"tokenLiquidityThreshold must 0.02-1% of supply\");\n        BaseERC404 _token = new BaseERC404(\n            wnt,\n            univ2router,\n            treasury,\n            _name,\n            _symbol,\n            _baseURI,\n            _totalSupply,\n            _tokenLiquidityThreshold,\n            univ2factory\n        );\n        address _pair = _addLiquidityAndBurn(address(_token));\n        emit TokenCreated(address(_token), _name, _symbol, _totalSupply);\n\n        return (_pair, address(_token));\n    }\n}\n"
      },
      "src/BaseFactory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.23;\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport {Address} from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport {IUniswapV2Router02} from \"@uniswap-periphery/interfaces/IUniswapV2Router02.sol\";\nimport {IUniswapV2Factory} from \"@uniswap-core/interfaces/IUniswapV2Factory.sol\";\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/// @title BaseFactory\n/// @notice A base factory contract to create new non-ruggable ERC20/ERC404 tokens\nabstract contract BaseFactory is ReentrancyGuard {\n    using SafeERC20 for IERC20;\n    using Address for address payable;\n\n    address public immutable treasury;\n\n    IERC20 public immutable wnt;\n    IUniswapV2Router02 public immutable univ2router;\n    IUniswapV2Factory public immutable univ2factory;\n\n    uint256 public constant SWAP_TAX = 225; // 0.25%\n    uint256 public constant PRECISION = 10000;\n\n    // ============================================================================================\n    // Constructor\n    // ============================================================================================\n\n    constructor(\n        IERC20 _wnt,\n        IUniswapV2Router02 _univ2router,\n        IUniswapV2Factory _univ2factory,\n        address _treasury\n    ) {\n        if (_treasury == address(0)) revert InvalidAddress();\n\n        wnt = _wnt;\n        univ2router = _univ2router;\n        univ2factory = _univ2factory;\n\n        treasury = _treasury;\n\n        if (block.chainid == 252) {\n            // https://docs.frax.com/fraxtal/fraxtal-incentives/fraxtal-incentives-delegation#setting-delegations-for-smart-contracts\n            address _delegationRegistry = 0x4392dC16867D53DBFE227076606455634d4c2795;\n            _delegationRegistry.call(\n                abi.encodeWithSignature(\n                    \"setDelegationForSelf(address)\",\n                    _treasury\n                )\n            );\n            _delegationRegistry.call(\n                abi.encodeWithSignature(\"disableSelfManagingDelegations()\")\n            );\n        }\n    }\n\n    // ============================================================================================\n    // Internal Functions\n    // ============================================================================================\n\n    function _addLiquidityAndBurn(\n        address _token\n    ) internal returns (address _pair) {\n        if (msg.value == 0) revert InvalidAmount();\n\n        payable(address(wnt)).functionCallWithValue(\n            abi.encodeWithSignature(\"deposit()\"),\n            msg.value\n        );\n\n        uint256 _amountToken = IERC20(_token).balanceOf(address(this));\n        uint256 _amountWNT = wnt.balanceOf(address(this));\n        // slither-disable-next-line incorrect-equality\n        if (_amountToken == 0 || _amountWNT == 0) revert InvalidAmount();\n\n        _pair = univ2factory.getPair(_token, address(wnt));\n        (_token, address(wnt));\n\n        IERC20(_token).forceApprove(address(univ2router), _amountToken);\n        wnt.forceApprove(address(univ2router), _amountWNT);\n\n        uint256 _liquidity = 0;\n        (_amountToken, _amountWNT, _liquidity) = univ2router.addLiquidity(\n            _token, // tokenA\n            address(wnt), // tokenB\n            _amountToken, // amountADesired\n            _amountWNT, // amountBDesired\n            _amountToken, // amountAMin\n            _amountWNT, // amountBMin\n            address(0), // to\n            block.timestamp // deadline\n        );\n\n        emit AddLiquidityAndBurn(\n            _amountToken,\n            _amountWNT,\n            0,\n            _liquidity,\n            _pair\n        );\n    }\n\n    // ============================================================================================\n    // Events\n    // ============================================================================================\n\n    event AddLiquidityAndBurn(\n        uint256 amountToken,\n        uint256 amountWNT,\n        uint256 amountTax,\n        uint256 liquidity,\n        address pair\n    );\n    event TokenCreated(\n        address token,\n        string name,\n        string symbol,\n        uint256 totalSupply\n    );\n\n    // ============================================================================================\n    // Errors\n    // ============================================================================================\n\n    error InvalidAmount();\n    error InvalidAddress();\n}\n"
      },
      "src/ERC404/BaseERC404.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.23;\n\nimport {DN404} from \"@vectorized/DN404.sol\";\nimport {DN404Mirror} from \"@vectorized/DN404Mirror.sol\";\n\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\n\nimport {BaseToken, IUniswapV2Router02, IERC20} from \"../BaseToken.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {IUniswapV2Factory} from \"@uniswap-core/interfaces/IUniswapV2Factory.sol\";\n\n/// @title BaseERC404\n/// @notice A standard ERC404 token\ncontract BaseERC404 is DN404, BaseToken {\n    string private _name;\n    string private _symbol;\n    string private _baseURI;\n\n    IUniswapV2Router02 public router;\n\n    address public pair;\n    address tokenFactory;\n\n    uint256 private tokenLiquidityThreshold;\n    bool public isSwapping;\n\n    constructor(\n        IERC20 _wnt,\n        IUniswapV2Router02 _univ2router,\n        address _treasury,\n        string memory name_,\n        string memory symbol_,\n        string memory baseURI_,\n        uint96 _totalSupply,\n        uint256 _tokenLiquidityThreshold,\n        IUniswapV2Factory univ2factory\n    ) BaseToken(_wnt, _univ2router, _treasury) {\n        _name = name_;\n        _symbol = symbol_;\n        _baseURI = baseURI_;\n        _initializeDN404(\n            _totalSupply, // initialTokenSupply\n            msg.sender, // initialSupplyOwner, TokenFactory\n            address(new DN404Mirror(address(0))) // Mirror\n        );\n        tokenFactory = msg.sender;\n        pair = univ2factory.createPair(address(this), address(_wnt));\n        router = _univ2router;\n        tokenLiquidityThreshold = _tokenLiquidityThreshold;\n        _approve(address(this), address(router), type(uint256).max);\n        isSwapping = false;\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(\n        uint256 _tokenId\n    ) public view override returns (string memory _result) {\n        if (bytes(_baseURI).length != 0)\n            _result = string(\n                abi.encodePacked(_baseURI, Strings.toString(_tokenId))\n            );\n    }\n\n    function _transfer(\n        address from,\n        address to,\n        uint256 value\n    ) internal override {\n        require(value > 0, \"Transfer amount must be greater than zero\");\n\n        uint256 fee = 0;\n        if (to == pair || from == pair) {\n            if (!(to == address(this) || from == address(this))) {\n                if (from != tokenFactory) {\n                    fee = ((value * SWAP_TAX) / PRECISION);\n                    if (from != pair) {\n                        handle_fees();\n                    }\n                }\n            }\n        }\n        super._transfer(from, to, value - fee);\n        if (fee > 0) {\n            super._transfer(from, address(this), fee);\n        }\n    }\n\n    function handle_fees() private {\n        uint256 contractBalance = balanceOf(address(this));\n        if (contractBalance >= tokenLiquidityThreshold) {\n            swapTokensForETH(contractBalance);\n        }\n    }\n\n    function swapTokensForETH(uint256 tokenAmount) private {\n        if (isSwapping) return;\n        isSwapping = true;\n        address[] memory path = new address[](2);\n        path[0] = address(this);\n        path[1] = router.WETH();\n\n        router.swapExactTokensForETHSupportingFeeOnTransferTokens(\n            tokenAmount,\n            0,\n            path,\n            treasury,\n            block.timestamp\n        );\n        isSwapping = false;\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    constructor() {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
      },
      "lib/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol": {
        "content": "pragma solidity >=0.6.2;\n\nimport './IUniswapV2Router01.sol';\n\ninterface IUniswapV2Router02 is IUniswapV2Router01 {\n    function removeLiquidityETHSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountETH);\n    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountETH);\n\n    function swapExactTokensForTokensSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n    function swapExactETHForTokensSupportingFeeOnTransferTokens(\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external payable;\n    function swapExactTokensForETHSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n}\n"
      },
      "lib/v2-core/contracts/interfaces/IUniswapV2Factory.sol": {
        "content": "pragma solidity >=0.5.0;\n\ninterface IUniswapV2Factory {\n    event PairCreated(address indexed token0, address indexed token1, address pair, uint);\n\n    function feeTo() external view returns (address);\n    function feeToSetter() external view returns (address);\n\n    function getPair(address tokenA, address tokenB) external view returns (address pair);\n    function allPairs(uint) external view returns (address pair);\n    function allPairsLength() external view returns (uint);\n\n    function createPair(address tokenA, address tokenB) external returns (address pair);\n\n    function setFeeTo(address) external;\n    function setFeeToSetter(address) external;\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to\n     * 0 before setting it to a non-zero value.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\n    }\n}\n"
      },
      "lib/dn404/src/DN404.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\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    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\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 UnitIsZero();\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 The function selector is not recognized.\n    error FnSelectorNotRecognized();\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    /// @dev The flag to denote that the address has overridden the default Permit2 allowance.\n    uint8 internal constant _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG = 1 << 2;\n\n    /// @dev The canonical Permit2 address.\n    /// For signature-based allowance granting for single transaction ERC20 `transferFrom`.\n    /// To enable, override `_givePermit2DefaultInfiniteAllowance()`.\n    /// [Github](https://github.com/Uniswap/permit2)\n    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)\n    address internal constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                          STORAGE                           */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Struct containing an address's token data and settings.\n    struct AddressData {\n        // Auxiliary data.\n        uint88 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.\n        uint32 ownedLength;\n        // The token balance in wei.\n        uint96 balance;\n    }\n\n    /// @dev A uint32 map in storage.\n    struct Uint32Map {\n        uint256 spacer;\n    }\n\n    /// @dev A bitmap in storage.\n    struct Bitmap {\n        uint256 spacer;\n    }\n\n    /// @dev A struct to wrap a uint256 in storage.\n    struct Uint256Ref {\n        uint256 value;\n    }\n\n    /// @dev A mapping of an address pair to a Uint256Ref.\n    struct AddressPairToUint256RefMap {\n        uint256 spacer;\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        // The head of the burned pool.\n        uint32 burnedPoolHead;\n        // The tail of the burned pool.\n        uint32 burnedPoolTail;\n        // Total number of NFTs in existence.\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        AddressPairToUint256RefMap 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        Bitmap mayHaveNFTApproval;\n        // Bitmap of whether a NFT ID exists. Ignored if `_useExistsLookup()` returns false.\n        Bitmap exists;\n        // Mapping of user allowances for ERC20 spenders.\n        AddressPairToUint256RefMap allowance;\n        // Mapping of NFT IDs owned by an address.\n        mapping(address => Uint32Map) owned;\n        // The pool of burned NFT IDs.\n        Uint32Map burnedPool;\n        // Even indices: owner aliases. Odd indices: owned indices.\n        Uint32Map oo;\n        // Mapping of user account AddressData.\n        mapping(address => AddressData) addressData;\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 (_unit() == 0) revert UnitIsZero();\n        if ($.mirrorERC721 != address(0)) revert DNAlreadyInitialized();\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        $.nextTokenId = 1;\n        $.mirrorERC721 = mirror;\n\n        if (initialTokenSupply != 0) {\n            if (initialSupplyOwner == address(0)) revert TransferToZeroAddress();\n            if (_totalSupplyOverflows(initialTokenSupply)) revert TotalSupplyOverflow();\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    /*                       CONFIGURABLES                        */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns if direct NFT transfers should be used during ERC20 transfers\n    /// whenever possible, instead of burning and re-minting.\n    function _useDirectTransfersIfPossible() internal view virtual returns (bool) {\n        return true;\n    }\n\n    /// @dev Returns if burns should be added to the burn pool.\n    /// This returns false by default, which means the NFT IDs are re-minted in a cycle.\n    function _addToBurnedPool(uint256 totalNFTSupplyAfterBurn, uint256 totalSupplyAfterBurn)\n        internal\n        view\n        virtual\n        returns (bool)\n    {\n        // Silence unused variable compiler warning.\n        totalSupplyAfterBurn = totalNFTSupplyAfterBurn;\n        return false;\n    }\n\n    /// @dev Returns whether to use the exists bitmap for more efficient\n    /// scanning of an empty token ID slot.\n    /// Recommended for collections that do not use the burn pool,\n    /// and are expected to have nearly all possible NFTs materialized.\n    ///\n    /// Note: The returned value must be constant after initialization.\n    function _useExistsLookup() internal view virtual returns (bool) {\n        return true;\n    }\n\n    /// @dev Hook that is called after any NFT token transfers, including minting and burning.\n    function _afterNFTTransfer(address from, address to, uint256 id) internal virtual {}\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        if (_givePermit2DefaultInfiniteAllowance() && spender == _PERMIT2) {\n            uint8 flags = _getDN404Storage().addressData[owner].flags;\n            if (flags & _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG == 0) return type(uint256).max;\n        }\n        return _ref(_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        _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        Uint256Ref storage a = _ref(_getDN404Storage().allowance, from, msg.sender);\n\n        uint256 allowed = _givePermit2DefaultInfiniteAllowance() && msg.sender == _PERMIT2\n            && (_getDN404Storage().addressData[from].flags & _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG) == 0\n            ? type(uint256).max\n            : a.value;\n\n        if (allowed != type(uint256).max) {\n            if (amount > allowed) revert InsufficientAllowance();\n            unchecked {\n                a.value = allowed - amount;\n            }\n        }\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                          PERMIT2                           */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Whether Permit2 has infinite allowances by default for all owners.\n    /// For signature-based allowance granting for single transaction ERC20 `transferFrom`.\n    /// To enable, override this function to return true.\n    function _givePermit2DefaultInfiniteAllowance() internal view virtual returns (bool) {\n        return false;\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                  INTERNAL MINT FUNCTIONS                   */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Mints `amount` tokens to `to`, increasing the total supply.\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 set to false.\n    ///\n    /// Emits a {Transfer} event.\n    function _mint(address to, uint256 amount) internal virtual {\n        if (to == address(0)) revert TransferToZeroAddress();\n\n        AddressData storage toAddressData = _addressData(to);\n        DN404Storage storage $ = _getDN404Storage();\n        if ($.mirrorERC721 == address(0)) revert();\n\n        _DNMintTemps memory t;\n        unchecked {\n            uint256 toBalance = uint256(toAddressData.balance) + amount;\n            toAddressData.balance = uint96(toBalance);\n            t.toEnd = toBalance / _unit();\n        }\n        uint256 maxId;\n        unchecked {\n            uint256 totalSupply_ = uint256($.totalSupply) + amount;\n            $.totalSupply = uint96(totalSupply_);\n            uint256 overflows = _toUint(_totalSupplyOverflows(totalSupply_));\n            if (overflows | _toUint(totalSupply_ < amount) != 0) revert TotalSupplyOverflow();\n            maxId = totalSupply_ / _unit();\n        }\n        unchecked {\n            if (toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG == 0) {\n                Uint32Map storage toOwned = $.owned[to];\n                Uint32Map storage oo = $.oo;\n                uint256 toIndex = toAddressData.ownedLength;\n                _DNPackedLogs memory packedLogs = _packedLogsMalloc(_zeroFloorSub(t.toEnd, toIndex));\n\n                if (packedLogs.logs.length != 0) {\n                    _packedLogsSet(packedLogs, to, 0);\n                    $.totalNFTSupply += uint32(packedLogs.logs.length);\n                    toAddressData.ownedLength = uint32(t.toEnd);\n                    t.toAlias = _registerAndResolveAlias(toAddressData, to);\n                    uint32 burnedPoolHead = $.burnedPoolHead;\n                    t.burnedPoolTail = $.burnedPoolTail;\n                    t.nextTokenId = _wrapNFTId($.nextTokenId, maxId);\n                    // Mint loop.\n                    do {\n                        uint256 id;\n                        if (burnedPoolHead != t.burnedPoolTail) {\n                            id = _get($.burnedPool, burnedPoolHead++);\n                        } else {\n                            id = t.nextTokenId;\n                            while (_get(oo, _ownershipIndex(id)) != 0) {\n                                id = _useExistsLookup()\n                                    ? _wrapNFTId(_findFirstUnset($.exists, id + 1, maxId + 1), maxId)\n                                    : _wrapNFTId(id + 1, maxId);\n                            }\n                            t.nextTokenId = _wrapNFTId(id + 1, maxId);\n                        }\n                        if (_useExistsLookup()) _set($.exists, id, true);\n                        _set(toOwned, toIndex, uint32(id));\n                        _setOwnerAliasAndOwnedIndex(oo, id, t.toAlias, uint32(toIndex++));\n                        _packedLogsAppend(packedLogs, id);\n                        _afterNFTTransfer(address(0), to, id);\n                    } while (toIndex != t.toEnd);\n\n                    $.nextTokenId = uint32(t.nextTokenId);\n                    $.burnedPoolHead = burnedPoolHead;\n                    _packedLogsSend(packedLogs, $.mirrorERC721);\n                }\n            }\n        }\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Emit the {Transfer} event.\n            mstore(0x00, amount)\n            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, shl(96, to)))\n        }\n    }\n\n    /// @dev Mints `amount` tokens to `to`, increasing the total supply.\n    /// This variant mints NFT tokens starting from ID `preTotalSupply / _unit() + 1`.\n    /// This variant will not touch the `burnedPool` and `nextTokenId`.\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 set to false.\n    ///\n    /// Emits a {Transfer} event.\n    function _mintNext(address to, uint256 amount) internal virtual {\n        if (to == address(0)) revert TransferToZeroAddress();\n\n        AddressData storage toAddressData = _addressData(to);\n        DN404Storage storage $ = _getDN404Storage();\n        if ($.mirrorERC721 == address(0)) revert();\n\n        _DNMintTemps memory t;\n        unchecked {\n            uint256 toBalance = uint256(toAddressData.balance) + amount;\n            toAddressData.balance = uint96(toBalance);\n            t.toEnd = toBalance / _unit();\n        }\n        uint256 startId;\n        uint256 maxId;\n        unchecked {\n            uint256 preTotalSupply = uint256($.totalSupply);\n            startId = preTotalSupply / _unit() + 1;\n            uint256 totalSupply_ = uint256(preTotalSupply) + amount;\n            $.totalSupply = uint96(totalSupply_);\n            uint256 overflows = _toUint(_totalSupplyOverflows(totalSupply_));\n            if (overflows | _toUint(totalSupply_ < amount) != 0) revert TotalSupplyOverflow();\n            maxId = totalSupply_ / _unit();\n        }\n        unchecked {\n            if (toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG == 0) {\n                Uint32Map storage toOwned = $.owned[to];\n                Uint32Map storage oo = $.oo;\n                uint256 toIndex = toAddressData.ownedLength;\n                _DNPackedLogs memory packedLogs = _packedLogsMalloc(_zeroFloorSub(t.toEnd, toIndex));\n\n                if (packedLogs.logs.length != 0) {\n                    _packedLogsSet(packedLogs, to, 0);\n                    $.totalNFTSupply += uint32(packedLogs.logs.length);\n                    toAddressData.ownedLength = uint32(t.toEnd);\n                    t.toAlias = _registerAndResolveAlias(toAddressData, to);\n                    // Mint loop.\n                    do {\n                        uint256 id = startId;\n                        while (_get(oo, _ownershipIndex(id)) != 0) {\n                            id = _useExistsLookup()\n                                ? _wrapNFTId(_findFirstUnset($.exists, id + 1, maxId + 1), maxId)\n                                : _wrapNFTId(id + 1, maxId);\n                        }\n                        startId = _wrapNFTId(id + 1, maxId);\n                        if (_useExistsLookup()) _set($.exists, id, true);\n                        _set(toOwned, toIndex, uint32(id));\n                        _setOwnerAliasAndOwnedIndex(oo, id, t.toAlias, uint32(toIndex++));\n                        _packedLogsAppend(packedLogs, id);\n                        _afterNFTTransfer(address(0), to, id);\n                    } while (toIndex != t.toEnd);\n\n                    _packedLogsSend(packedLogs, $.mirrorERC721);\n                }\n            }\n        }\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Emit the {Transfer} event.\n            mstore(0x00, amount)\n            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, shl(96, to)))\n        }\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                  INTERNAL BURN FUNCTIONS                   */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Burns `amount` tokens from `from`, reducing the total supply.\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    /// Emits a {Transfer} event.\n    function _burn(address from, uint256 amount) internal virtual {\n        AddressData storage fromAddressData = _addressData(from);\n        DN404Storage storage $ = _getDN404Storage();\n        if ($.mirrorERC721 == address(0)) revert();\n\n        uint256 fromBalance = fromAddressData.balance;\n        if (amount > fromBalance) revert InsufficientBalance();\n\n        unchecked {\n            fromAddressData.balance = uint96(fromBalance -= amount);\n            uint256 totalSupply_ = uint256($.totalSupply) - amount;\n            $.totalSupply = uint96(totalSupply_);\n\n            Uint32Map storage fromOwned = $.owned[from];\n            uint256 fromIndex = fromAddressData.ownedLength;\n            uint256 numNFTBurns = _zeroFloorSub(fromIndex, fromBalance / _unit());\n\n            if (numNFTBurns != 0) {\n                _DNPackedLogs memory packedLogs = _packedLogsMalloc(numNFTBurns);\n                _packedLogsSet(packedLogs, from, 1);\n                bool addToBurnedPool;\n                {\n                    uint256 totalNFTSupply = uint256($.totalNFTSupply) - numNFTBurns;\n                    $.totalNFTSupply = uint32(totalNFTSupply);\n                    addToBurnedPool = _addToBurnedPool(totalNFTSupply, totalSupply_);\n                }\n\n                Uint32Map storage oo = $.oo;\n                uint256 fromEnd = fromIndex - numNFTBurns;\n                fromAddressData.ownedLength = uint32(fromEnd);\n                uint32 burnedPoolTail = $.burnedPoolTail;\n                // Burn loop.\n                do {\n                    uint256 id = _get(fromOwned, --fromIndex);\n                    _setOwnerAliasAndOwnedIndex(oo, id, 0, 0);\n                    _packedLogsAppend(packedLogs, id);\n                    if (_useExistsLookup()) _set($.exists, id, false);\n                    if (addToBurnedPool) _set($.burnedPool, burnedPoolTail++, uint32(id));\n                    if (_get($.mayHaveNFTApproval, id)) {\n                        _set($.mayHaveNFTApproval, id, false);\n                        delete $.nftApprovals[id];\n                    }\n                    _afterNFTTransfer(from, address(0), id);\n                } while (fromIndex != fromEnd);\n\n                if (addToBurnedPool) $.burnedPoolTail = burnedPoolTail;\n                _packedLogsSend(packedLogs, $.mirrorERC721);\n            }\n        }\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Emit the {Transfer} event.\n            mstore(0x00, amount)\n            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)\n        }\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        AddressData storage fromAddressData = _addressData(from);\n        AddressData storage toAddressData = _addressData(to);\n        DN404Storage storage $ = _getDN404Storage();\n        if ($.mirrorERC721 == address(0)) revert();\n\n        _DNTransferTemps memory t;\n        t.fromOwnedLength = fromAddressData.ownedLength;\n        t.toOwnedLength = toAddressData.ownedLength;\n        t.totalSupply = $.totalSupply;\n\n        if (amount > (t.fromBalance = fromAddressData.balance)) revert InsufficientBalance();\n\n        unchecked {\n            fromAddressData.balance = uint96(t.fromBalance -= amount);\n            toAddressData.balance = uint96(t.toBalance = uint256(toAddressData.balance) + amount);\n\n            t.numNFTBurns = _zeroFloorSub(t.fromOwnedLength, 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(t.toBalance / _unit(), t.toOwnedLength);\n            }\n\n            while (_useDirectTransfersIfPossible()) {\n                uint256 n = _min(t.fromOwnedLength, _min(t.numNFTBurns, t.numNFTMints));\n                if (n == 0) break;\n                t.numNFTBurns -= n;\n                t.numNFTMints -= n;\n                if (from == to) {\n                    t.toOwnedLength += n;\n                    break;\n                }\n                _DNDirectLogs memory directLogs = _directLogsMalloc(n, from, to);\n                Uint32Map storage fromOwned = $.owned[from];\n                Uint32Map storage toOwned = $.owned[to];\n                t.toAlias = _registerAndResolveAlias(toAddressData, to);\n                uint256 toIndex = t.toOwnedLength;\n                // Direct transfer loop.\n                do {\n                    uint256 id = _get(fromOwned, --t.fromOwnedLength);\n                    _set(toOwned, toIndex, uint32(id));\n                    _setOwnerAliasAndOwnedIndex($.oo, id, t.toAlias, uint32(toIndex++));\n                    _directLogsAppend(directLogs, id);\n                    if (_get($.mayHaveNFTApproval, id)) {\n                        _set($.mayHaveNFTApproval, id, false);\n                        delete $.nftApprovals[id];\n                    }\n                    _afterNFTTransfer(from, to, id);\n                } while (--n != 0);\n\n                toAddressData.ownedLength = uint32(t.toOwnedLength = toIndex);\n                fromAddressData.ownedLength = uint32(t.fromOwnedLength);\n                _directLogsSend(directLogs, $.mirrorERC721);\n                break;\n            }\n\n            t.totalNFTSupply = uint256($.totalNFTSupply) + t.numNFTMints - t.numNFTBurns;\n            $.totalNFTSupply = uint32(t.totalNFTSupply);\n\n            Uint32Map storage oo = $.oo;\n            _DNPackedLogs memory packedLogs = _packedLogsMalloc(t.numNFTBurns + t.numNFTMints);\n\n            t.burnedPoolTail = $.burnedPoolTail;\n            if (t.numNFTBurns != 0) {\n                _packedLogsSet(packedLogs, from, 1);\n                bool addToBurnedPool = _addToBurnedPool(t.totalNFTSupply, t.totalSupply);\n                Uint32Map storage fromOwned = $.owned[from];\n                uint256 fromIndex = t.fromOwnedLength;\n                fromAddressData.ownedLength = uint32(t.fromEnd = fromIndex - t.numNFTBurns);\n                uint32 burnedPoolTail = t.burnedPoolTail;\n                // Burn loop.\n                do {\n                    uint256 id = _get(fromOwned, --fromIndex);\n                    _setOwnerAliasAndOwnedIndex(oo, id, 0, 0);\n                    _packedLogsAppend(packedLogs, id);\n                    if (_useExistsLookup()) _set($.exists, id, false);\n                    if (addToBurnedPool) _set($.burnedPool, burnedPoolTail++, uint32(id));\n                    if (_get($.mayHaveNFTApproval, id)) {\n                        _set($.mayHaveNFTApproval, id, false);\n                        delete $.nftApprovals[id];\n                    }\n                    _afterNFTTransfer(from, address(0), id);\n                } while (fromIndex != t.fromEnd);\n\n                if (addToBurnedPool) $.burnedPoolTail = (t.burnedPoolTail = burnedPoolTail);\n            }\n\n            if (t.numNFTMints != 0) {\n                _packedLogsSet(packedLogs, to, 0);\n                Uint32Map storage toOwned = $.owned[to];\n                t.toAlias = _registerAndResolveAlias(toAddressData, to);\n                uint256 maxId = t.totalSupply / _unit();\n                t.nextTokenId = _wrapNFTId($.nextTokenId, maxId);\n                uint256 toIndex = t.toOwnedLength;\n                toAddressData.ownedLength = uint32(t.toEnd = toIndex + t.numNFTMints);\n                uint32 burnedPoolHead = $.burnedPoolHead;\n                // Mint loop.\n                do {\n                    uint256 id;\n                    if (burnedPoolHead != t.burnedPoolTail) {\n                        id = _get($.burnedPool, burnedPoolHead++);\n                    } else {\n                        id = t.nextTokenId;\n                        while (_get(oo, _ownershipIndex(id)) != 0) {\n                            id = _useExistsLookup()\n                                ? _wrapNFTId(_findFirstUnset($.exists, id + 1, maxId + 1), maxId)\n                                : _wrapNFTId(id + 1, maxId);\n                        }\n                        t.nextTokenId = _wrapNFTId(id + 1, maxId);\n                    }\n                    if (_useExistsLookup()) _set($.exists, id, true);\n                    _set(toOwned, toIndex, uint32(id));\n                    _setOwnerAliasAndOwnedIndex(oo, id, t.toAlias, uint32(toIndex++));\n                    _packedLogsAppend(packedLogs, id);\n                    _afterNFTTransfer(address(0), to, id);\n                } while (toIndex != t.toEnd);\n\n                $.burnedPoolHead = burnedPoolHead;\n                $.nextTokenId = uint32(t.nextTokenId);\n            }\n\n            if (packedLogs.logs.length != 0) _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(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), shr(96, shl(96, to)))\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        if ($.mirrorERC721 == address(0)) revert();\n\n        Uint32Map storage oo = $.oo;\n\n        if (from != $.aliasToAddress[_get(oo, _ownershipIndex(_restrictNFTId(id)))]) {\n            revert TransferFromIncorrectOwner();\n        }\n\n        if (msgSender != from) {\n            if (_ref($.operatorApprovals, from, msgSender).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        mapping(address => Uint32Map) storage owned = $.owned;\n        Uint32Map storage fromOwned = owned[from];\n\n        unchecked {\n            uint256 fromBalance = fromAddressData.balance;\n            if (unit > fromBalance) revert InsufficientBalance();\n            fromAddressData.balance = uint96(fromBalance - unit);\n            toAddressData.balance += uint96(unit);\n        }\n        if (_get($.mayHaveNFTApproval, id)) {\n            _set($.mayHaveNFTApproval, id, false);\n            delete $.nftApprovals[id];\n        }\n        unchecked {\n            uint32 updatedId = _get(fromOwned, --fromAddressData.ownedLength);\n            uint32 i = _get(oo, _ownedIndex(id));\n            _set(fromOwned, i, updatedId);\n            _set(oo, _ownedIndex(updatedId), i);\n        }\n        unchecked {\n            uint32 n = toAddressData.ownedLength++;\n            _set(owned[to], n, uint32(id));\n            _setOwnerAliasAndOwnedIndex(oo, id, _registerAndResolveAlias(toAddressData, to), n);\n        }\n        _afterNFTTransfer(from, to, id);\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Emit the {Transfer} event.\n            mstore(0x00, unit)\n            // forgefmt: disable-next-item\n            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), shr(96, shl(96, to)))\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        if (_givePermit2DefaultInfiniteAllowance() && spender == _PERMIT2) {\n            _getDN404Storage().addressData[owner].flags |= _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG;\n        }\n        _ref(_getDN404Storage().allowance, owner, spender).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(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, shl(96, owner)), shr(96, shl(96, spender)))\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 (uint88) {\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, uint88 value) internal virtual {\n        _getDN404Storage().addressData[owner].aux = value;\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) return _hasCode(owner);\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        return _getDN404Storage().addressData[owner].ownedLength;\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(_restrictNFTId(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(_restrictNFTId(id)))];\n\n        if (msgSender != owner) {\n            if (_ref($.operatorApprovals, owner, msgSender).value == 0) {\n                revert ApprovalCallerNotOwnerNorApproved();\n            }\n        }\n\n        $.nftApprovals[id] = spender;\n        _set($.mayHaveNFTApproval, id, spender != address(0));\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        _ref(_getDN404Storage().operatorApprovals, msgSender, operator).value = _toUint(approved);\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)\n        internal\n        view\n        virtual\n        returns (uint256[] memory ids)\n    {\n        DN404Storage storage $ = _getDN404Storage();\n        Uint32Map storage owned = $.owned[owner];\n        uint256 n = _min($.addressData[owner].ownedLength, end);\n        /// @solidity memory-safe-assembly\n        assembly {\n            ids := mload(0x40)\n            let i := begin\n            for {} lt(i, n) { i := add(i, 1) } {\n                let s := add(shl(96, owned.slot), shr(3, i)) // 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 != mirror) 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 != mirror) 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        // `isApprovedForAll(address,address)`.\n        if (fnSelector == 0xe985e9c5) {\n            if (msg.sender != mirror) revert SenderNotMirror();\n            Uint256Ref storage ref = _ref(\n                $.operatorApprovals,\n                address(uint160(_calldataload(0x04))), // `owner`.\n                address(uint160(_calldataload(0x24))) // `operator`.\n            );\n            _return(ref.value);\n        }\n        // `ownerOf(uint256)`.\n        if (fnSelector == 0x6352211e) {\n            if (msg.sender != mirror) revert SenderNotMirror();\n            _return(uint160(_ownerOf(_calldataload(0x04))));\n        }\n        // `ownerAt(uint256)`.\n        if (fnSelector == 0x24359879) {\n            if (msg.sender != mirror) revert SenderNotMirror();\n            _return(uint160(_ownerAt(_calldataload(0x04))));\n        }\n        // `approveNFT(address,uint256,address)`.\n        if (fnSelector == 0xd10b6e0c) {\n            if (msg.sender != mirror) 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        // `getApproved(uint256)`.\n        if (fnSelector == 0x081812fc) {\n            if (msg.sender != mirror) revert SenderNotMirror();\n            _return(uint160(_getApproved(_calldataload(0x04))));\n        }\n        // `balanceOfNFT(address)`.\n        if (fnSelector == 0xf5b100ea) {\n            if (msg.sender != mirror) revert SenderNotMirror();\n            _return(_balanceOfNFT(address(uint160(_calldataload(0x04)))));\n        }\n        // `totalNFTSupply()`.\n        if (fnSelector == 0xe2c79281) {\n            if (msg.sender != mirror) revert SenderNotMirror();\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    /// Override this if you need to implement your custom\n    /// fallback with utilities like Solady's `LibZip.cdFallback()`.\n    /// And always remember to always wrap the fallback with `dn404Fallback`.\n    fallback() external payable virtual dn404Fallback {\n        revert FnSelectorNotRecognized(); // Not mandatory. Just for quality of life.\n    }\n\n    /// @dev This is to silence the compiler warning.\n    /// Override and remove the revert if you want your contract to receive ETH via receive.\n    receive() external payable virtual {\n        if (msg.value != 0) revert();\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                 INTERNAL / PRIVATE HELPERS                 */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns `(i - 1) << 1`.\n    function _ownershipIndex(uint256 i) internal pure returns (uint256) {\n        unchecked {\n            return (i - 1) << 1; // Minus 1 as token IDs start from 1.\n        }\n    }\n\n    /// @dev Returns `((i - 1) << 1) + 1`.\n    function _ownedIndex(uint256 i) internal pure returns (uint256) {\n        unchecked {\n            return ((i - 1) << 1) + 1; // Minus 1 as token IDs start from 1.\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        /// @solidity memory-safe-assembly\n        assembly {\n            let s := add(shl(96, map.slot), shr(3, index)) // Storage slot.\n            result := and(0xffffffff, shr(shl(5, and(index, 7)), sload(s)))\n        }\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            let s := add(shl(96, map.slot), shr(3, index)) // Storage slot.\n            let o := shl(5, and(index, 7)) // Storage slot offset (bits).\n            let v := sload(s) // Storage slot value.\n            sstore(s, xor(v, shl(o, and(0xffffffff, xor(value, shr(o, v))))))\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 i := sub(id, 1) // Index of the uint64 combined value.\n            let s := add(shl(96, map.slot), shr(2, i)) // Storage slot.\n            let v := sload(s) // Storage slot value.\n            let o := shl(6, and(i, 3)) // Storage slot offset (bits).\n            let combined := or(shl(32, ownedIndex), and(0xffffffff, ownership))\n            sstore(s, xor(v, shl(o, and(0xffffffffffffffff, xor(shr(o, v), combined)))))\n        }\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 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let s := add(shl(96, bitmap.slot), shr(8, index)) // Storage slot.\n            result := and(1, shr(and(0xff, index), sload(s)))\n        }\n    }\n\n    /// @dev Updates the bit at `index` in `bitmap` to `value`.\n    function _set(Bitmap storage bitmap, uint256 index, bool value) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let s := add(shl(96, bitmap.slot), shr(8, index)) // Storage slot.\n            let o := and(0xff, index) // Storage slot offset (bits).\n            sstore(s, or(and(sload(s), not(shl(o, 1))), shl(o, iszero(iszero(value)))))\n        }\n    }\n\n    /// @dev Returns the index of the least significant unset bit in `[begin, end)`.\n    /// If no unset bit is found, returns `type(uint256).max`.\n    function _findFirstUnset(Bitmap storage bitmap, uint256 begin, uint256 end)\n        internal\n        view\n        returns (uint256 unsetBitIndex)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            unsetBitIndex := not(0) // Initialize to `type(uint256).max`.\n            let s := shl(96, bitmap.slot) // Storage offset of the bitmap.\n            let bucket := add(s, shr(8, begin))\n            let negBits := shl(and(0xff, begin), shr(and(0xff, begin), not(sload(bucket))))\n            if iszero(negBits) {\n                let lastBucket := add(s, shr(8, end))\n                for {} 1 {} {\n                    bucket := add(bucket, 1)\n                    negBits := not(sload(bucket))\n                    if or(negBits, gt(bucket, lastBucket)) { break }\n                }\n                if gt(bucket, lastBucket) {\n                    negBits := shr(and(0xff, not(end)), shl(and(0xff, not(end)), negBits))\n                }\n            }\n            if negBits {\n                // Find-first-set routine.\n                let b := and(negBits, add(not(negBits), 1)) // Isolate the least significant bit.\n                let r := 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                // 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                r := or(shl(8, sub(bucket, s)), r)\n                unsetBitIndex := or(r, sub(0, or(iszero(lt(r, end)), lt(r, begin))))\n            }\n        }\n    }\n\n    /// @dev Returns a storage reference to the value at (`a0`, `a1`) in `map`.\n    function _ref(AddressPairToUint256RefMap storage map, address a0, address a1)\n        internal\n        pure\n        returns (Uint256Ref storage ref)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x28, a1)\n            mstore(0x14, a0)\n            mstore(0x00, map.slot)\n            ref.slot := keccak256(0x00, 0x48)\n            // Clear the part of the free memory pointer that was overwritten.\n            mstore(0x28, 0x00)\n        }\n    }\n\n    /// @dev Wraps the NFT ID.\n    function _wrapNFTId(uint256 id, uint256 maxId) internal pure returns (uint256 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := or(mul(iszero(gt(id, maxId)), id), gt(id, maxId))\n        }\n    }\n\n    /// @dev Returns `id > type(uint32).max ? 0 : id`.\n    function _restrictNFTId(uint256 id) internal pure returns (uint256 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := mul(id, lt(id, 0x100000000))\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 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 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 `_directLogsSend`.\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), to) // Set `p.to`.\n            mstore(add(0x20, p), 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            let from := mload(add(0x20, p))\n            let to := mload(add(0x40, p))\n            mstore(add(o, 0x20), from)\n            mstore(add(o, 0x40), to)\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    /// @dev Struct containing packed log data for {Transfer} events to be\n    /// emitted by the mirror NFT contract.\n    struct _DNPackedLogs {\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) private pure returns (_DNPackedLogs memory p) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Note that `p` implicitly allocates and advances the free memory pointer by\n            // 3 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(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(_DNPackedLogs memory p, address a, uint256 burnBit) private pure {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(add(p, 0x20), or(shl(96, a), burnBit)) // Set `p.addressAndBit`.\n        }\n    }\n\n    /// @dev Adds a packed log item to `p` with token `id`.\n    function _packedLogsAppend(_DNPackedLogs memory p, uint256 id) private pure {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let offset := mload(p)\n            mstore(offset, or(mload(add(p, 0x20)), shl(8, id))) // `p.addressAndBit | (id << 8)`.\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 _packedLogsSend(_DNPackedLogs memory p, address mirror) private {\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 _DNTransferTemps {\n        uint256 numNFTBurns;\n        uint256 numNFTMints;\n        uint256 fromBalance;\n        uint256 toBalance;\n        uint256 fromOwnedLength;\n        uint256 toOwnedLength;\n        uint256 totalSupply;\n        uint256 totalNFTSupply;\n        uint256 fromEnd;\n        uint256 toEnd;\n        uint32 toAlias;\n        uint256 nextTokenId;\n        uint32 burnedPoolTail;\n    }\n\n    /// @dev Struct of temporary variables for mints.\n    struct _DNMintTemps {\n        uint256 nextTokenId;\n        uint32 burnedPoolTail;\n        uint256 toEnd;\n        uint32 toAlias;\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"
      },
      "lib/dn404/src/DN404Mirror.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @title DN404Mirror\n/// @notice DN404Mirror provides an interface for interacting with the\n/// NFT tokens in a DN404 implementation.\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 the base DN404 contract.\ncontract DN404Mirror {\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                           EVENTS                           */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Emitted when token `id` is transferred from `from` to `to`.\n    event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n    /// @dev Emitted when `owner` enables `account` to manage the `id` token.\n    event Approval(address indexed owner, address indexed account, uint256 indexed id);\n\n    /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.\n    event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);\n\n    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.\n    /// This is for marketplace signaling purposes. This contract has a `pullOwner()`\n    /// function that will sync the owner from the base contract.\n    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);\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(\"ApprovalForAll(address,address,bool)\"))`.\n    uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =\n        0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                        CUSTOM ERRORS                       */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Thrown when a call for an NFT function did not originate\n    /// from the base DN404 contract.\n    error SenderNotBase();\n\n    /// @dev Thrown when a call for an NFT function did not originate from the deployer.\n    error SenderNotDeployer();\n\n    /// @dev Thrown when transferring an NFT to a contract address that\n    /// does not implement ERC721Receiver.\n    error TransferToNonERC721ReceiverImplementer();\n\n    /// @dev Thrown when linking to the DN404 base contract and the\n    /// DN404 supportsInterface check fails or the call reverts.\n    error CannotLink();\n\n    /// @dev Thrown when a linkMirrorContract call is received and the\n    /// NFT mirror contract has already been linked to a DN404 base contract.\n    error AlreadyLinked();\n\n    /// @dev Thrown when retrieving the base DN404 address when a link has not\n    /// been established.\n    error NotLinked();\n\n    /// @dev The function selector is not recognized.\n    error FnSelectorNotRecognized();\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                          STORAGE                           */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Struct contain the NFT mirror contract storage.\n    struct DN404NFTStorage {\n        // Address of the ERC20 base contract.\n        address baseERC20;\n        // The deployer, if provided. If non-zero, the initialization of the\n        // ERC20 <-> ERC721 link can only be done be the deployer via the ERC20 base contract.\n        address deployer;\n        // The owner of the ERC20 base contract. For marketplace signaling.\n        address owner;\n    }\n\n    /// @dev Returns a storage pointer for DN404NFTStorage.\n    function _getDN404NFTStorage() internal pure virtual returns (DN404NFTStorage storage $) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // `uint72(bytes9(keccak256(\"DN404_MIRROR_STORAGE\")))`.\n            $.slot := 0x3602298b8c10b01230 // Truncate to 9 bytes to reduce bytecode size.\n        }\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                        CONSTRUCTOR                         */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    constructor(address deployer) {\n        // For non-proxies, we will store the deployer so that only the deployer can\n        // link the base contract.\n        _getDN404NFTStorage().deployer = deployer;\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                     ERC721 OPERATIONS                      */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns the token collection name from the base DN404 contract.\n    function name() public view virtual returns (string memory) {\n        return _readString(0x06fdde03, 0); // `name()`.\n    }\n\n    /// @dev Returns the token collection symbol from the base DN404 contract.\n    function symbol() public view virtual returns (string memory) {\n        return _readString(0x95d89b41, 0); // `symbol()`.\n    }\n\n    /// @dev Returns the Uniform Resource Identifier (URI) for token `id` from\n    /// the base DN404 contract.\n    function tokenURI(uint256 id) public view virtual returns (string memory) {\n        return _readString(0xc87b56dd, id); // `tokenURI()`.\n    }\n\n    /// @dev Returns the total NFT supply from the base DN404 contract.\n    function totalSupply() public view virtual returns (uint256) {\n        return _readWord(0xe2c79281, 0, 0); // `totalNFTSupply()`.\n    }\n\n    /// @dev Returns the number of NFT tokens owned by `nftOwner` from the base DN404 contract.\n    ///\n    /// Requirements:\n    /// - `nftOwner` must not be the zero address.\n    function balanceOf(address nftOwner) public view virtual returns (uint256) {\n        return _readWord(0xf5b100ea, uint160(nftOwner), 0); // `balanceOfNFT(address)`.\n    }\n\n    /// @dev Returns the owner of token `id` from the base DN404 contract.\n    ///\n    /// Requirements:\n    /// - Token `id` must exist.\n    function ownerOf(uint256 id) public view virtual returns (address) {\n        return address(uint160(_readWord(0x6352211e, id, 0))); // `ownerOf(uint256)`.\n    }\n\n    /// @dev Returns the owner of token `id` from the base DN404 contract.\n    /// Returns `address(0)` instead of reverting if the token does not exist.\n    function ownerAt(uint256 id) public view virtual returns (address) {\n        return address(uint160(_readWord(0x24359879, id, 0))); // `ownerAt(uint256)`.\n    }\n\n    /// @dev Sets `spender` as the approved account to manage token `id` in\n    /// the base DN404 contract.\n    ///\n    /// Requirements:\n    /// - Token `id` must exist.\n    /// - The caller must be the owner of the token,\n    ///   or an approved operator for the token owner.\n    ///\n    /// Emits an {Approval} event.\n    function approve(address spender, uint256 id) public payable virtual {\n        address base = baseERC20();\n        /// @solidity memory-safe-assembly\n        assembly {\n            spender := shr(96, shl(96, spender))\n            let m := mload(0x40)\n            mstore(0x00, 0xd10b6e0c) // `approveNFT(address,uint256,address)`.\n            mstore(0x20, spender)\n            mstore(0x40, id)\n            mstore(0x60, caller())\n            if iszero(\n                and( // Arguments of `and` are evaluated last to first.\n                    gt(returndatasize(), 0x1f), // The call must return at least 32 bytes.\n                    call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20)\n                )\n            ) {\n                returndatacopy(m, 0x00, returndatasize())\n                revert(m, returndatasize())\n            }\n            mstore(0x40, m) // Restore the free memory pointer.\n            mstore(0x60, 0) // Restore the zero pointer.\n            // Emit the {Approval} event.\n            log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, shr(96, mload(0x0c)), spender, id)\n        }\n    }\n\n    /// @dev Returns the account approved to manage token `id` from\n    /// the base DN404 contract.\n    ///\n    /// Requirements:\n    /// - Token `id` must exist.\n    function getApproved(uint256 id) public view virtual returns (address) {\n        return address(uint160(_readWord(0x081812fc, id, 0))); // `getApproved(uint256)`.\n    }\n\n    /// @dev Sets whether `operator` is approved to manage the tokens of the caller in\n    /// the base DN404 contract.\n    ///\n    /// Emits an {ApprovalForAll} event.\n    function setApprovalForAll(address operator, bool approved) public virtual {\n        address base = baseERC20();\n        /// @solidity memory-safe-assembly\n        assembly {\n            operator := shr(96, shl(96, operator))\n            let m := mload(0x40)\n            mstore(0x00, 0x813500fc) // `setApprovalForAll(address,bool,address)`.\n            mstore(0x20, operator)\n            mstore(0x40, iszero(iszero(approved)))\n            mstore(0x60, caller())\n            if iszero(\n                and( // Arguments of `and` are evaluated last to first.\n                    eq(mload(0x00), 1), // The call must return 1.\n                    call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20)\n                )\n            ) {\n                returndatacopy(m, 0x00, returndatasize())\n                revert(m, returndatasize())\n            }\n            // Emit the {ApprovalForAll} event.\n            // The `approved` value is already at 0x40.\n            log3(0x40, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), operator)\n            mstore(0x40, m) // Restore the free memory pointer.\n            mstore(0x60, 0) // Restore the zero pointer.\n        }\n    }\n\n    /// @dev Returns whether `operator` is approved to manage the tokens of `nftOwner` from\n    /// the base DN404 contract.\n    function isApprovedForAll(address nftOwner, address operator)\n        public\n        view\n        virtual\n        returns (bool)\n    {\n        // `isApprovedForAll(address,address)`.\n        return _readWord(0xe985e9c5, uint160(nftOwner), uint160(operator)) != 0;\n    }\n\n    /// @dev Transfers token `id` from `from` to `to`.\n    ///\n    /// Requirements:\n    ///\n    /// - Token `id` must exist.\n    /// - `from` must be the owner of the token.\n    /// - `to` cannot be the zero address.\n    /// - The caller must be the owner of the token, or be approved to manage the token.\n    ///\n    /// Emits a {Transfer} event.\n    function transferFrom(address from, address to, uint256 id) public payable virtual {\n        address base = baseERC20();\n        /// @solidity memory-safe-assembly\n        assembly {\n            from := shr(96, shl(96, from))\n            to := shr(96, shl(96, to))\n            let m := mload(0x40)\n            mstore(m, 0xe5eb36c8) // `transferFromNFT(address,address,uint256,address)`.\n            mstore(add(m, 0x20), from)\n            mstore(add(m, 0x40), to)\n            mstore(add(m, 0x60), id)\n            mstore(add(m, 0x80), caller())\n            if iszero(\n                and( // Arguments of `and` are evaluated last to first.\n                    eq(mload(m), 1), // The call must return 1.\n                    call(gas(), base, callvalue(), add(m, 0x1c), 0x84, m, 0x20)\n                )\n            ) {\n                returndatacopy(m, 0x00, returndatasize())\n                revert(m, returndatasize())\n            }\n            // Emit the {Transfer} event.\n            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)\n        }\n    }\n\n    /// @dev Equivalent to `safeTransferFrom(from, to, id, \"\")`.\n    function safeTransferFrom(address from, address to, uint256 id) public payable virtual {\n        transferFrom(from, to, id);\n        if (_hasCode(to)) _checkOnERC721Received(from, to, id, \"\");\n    }\n\n    /// @dev Transfers token `id` from `from` to `to`.\n    ///\n    /// Requirements:\n    ///\n    /// - Token `id` must exist.\n    /// - `from` must be the owner of the token.\n    /// - `to` cannot be the zero address.\n    /// - The caller must be the owner of the token, or be approved to manage the token.\n    /// - If `to` refers to a smart contract, it must implement\n    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n    ///\n    /// Emits a {Transfer} event.\n    function safeTransferFrom(address from, address to, uint256 id, bytes calldata data)\n        public\n        payable\n        virtual\n    {\n        transferFrom(from, to, id);\n        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);\n    }\n\n    /// @dev Returns true if this contract implements the interface defined by `interfaceId`.\n    /// See: https://eips.ethereum.org/EIPS/eip-165\n    /// This function call must use less than 30000 gas.\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let s := shr(224, interfaceId)\n            // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f.\n            result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f))\n        }\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                  OWNER SYNCING OPERATIONS                  */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns the `owner` of the contract, for marketplace signaling purposes.\n    function owner() public view virtual returns (address) {\n        return _getDN404NFTStorage().owner;\n    }\n\n    /// @dev Permissionless function to pull the owner from the base DN404 contract\n    /// if it implements ownable, for marketplace signaling purposes.\n    function pullOwner() public virtual returns (bool) {\n        address newOwner;\n        address base = baseERC20();\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, 0x8da5cb5b) // `owner()`.\n            let success := staticcall(gas(), base, 0x1c, 0x04, 0x00, 0x20)\n            newOwner := mul(shr(96, mload(0x0c)), and(gt(returndatasize(), 0x1f), success))\n        }\n        DN404NFTStorage storage $ = _getDN404NFTStorage();\n        address oldOwner = $.owner;\n        if (oldOwner != newOwner) {\n            $.owner = newOwner;\n            emit OwnershipTransferred(oldOwner, newOwner);\n        }\n        return true;\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                     MIRROR OPERATIONS                      */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Returns the address of the base DN404 contract.\n    function baseERC20() public view virtual returns (address base) {\n        base = _getDN404NFTStorage().baseERC20;\n        if (base == address(0)) revert NotLinked();\n    }\n\n    /// @dev Fallback modifier to execute calls from the base DN404 contract.\n    modifier dn404NFTFallback() virtual {\n        DN404NFTStorage storage $ = _getDN404NFTStorage();\n\n        uint256 fnSelector = _calldataload(0x00) >> 224;\n\n        // `logTransfer(uint256[])`.\n        if (fnSelector == 0x263c69d6) {\n            if (msg.sender != $.baseERC20) revert SenderNotBase();\n            /// @solidity memory-safe-assembly\n            assembly {\n                let o := add(0x24, calldataload(0x04)) // Packed logs offset.\n                let end := add(o, shl(5, calldataload(sub(o, 0x20))))\n                for {} iszero(eq(o, end)) { o := add(0x20, o) } {\n                    let d := calldataload(o) // Entry in the packed logs.\n                    let a := shr(96, d) // The address.\n                    let b := and(1, d) // Whether it is a burn.\n                    log4(\n                        codesize(),\n                        0x00,\n                        _TRANSFER_EVENT_SIGNATURE,\n                        mul(a, b), // `from`.\n                        mul(a, iszero(b)), // `to`.\n                        shr(168, shl(160, d)) // `id`.\n                    )\n                }\n                mstore(0x00, 0x01)\n                return(0x00, 0x20)\n            }\n        }\n        // `logDirectTransfer(address,address,uint256[])`.\n        if (fnSelector == 0x144027d3) {\n            if (msg.sender != $.baseERC20) revert SenderNotBase();\n            /// @solidity memory-safe-assembly\n            assembly {\n                let from := calldataload(0x04)\n                let to := calldataload(0x24)\n                let o := add(0x24, calldataload(0x44)) // Direct logs offset.\n                let end := add(o, shl(5, calldataload(sub(o, 0x20))))\n                for {} iszero(eq(o, end)) { o := add(0x20, o) } {\n                    log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, calldataload(o))\n                }\n                mstore(0x00, 0x01)\n                return(0x00, 0x20)\n            }\n        }\n        // `linkMirrorContract(address)`.\n        if (fnSelector == 0x0f4599e5) {\n            if ($.deployer != address(0)) {\n                if (address(uint160(_calldataload(0x04))) != $.deployer) {\n                    revert SenderNotDeployer();\n                }\n            }\n            if ($.baseERC20 != address(0)) revert AlreadyLinked();\n            $.baseERC20 = msg.sender;\n            /// @solidity memory-safe-assembly\n            assembly {\n                mstore(0x00, 0x01)\n                return(0x00, 0x20)\n            }\n        }\n        _;\n    }\n\n    /// @dev Fallback function for calls from base DN404 contract.\n    /// Override this if you need to implement your custom\n    /// fallback with utilities like Solady's `LibZip.cdFallback()`.\n    /// And always remember to always wrap the fallback with `dn404NFTFallback`.\n    fallback() external payable virtual dn404NFTFallback {\n        revert FnSelectorNotRecognized(); // Not mandatory. Just for quality of life.\n    }\n\n    /// @dev This is to silence the compiler warning.\n    /// Override and remove the revert if you want your contract to receive ETH via receive.\n    receive() external payable virtual {\n        if (msg.value != 0) revert();\n    }\n\n    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/\n    /*                      PRIVATE HELPERS                       */\n    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/\n\n    /// @dev Helper to read a string from the base DN404 contract.\n    function _readString(uint256 fnSelector, uint256 arg0)\n        private\n        view\n        returns (string memory result)\n    {\n        address base = baseERC20();\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := mload(0x40)\n            mstore(0x00, fnSelector)\n            mstore(0x20, arg0)\n            if iszero(staticcall(gas(), base, 0x1c, 0x24, 0x00, 0x00)) {\n                returndatacopy(result, 0x00, returndatasize())\n                revert(result, returndatasize())\n            }\n            returndatacopy(0x00, 0x00, 0x20) // Copy the offset of the string in returndata.\n            returndatacopy(result, mload(0x00), 0x20) // Copy the length of the string.\n            returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), mload(result)) // Copy the string.\n            let end := add(add(result, 0x20), mload(result))\n            mstore(end, 0) // Zeroize the word after the string.\n            mstore(0x40, add(end, 0x20)) // Allocate memory.\n        }\n    }\n\n    /// @dev Helper to read a word from the base DN404 contract.\n    function _readWord(uint256 fnSelector, uint256 arg0, uint256 arg1)\n        private\n        view\n        returns (uint256 result)\n    {\n        address base = baseERC20();\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40)\n            mstore(0x00, fnSelector)\n            mstore(0x20, arg0)\n            mstore(0x40, arg1)\n            if iszero(\n                and( // Arguments of `and` are evaluated last to first.\n                    gt(returndatasize(), 0x1f), // The call must return at least 32 bytes.\n                    staticcall(gas(), base, 0x1c, 0x44, 0x00, 0x20)\n                )\n            ) {\n                returndatacopy(m, 0x00, returndatasize())\n                revert(m, returndatasize())\n            }\n            mstore(0x40, m) // Restore the free memory pointer.\n            result := mload(0x00)\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 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 Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`.\n    /// Reverts if the target does not support the function correctly.\n    function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data)\n        private\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Prepare the calldata.\n            let m := mload(0x40)\n            let onERC721ReceivedSelector := 0x150b7a02\n            mstore(m, onERC721ReceivedSelector)\n            mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`.\n            mstore(add(m, 0x40), shr(96, shl(96, from)))\n            mstore(add(m, 0x60), id)\n            mstore(add(m, 0x80), 0x80)\n            let n := mload(data)\n            mstore(add(m, 0xa0), n)\n            if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) }\n            // Revert if the call reverts.\n            if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) {\n                if returndatasize() {\n                    // Bubble up the revert if the call reverts.\n                    returndatacopy(m, 0x00, returndatasize())\n                    revert(m, returndatasize())\n                }\n            }\n            // Load the returndata and compare it.\n            if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {\n                mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/Strings.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toString(int256 value) internal pure returns (string memory) {\n        return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value))));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return keccak256(bytes(a)) == keccak256(bytes(b));\n    }\n}\n"
      },
      "src/BaseToken.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.23;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\n\nimport {IUniswapV2Router02} from \"@uniswap-periphery/interfaces/IUniswapV2Router02.sol\";\n\n/// @title BaseToken\n/// @notice A base contract for all tokens\nabstract contract BaseToken is ReentrancyGuard {\n    using SafeERC20 for IERC20;\n\n    address public immutable treasury;\n\n    IERC20 public immutable wnt;\n    IUniswapV2Router02 public immutable univ2router;\n\n    uint256 public constant SWAP_TAX = 225; // 0.25%\n    uint256 public constant PRECISION = 10000;\n\n    // ============================================================================================\n    // Constructor\n    // ============================================================================================\n\n    constructor(\n        IERC20 _wnt,\n        IUniswapV2Router02 _univ2router,\n        address _treasury\n    ) {\n        wnt = _wnt;\n        univ2router = _univ2router;\n\n        treasury = _treasury;\n\n        if (block.chainid == 252) {\n            // https://docs.frax.com/fraxtal/fraxtal-incentives/fraxtal-incentives-delegation#setting-delegations-for-smart-contracts\n            address _delegationRegistry = 0x4392dC16867D53DBFE227076606455634d4c2795;\n            _delegationRegistry.call(\n                abi.encodeWithSignature(\n                    \"setDelegationForSelf(address)\",\n                    _treasury\n                )\n            );\n            _delegationRegistry.call(\n                abi.encodeWithSignature(\"disableSelfManagingDelegations()\")\n            );\n        }\n    }\n\n    // ============================================================================================\n    // External Functions\n    // ============================================================================================\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "lib/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol": {
        "content": "pragma solidity >=0.6.2;\n\ninterface IUniswapV2Router01 {\n    function factory() external pure returns (address);\n    function WETH() external pure returns (address);\n\n    function addLiquidity(\n        address tokenA,\n        address tokenB,\n        uint amountADesired,\n        uint amountBDesired,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountA, uint amountB, uint liquidity);\n    function addLiquidityETH(\n        address token,\n        uint amountTokenDesired,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);\n    function removeLiquidity(\n        address tokenA,\n        address tokenB,\n        uint liquidity,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountA, uint amountB);\n    function removeLiquidityETH(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountToken, uint amountETH);\n    function removeLiquidityWithPermit(\n        address tokenA,\n        address tokenB,\n        uint liquidity,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountA, uint amountB);\n    function removeLiquidityETHWithPermit(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountToken, uint amountETH);\n    function swapExactTokensForTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n    function swapTokensForExactTokens(\n        uint amountOut,\n        uint amountInMax,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)\n        external\n        payable\n        returns (uint[] memory amounts);\n    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)\n        external\n        returns (uint[] memory amounts);\n    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)\n        external\n        returns (uint[] memory amounts);\n    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)\n        external\n        payable\n        returns (uint[] memory amounts);\n\n    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);\n    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);\n    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);\n    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);\n    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "forge-std/=lib/forge-std/src/",
        "@openzeppelin/=lib/openzeppelin-contracts/",
        "@vectorized/=lib/dn404/src/",
        "@uniswap-periphery/=lib/v2-periphery/contracts/",
        "@uniswap-core/=lib/v2-core/contracts/",
        "dn404/=lib/dn404/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
        "murky/=lib/dn404/lib/murky/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/",
        "openzeppelin/=lib/openzeppelin-contracts/contracts/",
        "solady/=lib/dn404/lib/solady/src/",
        "v2-core/=lib/v2-core/contracts/",
        "v2-periphery/=lib/v2-periphery/contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "viaIR": false,
      "libraries": {}
    }
  }}