{"sources":{"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 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 by 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        ownerOf(id); // `ownerOf` reverts if the token does not exist.\n        // We'll leave if optional for `_tokenURI` to revert for non-existent token\n        // on the ERC20 side, since this is only recommended by the ERC721 standard.\n        return _readString(0xcb30b460, id); // `tokenURINFT(uint256)`.\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(0x2d8a746e, id, 0))); // `ownerOfNFT(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(0xc016aa52, id, 0))); // `ownerAtNFT(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(0x27ef5495, id, 0))); // `getApprovedNFT(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, 0xf6916ddd) // `setApprovalForAllNFT(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        // `isApprovedForAllNFT(address,address)`.\n        return _readWord(0x62fb246d, 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        bytes calldata emptyData;\n        /// @solidity memory-safe-assembly\n        assembly {\n            emptyData.length := 0\n        }\n        safeTransferFrom(from, to, id, emptyData);\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        /// @solidity memory-safe-assembly\n        assembly {\n            if extcodesize(to) {\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                mstore(add(m, 0xa0), data.length)\n                calldatacopy(add(m, 0xc0), data.offset, data.length)\n                // Revert if the call reverts.\n                if iszero(call(gas(), to, 0, add(m, 0x1c), add(data.length, 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\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        uint32 baseOwnerFunctionSelector = uint32(_baseOwnerFunctionSelector());\n        DN404NFTStorage storage $ = _getDN404NFTStorage();\n        address oldOwner = $.owner;\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, baseOwnerFunctionSelector)\n            let success := staticcall(gas(), base, 0x1c, 0x04, 0x00, 0x20)\n            newOwner := mul(shr(96, mload(0x0c)), and(gt(returndatasize(), 0x1f), success))\n            if iszero(success) { if shl(96, oldOwner) { revert(0x00, 0x00) } }\n        }\n        if (oldOwner != newOwner) {\n            $.owner = newOwner;\n            emit OwnershipTransferred(oldOwner, newOwner);\n        }\n        return true;\n    }\n\n    /// @dev Override to allow for a different function selector on `baseERC20`.\n    function _baseOwnerFunctionSelector() internal view virtual returns (bytes4) {\n        return 0x8da5cb5b; // `owner()`.\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)) _rv(uint32(NotLinked.selector));\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) _rv(uint32(SenderNotBase.selector));\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) _rv(uint32(SenderNotBase.selector));\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                    _rv(uint32(SenderNotDeployer.selector));\n                }\n            }\n            if ($.baseERC20 != address(0)) _rv(uint32(AlreadyLinked.selector));\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        _rv(uint32(FnSelectorNotRecognized.selector)); // 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 More bytecode-efficient way to revert.\n    function _rv(uint32 s) private pure {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, s)\n            revert(0x1c, 0x04)\n        }\n    }\n}\n"}},"abi":[{"type":"constructor","inputs":[{"name":"deployer","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"name":"AlreadyLinked","type":"error","inputs":[]},{"name":"FnSelectorNotRecognized","type":"error","inputs":[]},{"name":"NotLinked","type":"error","inputs":[]},{"name":"SenderNotBase","type":"error","inputs":[]},{"name":"SenderNotDeployer","type":"error","inputs":[]},{"name":"TransferToNonERC721ReceiverImplementer","type":"error","inputs":[]},{"name":"Approval","type":"event","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"account","type":"address","indexed":true,"internalType":"address"},{"name":"id","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"name":"ApprovalForAll","type":"event","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"operator","type":"address","indexed":true,"internalType":"address"},{"name":"isApproved","type":"bool","indexed":false,"internalType":"bool"}],"anonymous":false},{"name":"OwnershipTransferred","type":"event","inputs":[{"name":"oldOwner","type":"address","indexed":true,"internalType":"address"},{"name":"newOwner","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"name":"Transfer","type":"event","inputs":[{"name":"from","type":"address","indexed":true,"internalType":"address"},{"name":"to","type":"address","indexed":true,"internalType":"address"},{"name":"id","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"fallback","stateMutability":"payable"},{"name":"approve","type":"function","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"name":"balanceOf","type":"function","inputs":[{"name":"nftOwner","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"baseERC20","type":"function","inputs":[],"outputs":[{"name":"base","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"getApproved","type":"function","inputs":[{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"isApprovedForAll","type":"function","inputs":[{"name":"nftOwner","type":"address","internalType":"address"},{"name":"operator","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"name","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"owner","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"ownerAt","type":"function","inputs":[{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"ownerOf","type":"function","inputs":[{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"pullOwner","type":"function","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"name":"safeTransferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"name":"safeTransferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"id","type":"uint256","internalType":"uint256"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"name":"setApprovalForAll","type":"function","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"approved","type":"bool","internalType":"bool"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"supportsInterface","type":"function","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"result","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"symbol","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"tokenURI","type":"function","inputs":[{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"totalSupply","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"transferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"id","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"type":"receive","stateMutability":"payable"}],"matchId":"58051315","creationMatch":"exact_match","runtimeMatch":"exact_match","verifiedAt":"2026-11-02T07:52:39Z","match":"exact_match","chainId":"56","address":"0xB61b93704ae5c1d1D48Cd97A18D78F23a4912b07"}