creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "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 baseERC20;\n        address deployer;\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 result) {\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 result) {\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 result) {\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 result) {\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 result) {\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 result) {\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 result) {\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 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(\n                    gt(returndatasize(), 0x1f),\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(eq(mload(0x00), 1), call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20))\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 result)\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 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(eq(mload(m), 1), call(gas(), base, callvalue(), add(m, 0x1c), 0x84, m, 0x20))\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\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        virtual\n    {\n        transferFrom(from, to, id);\n\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 {\n        address newOwner;\n        address base = baseERC20();\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, 0x8da5cb5b) // `owner()`.\n            if and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x04, 0x00, 0x20)) {\n                newOwner := shr(96, mload(0x0c))\n            }\n        }\n        DN404NFTStorage storage $ = _getDN404NFTStorage();\n        address oldOwner = $.owner;\n        if (oldOwner != newOwner) {\n            $.owner = newOwner;\n            emit OwnershipTransferred(oldOwner, newOwner);\n        }\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\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\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            mstore(0x40, add(add(result, 0x20), mload(result))) // 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(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x44, 0x00, 0x20))\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"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}