ETH Price: $2,561.89 (-2.14%)

Transaction Decoder

Block:
20793474 at Sep-20-2024 06:04:47 PM +UTC
Transaction Fee:
0.00083953272721312 ETH $2.15
Gas Used:
58,105 Gas / 14.448545344 Gwei

Emitted Events:

297 PublicResolver.AddressChanged( node=77563133045982C78468EDDFC8637D2E4F3B8950F5B8C6617BFE59ABC4869F97, coinType=60, newAddress=[Sender] 0x2b2b623d5b40e8d5d0932abf4bb383b2b42f69c5 )
298 PublicResolver.AddrChanged( node=77563133045982C78468EDDFC8637D2E4F3B8950F5B8C6617BFE59ABC4869F97, a=[Sender] 0x2b2b623d5b40e8d5d0932abf4bb383b2b42f69c5 )

Account State Difference:

  Address   Before After State Difference Code
0x231b0Ee1...4EB5E8E63
(ENS: Public Resolver)
0x2b2b623D...2b42f69C5
0.072184786385328755 Eth
Nonce: 1459
0.071345253658115635 Eth
Nonce: 1460
0.00083953272721312
(beaverbuild)
14.332732683512743897 Eth14.332738145382743897 Eth0.00000546187

Execution Trace

PublicResolver.setAddr( node=77563133045982C78468EDDFC8637D2E4F3B8950F5B8C6617BFE59ABC4869F97, coinType=60, a=0x2B2B623D5B40E8D5D0932ABF4BB383B2B42F69C5 )
  • ENSRegistryWithFallback.owner( node=77563133045982C78468EDDFC8637D2E4F3B8950F5B8C6617BFE59ABC4869F97 ) => ( 0x2b2b623D5B40e8d5d0932ABF4Bb383B2b42f69C5 )
    File 1 of 2: PublicResolver
    // SPDX-License-Identifier: BSD-2-Clause
    pragma solidity ^0.8.4;
    /**
    * @dev A library for working with mutable byte buffers in Solidity.
    *
    * Byte buffers are mutable and expandable, and provide a variety of primitives
    * for appending to them. At any time you can fetch a bytes object containing the
    * current contents of the buffer. The bytes object should not be stored between
    * operations, as it may change due to resizing of the buffer.
    */
    library Buffer {
        /**
        * @dev Represents a mutable buffer. Buffers have a current value (buf) and
        *      a capacity. The capacity may be longer than the current value, in
        *      which case it can be extended without the need to allocate more memory.
        */
        struct buffer {
            bytes buf;
            uint capacity;
        }
        /**
        * @dev Initializes a buffer with an initial capacity.
        * @param buf The buffer to initialize.
        * @param capacity The number of bytes of space to allocate the buffer.
        * @return The buffer, for chaining.
        */
        function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
            if (capacity % 32 != 0) {
                capacity += 32 - (capacity % 32);
            }
            // Allocate space for the buffer data
            buf.capacity = capacity;
            assembly {
                let ptr := mload(0x40)
                mstore(buf, ptr)
                mstore(ptr, 0)
                let fpm := add(32, add(ptr, capacity))
                if lt(fpm, ptr) {
                    revert(0, 0)
                }
                mstore(0x40, fpm)
            }
            return buf;
        }
        /**
        * @dev Initializes a new buffer from an existing bytes object.
        *      Changes to the buffer may mutate the original value.
        * @param b The bytes object to initialize the buffer with.
        * @return A new buffer.
        */
        function fromBytes(bytes memory b) internal pure returns(buffer memory) {
            buffer memory buf;
            buf.buf = b;
            buf.capacity = b.length;
            return buf;
        }
        function resize(buffer memory buf, uint capacity) private pure {
            bytes memory oldbuf = buf.buf;
            init(buf, capacity);
            append(buf, oldbuf);
        }
        /**
        * @dev Sets buffer length to 0.
        * @param buf The buffer to truncate.
        * @return The original buffer, for chaining..
        */
        function truncate(buffer memory buf) internal pure returns (buffer memory) {
            assembly {
                let bufptr := mload(buf)
                mstore(bufptr, 0)
            }
            return buf;
        }
        /**
        * @dev Appends len bytes of a byte string to a buffer. Resizes if doing so would exceed
        *      the capacity of the buffer.
        * @param buf The buffer to append to.
        * @param data The data to append.
        * @param len The number of bytes to copy.
        * @return The original buffer, for chaining.
        */
        function append(buffer memory buf, bytes memory data, uint len) internal pure returns(buffer memory) {
            require(len <= data.length);
            uint off = buf.buf.length;
            uint newCapacity = off + len;
            if (newCapacity > buf.capacity) {
                resize(buf, newCapacity * 2);
            }
            uint dest;
            uint src;
            assembly {
                // Memory address of the buffer data
                let bufptr := mload(buf)
                // Length of existing buffer data
                let buflen := mload(bufptr)
                // Start address = buffer address + offset + sizeof(buffer length)
                dest := add(add(bufptr, 32), off)
                // Update buffer length if we're extending it
                if gt(newCapacity, buflen) {
                    mstore(bufptr, newCapacity)
                }
                src := add(data, 32)
            }
            // Copy word-length chunks while possible
            for (; len >= 32; len -= 32) {
                assembly {
                    mstore(dest, mload(src))
                }
                dest += 32;
                src += 32;
            }
            // Copy remaining bytes
            unchecked {
                uint mask = (256 ** (32 - len)) - 1;
                assembly {
                    let srcpart := and(mload(src), not(mask))
                    let destpart := and(mload(dest), mask)
                    mstore(dest, or(destpart, srcpart))
                }
            }
            return buf;
        }
        /**
        * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
        *      the capacity of the buffer.
        * @param buf The buffer to append to.
        * @param data The data to append.
        * @return The original buffer, for chaining.
        */
        function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
            return append(buf, data, data.length);
        }
        /**
        * @dev Appends a byte to the buffer. Resizes if doing so would exceed the
        *      capacity of the buffer.
        * @param buf The buffer to append to.
        * @param data The data to append.
        * @return The original buffer, for chaining.
        */
        function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {
            uint off = buf.buf.length;
            uint offPlusOne = off + 1;
            if (off >= buf.capacity) {
                resize(buf, offPlusOne * 2);
            }
            assembly {
                // Memory address of the buffer data
                let bufptr := mload(buf)
                // Address = buffer address + sizeof(buffer length) + off
                let dest := add(add(bufptr, off), 32)
                mstore8(dest, data)
                // Update buffer length if we extended it
                if gt(offPlusOne, mload(bufptr)) {
                    mstore(bufptr, offPlusOne)
                }
            }
            return buf;
        }
        /**
        * @dev Appends len bytes of bytes32 to a buffer. Resizes if doing so would
        *      exceed the capacity of the buffer.
        * @param buf The buffer to append to.
        * @param data The data to append.
        * @param len The number of bytes to write (left-aligned).
        * @return The original buffer, for chaining.
        */
        function append(buffer memory buf, bytes32 data, uint len) private pure returns(buffer memory) {
            uint off = buf.buf.length;
            uint newCapacity = len + off;
            if (newCapacity > buf.capacity) {
                resize(buf, newCapacity * 2);
            }
            unchecked {
                uint mask = (256 ** len) - 1;
                // Right-align data
                data = data >> (8 * (32 - len));
                assembly {
                    // Memory address of the buffer data
                    let bufptr := mload(buf)
                    // Address = buffer address + sizeof(buffer length) + newCapacity
                    let dest := add(bufptr, newCapacity)
                    mstore(dest, or(and(mload(dest), not(mask)), data))
                    // Update buffer length if we extended it
                    if gt(newCapacity, mload(bufptr)) {
                        mstore(bufptr, newCapacity)
                    }
                }
            }
            return buf;
        }
        /**
        * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
        *      the capacity of the buffer.
        * @param buf The buffer to append to.
        * @param data The data to append.
        * @return The original buffer, for chhaining.
        */
        function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
            return append(buf, bytes32(data), 20);
        }
        /**
        * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
        *      the capacity of the buffer.
        * @param buf The buffer to append to.
        * @param data The data to append.
        * @return The original buffer, for chaining.
        */
        function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
            return append(buf, data, 32);
        }
        /**
         * @dev Appends a byte to the end of the buffer. Resizes if doing so would
         *      exceed the capacity of the buffer.
         * @param buf The buffer to append to.
         * @param data The data to append.
         * @param len The number of bytes to write (right-aligned).
         * @return The original buffer.
         */
        function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
            uint off = buf.buf.length;
            uint newCapacity = len + off;
            if (newCapacity > buf.capacity) {
                resize(buf, newCapacity * 2);
            }
            uint mask = (256 ** len) - 1;
            assembly {
                // Memory address of the buffer data
                let bufptr := mload(buf)
                // Address = buffer address + sizeof(buffer length) + newCapacity
                let dest := add(bufptr, newCapacity)
                mstore(dest, or(and(mload(dest), not(mask)), data))
                // Update buffer length if we extended it
                if gt(newCapacity, mload(bufptr)) {
                    mstore(bufptr, newCapacity)
                }
            }
            return buf;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
    pragma solidity ^0.8.0;
    import "../../utils/introspection/IERC165.sol";
    /**
     * @dev Required interface of an ERC1155 compliant contract, as defined in the
     * https://eips.ethereum.org/EIPS/eip-1155[EIP].
     *
     * _Available since v3.1._
     */
    interface IERC1155 is IERC165 {
        /**
         * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
         */
        event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
        /**
         * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
         * transfers.
         */
        event TransferBatch(
            address indexed operator,
            address indexed from,
            address indexed to,
            uint256[] ids,
            uint256[] values
        );
        /**
         * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
         * `approved`.
         */
        event ApprovalForAll(address indexed account, address indexed operator, bool approved);
        /**
         * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
         *
         * If an {URI} event was emitted for `id`, the standard
         * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
         * returned by {IERC1155MetadataURI-uri}.
         */
        event URI(string value, uint256 indexed id);
        /**
         * @dev Returns the amount of tokens of token type `id` owned by `account`.
         *
         * Requirements:
         *
         * - `account` cannot be the zero address.
         */
        function balanceOf(address account, uint256 id) external view returns (uint256);
        /**
         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
         *
         * Requirements:
         *
         * - `accounts` and `ids` must have the same length.
         */
        function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
            external
            view
            returns (uint256[] memory);
        /**
         * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
         *
         * Emits an {ApprovalForAll} event.
         *
         * Requirements:
         *
         * - `operator` cannot be the caller.
         */
        function setApprovalForAll(address operator, bool approved) external;
        /**
         * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
         *
         * See {setApprovalForAll}.
         */
        function isApprovedForAll(address account, address operator) external view returns (bool);
        /**
         * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
         *
         * Emits a {TransferSingle} event.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
         * - `from` must have a balance of tokens of type `id` of at least `amount`.
         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
         * acceptance magic value.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 id,
            uint256 amount,
            bytes calldata data
        ) external;
        /**
         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
         *
         * Emits a {TransferBatch} event.
         *
         * Requirements:
         *
         * - `ids` and `amounts` must have the same length.
         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
         * acceptance magic value.
         */
        function safeBatchTransferFrom(
            address from,
            address to,
            uint256[] calldata ids,
            uint256[] calldata amounts,
            bytes calldata data
        ) external;
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
    pragma solidity ^0.8.0;
    import "../../utils/introspection/IERC165.sol";
    /**
     * @dev Required interface of an ERC721 compliant contract.
     */
    interface IERC721 is IERC165 {
        /**
         * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
         */
        event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
        /**
         * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
         */
        event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
        /**
         * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
         */
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
        /**
         * @dev Returns the number of tokens in ``owner``'s account.
         */
        function balanceOf(address owner) external view returns (uint256 balance);
        /**
         * @dev Returns the owner of the `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function ownerOf(uint256 tokenId) external view returns (address owner);
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId,
            bytes calldata data
        ) external;
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
         * are aware of the ERC721 protocol to prevent tokens from being forever locked.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) external;
        /**
         * @dev Transfers `tokenId` token from `from` to `to`.
         *
         * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
         * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
         * understand this adds an external call which potentially creates a reentrancy vulnerability.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(
            address from,
            address to,
            uint256 tokenId
        ) external;
        /**
         * @dev Gives permission to `to` to transfer `tokenId` token to another account.
         * The approval is cleared when the token is transferred.
         *
         * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
         *
         * Requirements:
         *
         * - The caller must own the token or be an approved operator.
         * - `tokenId` must exist.
         *
         * Emits an {Approval} event.
         */
        function approve(address to, uint256 tokenId) external;
        /**
         * @dev Approve or remove `operator` as an operator for the caller.
         * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
         *
         * Requirements:
         *
         * - The `operator` cannot be the caller.
         *
         * Emits an {ApprovalForAll} event.
         */
        function setApprovalForAll(address operator, bool _approved) external;
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId) external view returns (address operator);
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}
         */
        function isApprovedForAll(address owner, address operator) external view returns (bool);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
    pragma solidity ^0.8.0;
    import "./IERC165.sol";
    /**
     * @dev Implementation of the {IERC165} interface.
     *
     * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
     * for the additional interface id that will be supported. For example:
     *
     * ```solidity
     * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
     *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
     * }
     * ```
     *
     * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
     */
    abstract contract ERC165 is IERC165 {
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            return interfaceId == type(IERC165).interfaceId;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    pragma solidity ^0.8.4;
    library BytesUtils {
        error OffsetOutOfBoundsError(uint256 offset, uint256 length);
        /*
         * @dev Returns the keccak-256 hash of a byte range.
         * @param self The byte string to hash.
         * @param offset The position to start hashing at.
         * @param len The number of bytes to hash.
         * @return The hash of the byte range.
         */
        function keccak(
            bytes memory self,
            uint256 offset,
            uint256 len
        ) internal pure returns (bytes32 ret) {
            require(offset + len <= self.length);
            assembly {
                ret := keccak256(add(add(self, 32), offset), len)
            }
        }
        /*
         * @dev Returns a positive number if `other` comes lexicographically after
         *      `self`, a negative number if it comes before, or zero if the
         *      contents of the two bytes are equal.
         * @param self The first bytes to compare.
         * @param other The second bytes to compare.
         * @return The result of the comparison.
         */
        function compare(
            bytes memory self,
            bytes memory other
        ) internal pure returns (int256) {
            return compare(self, 0, self.length, other, 0, other.length);
        }
        /*
         * @dev Returns a positive number if `other` comes lexicographically after
         *      `self`, a negative number if it comes before, or zero if the
         *      contents of the two bytes are equal. Comparison is done per-rune,
         *      on unicode codepoints.
         * @param self The first bytes to compare.
         * @param offset The offset of self.
         * @param len    The length of self.
         * @param other The second bytes to compare.
         * @param otheroffset The offset of the other string.
         * @param otherlen    The length of the other string.
         * @return The result of the comparison.
         */
        function compare(
            bytes memory self,
            uint256 offset,
            uint256 len,
            bytes memory other,
            uint256 otheroffset,
            uint256 otherlen
        ) internal pure returns (int256) {
            if (offset + len > self.length) {
                revert OffsetOutOfBoundsError(offset + len, self.length);
            }
            if (otheroffset + otherlen > other.length) {
                revert OffsetOutOfBoundsError(otheroffset + otherlen, other.length);
            }
            uint256 shortest = len;
            if (otherlen < len) shortest = otherlen;
            uint256 selfptr;
            uint256 otherptr;
            assembly {
                selfptr := add(self, add(offset, 32))
                otherptr := add(other, add(otheroffset, 32))
            }
            for (uint256 idx = 0; idx < shortest; idx += 32) {
                uint256 a;
                uint256 b;
                assembly {
                    a := mload(selfptr)
                    b := mload(otherptr)
                }
                if (a != b) {
                    // Mask out irrelevant bytes and check again
                    uint256 mask;
                    if (shortest - idx >= 32) {
                        mask = type(uint256).max;
                    } else {
                        mask = ~(2 ** (8 * (idx + 32 - shortest)) - 1);
                    }
                    int256 diff = int256(a & mask) - int256(b & mask);
                    if (diff != 0) return diff;
                }
                selfptr += 32;
                otherptr += 32;
            }
            return int256(len) - int256(otherlen);
        }
        /*
         * @dev Returns true if the two byte ranges are equal.
         * @param self The first byte range to compare.
         * @param offset The offset into the first byte range.
         * @param other The second byte range to compare.
         * @param otherOffset The offset into the second byte range.
         * @param len The number of bytes to compare
         * @return True if the byte ranges are equal, false otherwise.
         */
        function equals(
            bytes memory self,
            uint256 offset,
            bytes memory other,
            uint256 otherOffset,
            uint256 len
        ) internal pure returns (bool) {
            return keccak(self, offset, len) == keccak(other, otherOffset, len);
        }
        /*
         * @dev Returns true if the two byte ranges are equal with offsets.
         * @param self The first byte range to compare.
         * @param offset The offset into the first byte range.
         * @param other The second byte range to compare.
         * @param otherOffset The offset into the second byte range.
         * @return True if the byte ranges are equal, false otherwise.
         */
        function equals(
            bytes memory self,
            uint256 offset,
            bytes memory other,
            uint256 otherOffset
        ) internal pure returns (bool) {
            return
                keccak(self, offset, self.length - offset) ==
                keccak(other, otherOffset, other.length - otherOffset);
        }
        /*
         * @dev Compares a range of 'self' to all of 'other' and returns True iff
         *      they are equal.
         * @param self The first byte range to compare.
         * @param offset The offset into the first byte range.
         * @param other The second byte range to compare.
         * @return True if the byte ranges are equal, false otherwise.
         */
        function equals(
            bytes memory self,
            uint256 offset,
            bytes memory other
        ) internal pure returns (bool) {
            return
                self.length == offset + other.length &&
                equals(self, offset, other, 0, other.length);
        }
        /*
         * @dev Returns true if the two byte ranges are equal.
         * @param self The first byte range to compare.
         * @param other The second byte range to compare.
         * @return True if the byte ranges are equal, false otherwise.
         */
        function equals(
            bytes memory self,
            bytes memory other
        ) internal pure returns (bool) {
            return
                self.length == other.length &&
                equals(self, 0, other, 0, self.length);
        }
        /*
         * @dev Returns the 8-bit number at the specified index of self.
         * @param self The byte string.
         * @param idx The index into the bytes
         * @return The specified 8 bits of the string, interpreted as an integer.
         */
        function readUint8(
            bytes memory self,
            uint256 idx
        ) internal pure returns (uint8 ret) {
            return uint8(self[idx]);
        }
        /*
         * @dev Returns the 16-bit number at the specified index of self.
         * @param self The byte string.
         * @param idx The index into the bytes
         * @return The specified 16 bits of the string, interpreted as an integer.
         */
        function readUint16(
            bytes memory self,
            uint256 idx
        ) internal pure returns (uint16 ret) {
            require(idx + 2 <= self.length);
            assembly {
                ret := and(mload(add(add(self, 2), idx)), 0xFFFF)
            }
        }
        /*
         * @dev Returns the 32-bit number at the specified index of self.
         * @param self The byte string.
         * @param idx The index into the bytes
         * @return The specified 32 bits of the string, interpreted as an integer.
         */
        function readUint32(
            bytes memory self,
            uint256 idx
        ) internal pure returns (uint32 ret) {
            require(idx + 4 <= self.length);
            assembly {
                ret := and(mload(add(add(self, 4), idx)), 0xFFFFFFFF)
            }
        }
        /*
         * @dev Returns the 32 byte value at the specified index of self.
         * @param self The byte string.
         * @param idx The index into the bytes
         * @return The specified 32 bytes of the string.
         */
        function readBytes32(
            bytes memory self,
            uint256 idx
        ) internal pure returns (bytes32 ret) {
            require(idx + 32 <= self.length);
            assembly {
                ret := mload(add(add(self, 32), idx))
            }
        }
        /*
         * @dev Returns the 32 byte value at the specified index of self.
         * @param self The byte string.
         * @param idx The index into the bytes
         * @return The specified 32 bytes of the string.
         */
        function readBytes20(
            bytes memory self,
            uint256 idx
        ) internal pure returns (bytes20 ret) {
            require(idx + 20 <= self.length);
            assembly {
                ret := and(
                    mload(add(add(self, 32), idx)),
                    0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000
                )
            }
        }
        /*
         * @dev Returns the n byte value at the specified index of self.
         * @param self The byte string.
         * @param idx The index into the bytes.
         * @param len The number of bytes.
         * @return The specified 32 bytes of the string.
         */
        function readBytesN(
            bytes memory self,
            uint256 idx,
            uint256 len
        ) internal pure returns (bytes32 ret) {
            require(len <= 32);
            require(idx + len <= self.length);
            assembly {
                let mask := not(sub(exp(256, sub(32, len)), 1))
                ret := and(mload(add(add(self, 32), idx)), mask)
            }
        }
        function memcpy(uint256 dest, uint256 src, uint256 len) private pure {
            // Copy word-length chunks while possible
            for (; len >= 32; len -= 32) {
                assembly {
                    mstore(dest, mload(src))
                }
                dest += 32;
                src += 32;
            }
            // Copy remaining bytes
            unchecked {
                uint256 mask = (256 ** (32 - len)) - 1;
                assembly {
                    let srcpart := and(mload(src), not(mask))
                    let destpart := and(mload(dest), mask)
                    mstore(dest, or(destpart, srcpart))
                }
            }
        }
        /*
         * @dev Copies a substring into a new byte string.
         * @param self The byte string to copy from.
         * @param offset The offset to start copying at.
         * @param len The number of bytes to copy.
         */
        function substring(
            bytes memory self,
            uint256 offset,
            uint256 len
        ) internal pure returns (bytes memory) {
            require(offset + len <= self.length);
            bytes memory ret = new bytes(len);
            uint256 dest;
            uint256 src;
            assembly {
                dest := add(ret, 32)
                src := add(add(self, 32), offset)
            }
            memcpy(dest, src, len);
            return ret;
        }
        // Maps characters from 0x30 to 0x7A to their base32 values.
        // 0xFF represents invalid characters in that range.
        bytes constant base32HexTable =
            hex"00010203040506070809FFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1FFFFFFFFFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1F";
        /**
         * @dev Decodes unpadded base32 data of up to one word in length.
         * @param self The data to decode.
         * @param off Offset into the string to start at.
         * @param len Number of characters to decode.
         * @return The decoded data, left aligned.
         */
        function base32HexDecodeWord(
            bytes memory self,
            uint256 off,
            uint256 len
        ) internal pure returns (bytes32) {
            require(len <= 52);
            uint256 ret = 0;
            uint8 decoded;
            for (uint256 i = 0; i < len; i++) {
                bytes1 char = self[off + i];
                require(char >= 0x30 && char <= 0x7A);
                decoded = uint8(base32HexTable[uint256(uint8(char)) - 0x30]);
                require(decoded <= 0x20);
                if (i == len - 1) {
                    break;
                }
                ret = (ret << 5) | decoded;
            }
            uint256 bitlen = len * 5;
            if (len % 8 == 0) {
                // Multiple of 8 characters, no padding
                ret = (ret << 5) | decoded;
            } else if (len % 8 == 2) {
                // Two extra characters - 1 byte
                ret = (ret << 3) | (decoded >> 2);
                bitlen -= 2;
            } else if (len % 8 == 4) {
                // Four extra characters - 2 bytes
                ret = (ret << 1) | (decoded >> 4);
                bitlen -= 4;
            } else if (len % 8 == 5) {
                // Five extra characters - 3 bytes
                ret = (ret << 4) | (decoded >> 1);
                bitlen -= 1;
            } else if (len % 8 == 7) {
                // Seven extra characters - 4 bytes
                ret = (ret << 2) | (decoded >> 3);
                bitlen -= 3;
            } else {
                revert();
            }
            return bytes32(ret << (256 - bitlen));
        }
        /**
         * @dev Finds the first occurrence of the byte `needle` in `self`.
         * @param self The string to search
         * @param off The offset to start searching at
         * @param len The number of bytes to search
         * @param needle The byte to search for
         * @return The offset of `needle` in `self`, or 2**256-1 if it was not found.
         */
        function find(
            bytes memory self,
            uint256 off,
            uint256 len,
            bytes1 needle
        ) internal pure returns (uint256) {
            for (uint256 idx = off; idx < off + len; idx++) {
                if (self[idx] == needle) {
                    return idx;
                }
            }
            return type(uint256).max;
        }
    }
    pragma solidity ^0.8.4;
    import "./BytesUtils.sol";
    import "@ensdomains/buffer/contracts/Buffer.sol";
    /**
     * @dev RRUtils is a library that provides utilities for parsing DNS resource records.
     */
    library RRUtils {
        using BytesUtils for *;
        using Buffer for *;
        /**
         * @dev Returns the number of bytes in the DNS name at 'offset' in 'self'.
         * @param self The byte array to read a name from.
         * @param offset The offset to start reading at.
         * @return The length of the DNS name at 'offset', in bytes.
         */
        function nameLength(
            bytes memory self,
            uint256 offset
        ) internal pure returns (uint256) {
            uint256 idx = offset;
            while (true) {
                assert(idx < self.length);
                uint256 labelLen = self.readUint8(idx);
                idx += labelLen + 1;
                if (labelLen == 0) {
                    break;
                }
            }
            return idx - offset;
        }
        /**
         * @dev Returns a DNS format name at the specified offset of self.
         * @param self The byte array to read a name from.
         * @param offset The offset to start reading at.
         * @return ret The name.
         */
        function readName(
            bytes memory self,
            uint256 offset
        ) internal pure returns (bytes memory ret) {
            uint256 len = nameLength(self, offset);
            return self.substring(offset, len);
        }
        /**
         * @dev Returns the number of labels in the DNS name at 'offset' in 'self'.
         * @param self The byte array to read a name from.
         * @param offset The offset to start reading at.
         * @return The number of labels in the DNS name at 'offset', in bytes.
         */
        function labelCount(
            bytes memory self,
            uint256 offset
        ) internal pure returns (uint256) {
            uint256 count = 0;
            while (true) {
                assert(offset < self.length);
                uint256 labelLen = self.readUint8(offset);
                offset += labelLen + 1;
                if (labelLen == 0) {
                    break;
                }
                count += 1;
            }
            return count;
        }
        uint256 constant RRSIG_TYPE = 0;
        uint256 constant RRSIG_ALGORITHM = 2;
        uint256 constant RRSIG_LABELS = 3;
        uint256 constant RRSIG_TTL = 4;
        uint256 constant RRSIG_EXPIRATION = 8;
        uint256 constant RRSIG_INCEPTION = 12;
        uint256 constant RRSIG_KEY_TAG = 16;
        uint256 constant RRSIG_SIGNER_NAME = 18;
        struct SignedSet {
            uint16 typeCovered;
            uint8 algorithm;
            uint8 labels;
            uint32 ttl;
            uint32 expiration;
            uint32 inception;
            uint16 keytag;
            bytes signerName;
            bytes data;
            bytes name;
        }
        function readSignedSet(
            bytes memory data
        ) internal pure returns (SignedSet memory self) {
            self.typeCovered = data.readUint16(RRSIG_TYPE);
            self.algorithm = data.readUint8(RRSIG_ALGORITHM);
            self.labels = data.readUint8(RRSIG_LABELS);
            self.ttl = data.readUint32(RRSIG_TTL);
            self.expiration = data.readUint32(RRSIG_EXPIRATION);
            self.inception = data.readUint32(RRSIG_INCEPTION);
            self.keytag = data.readUint16(RRSIG_KEY_TAG);
            self.signerName = readName(data, RRSIG_SIGNER_NAME);
            self.data = data.substring(
                RRSIG_SIGNER_NAME + self.signerName.length,
                data.length - RRSIG_SIGNER_NAME - self.signerName.length
            );
        }
        function rrs(
            SignedSet memory rrset
        ) internal pure returns (RRIterator memory) {
            return iterateRRs(rrset.data, 0);
        }
        /**
         * @dev An iterator over resource records.
         */
        struct RRIterator {
            bytes data;
            uint256 offset;
            uint16 dnstype;
            uint16 class;
            uint32 ttl;
            uint256 rdataOffset;
            uint256 nextOffset;
        }
        /**
         * @dev Begins iterating over resource records.
         * @param self The byte string to read from.
         * @param offset The offset to start reading at.
         * @return ret An iterator object.
         */
        function iterateRRs(
            bytes memory self,
            uint256 offset
        ) internal pure returns (RRIterator memory ret) {
            ret.data = self;
            ret.nextOffset = offset;
            next(ret);
        }
        /**
         * @dev Returns true iff there are more RRs to iterate.
         * @param iter The iterator to check.
         * @return True iff the iterator has finished.
         */
        function done(RRIterator memory iter) internal pure returns (bool) {
            return iter.offset >= iter.data.length;
        }
        /**
         * @dev Moves the iterator to the next resource record.
         * @param iter The iterator to advance.
         */
        function next(RRIterator memory iter) internal pure {
            iter.offset = iter.nextOffset;
            if (iter.offset >= iter.data.length) {
                return;
            }
            // Skip the name
            uint256 off = iter.offset + nameLength(iter.data, iter.offset);
            // Read type, class, and ttl
            iter.dnstype = iter.data.readUint16(off);
            off += 2;
            iter.class = iter.data.readUint16(off);
            off += 2;
            iter.ttl = iter.data.readUint32(off);
            off += 4;
            // Read the rdata
            uint256 rdataLength = iter.data.readUint16(off);
            off += 2;
            iter.rdataOffset = off;
            iter.nextOffset = off + rdataLength;
        }
        /**
         * @dev Returns the name of the current record.
         * @param iter The iterator.
         * @return A new bytes object containing the owner name from the RR.
         */
        function name(RRIterator memory iter) internal pure returns (bytes memory) {
            return
                iter.data.substring(
                    iter.offset,
                    nameLength(iter.data, iter.offset)
                );
        }
        /**
         * @dev Returns the rdata portion of the current record.
         * @param iter The iterator.
         * @return A new bytes object containing the RR's RDATA.
         */
        function rdata(
            RRIterator memory iter
        ) internal pure returns (bytes memory) {
            return
                iter.data.substring(
                    iter.rdataOffset,
                    iter.nextOffset - iter.rdataOffset
                );
        }
        uint256 constant DNSKEY_FLAGS = 0;
        uint256 constant DNSKEY_PROTOCOL = 2;
        uint256 constant DNSKEY_ALGORITHM = 3;
        uint256 constant DNSKEY_PUBKEY = 4;
        struct DNSKEY {
            uint16 flags;
            uint8 protocol;
            uint8 algorithm;
            bytes publicKey;
        }
        function readDNSKEY(
            bytes memory data,
            uint256 offset,
            uint256 length
        ) internal pure returns (DNSKEY memory self) {
            self.flags = data.readUint16(offset + DNSKEY_FLAGS);
            self.protocol = data.readUint8(offset + DNSKEY_PROTOCOL);
            self.algorithm = data.readUint8(offset + DNSKEY_ALGORITHM);
            self.publicKey = data.substring(
                offset + DNSKEY_PUBKEY,
                length - DNSKEY_PUBKEY
            );
        }
        uint256 constant DS_KEY_TAG = 0;
        uint256 constant DS_ALGORITHM = 2;
        uint256 constant DS_DIGEST_TYPE = 3;
        uint256 constant DS_DIGEST = 4;
        struct DS {
            uint16 keytag;
            uint8 algorithm;
            uint8 digestType;
            bytes digest;
        }
        function readDS(
            bytes memory data,
            uint256 offset,
            uint256 length
        ) internal pure returns (DS memory self) {
            self.keytag = data.readUint16(offset + DS_KEY_TAG);
            self.algorithm = data.readUint8(offset + DS_ALGORITHM);
            self.digestType = data.readUint8(offset + DS_DIGEST_TYPE);
            self.digest = data.substring(offset + DS_DIGEST, length - DS_DIGEST);
        }
        function isSubdomainOf(
            bytes memory self,
            bytes memory other
        ) internal pure returns (bool) {
            uint256 off = 0;
            uint256 counts = labelCount(self, 0);
            uint256 othercounts = labelCount(other, 0);
            while (counts > othercounts) {
                off = progress(self, off);
                counts--;
            }
            return self.equals(off, other, 0);
        }
        function compareNames(
            bytes memory self,
            bytes memory other
        ) internal pure returns (int256) {
            if (self.equals(other)) {
                return 0;
            }
            uint256 off;
            uint256 otheroff;
            uint256 prevoff;
            uint256 otherprevoff;
            uint256 counts = labelCount(self, 0);
            uint256 othercounts = labelCount(other, 0);
            // Keep removing labels from the front of the name until both names are equal length
            while (counts > othercounts) {
                prevoff = off;
                off = progress(self, off);
                counts--;
            }
            while (othercounts > counts) {
                otherprevoff = otheroff;
                otheroff = progress(other, otheroff);
                othercounts--;
            }
            // Compare the last nonequal labels to each other
            while (counts > 0 && !self.equals(off, other, otheroff)) {
                prevoff = off;
                off = progress(self, off);
                otherprevoff = otheroff;
                otheroff = progress(other, otheroff);
                counts -= 1;
            }
            if (off == 0) {
                return -1;
            }
            if (otheroff == 0) {
                return 1;
            }
            return
                self.compare(
                    prevoff + 1,
                    self.readUint8(prevoff),
                    other,
                    otherprevoff + 1,
                    other.readUint8(otherprevoff)
                );
        }
        /**
         * @dev Compares two serial numbers using RFC1982 serial number math.
         */
        function serialNumberGte(
            uint32 i1,
            uint32 i2
        ) internal pure returns (bool) {
            unchecked {
                return int32(i1) - int32(i2) >= 0;
            }
        }
        function progress(
            bytes memory body,
            uint256 off
        ) internal pure returns (uint256) {
            return off + 1 + body.readUint8(off);
        }
        /**
         * @dev Computes the keytag for a chunk of data.
         * @param data The data to compute a keytag for.
         * @return The computed key tag.
         */
        function computeKeytag(bytes memory data) internal pure returns (uint16) {
            /* This function probably deserves some explanation.
             * The DNSSEC keytag function is a checksum that relies on summing up individual bytes
             * from the input string, with some mild bitshifting. Here's a Naive solidity implementation:
             *
             *     function computeKeytag(bytes memory data) internal pure returns (uint16) {
             *         uint ac;
             *         for (uint i = 0; i < data.length; i++) {
             *             ac += i & 1 == 0 ? uint16(data.readUint8(i)) << 8 : data.readUint8(i);
             *         }
             *         return uint16(ac + (ac >> 16));
             *     }
             *
             * The EVM, with its 256 bit words, is exceedingly inefficient at doing byte-by-byte operations;
             * the code above, on reasonable length inputs, consumes over 100k gas. But we can make the EVM's
             * large words work in our favour.
             *
             * The code below works by treating the input as a series of 256 bit words. It first masks out
             * even and odd bytes from each input word, adding them to two separate accumulators `ac1` and `ac2`.
             * The bytes are separated by empty bytes, so as long as no individual sum exceeds 2^16-1, we're
             * effectively summing 16 different numbers with each EVM ADD opcode.
             *
             * Once it's added up all the inputs, it has to add all the 16 bit values in `ac1` and `ac2` together.
             * It does this using the same trick - mask out every other value, shift to align them, add them together.
             * After the first addition on both accumulators, there's enough room to add the two accumulators together,
             * and the remaining sums can be done just on ac1.
             */
            unchecked {
                require(data.length <= 8192, "Long keys not permitted");
                uint256 ac1;
                uint256 ac2;
                for (uint256 i = 0; i < data.length + 31; i += 32) {
                    uint256 word;
                    assembly {
                        word := mload(add(add(data, 32), i))
                    }
                    if (i + 32 > data.length) {
                        uint256 unused = 256 - (data.length - i) * 8;
                        word = (word >> unused) << unused;
                    }
                    ac1 +=
                        (word &
                            0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >>
                        8;
                    ac2 += (word &
                        0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF);
                }
                ac1 =
                    (ac1 &
                        0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) +
                    ((ac1 &
                        0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >>
                        16);
                ac2 =
                    (ac2 &
                        0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) +
                    ((ac2 &
                        0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >>
                        16);
                ac1 = (ac1 << 8) + ac2;
                ac1 =
                    (ac1 &
                        0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) +
                    ((ac1 &
                        0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >>
                        32);
                ac1 =
                    (ac1 &
                        0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) +
                    ((ac1 &
                        0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >>
                        64);
                ac1 =
                    (ac1 &
                        0x00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) +
                    (ac1 >> 128);
                ac1 += (ac1 >> 16) & 0xFFFF;
                return uint16(ac1);
            }
        }
    }
    import "../registry/ENS.sol";
    import "./IBaseRegistrar.sol";
    import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
    interface IBaseRegistrar is IERC721 {
        event ControllerAdded(address indexed controller);
        event ControllerRemoved(address indexed controller);
        event NameMigrated(
            uint256 indexed id,
            address indexed owner,
            uint256 expires
        );
        event NameRegistered(
            uint256 indexed id,
            address indexed owner,
            uint256 expires
        );
        event NameRenewed(uint256 indexed id, uint256 expires);
        // Authorises a controller, who can register and renew domains.
        function addController(address controller) external;
        // Revoke controller permission for an address.
        function removeController(address controller) external;
        // Set the resolver for the TLD this registrar manages.
        function setResolver(address resolver) external;
        // Returns the expiration timestamp of the specified label hash.
        function nameExpires(uint256 id) external view returns (uint256);
        // Returns true iff the specified name is available for registration.
        function available(uint256 id) external view returns (bool);
        /**
         * @dev Register a name.
         */
        function register(
            uint256 id,
            address owner,
            uint256 duration
        ) external returns (uint256);
        function renew(uint256 id, uint256 duration) external returns (uint256);
        /**
         * @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
         */
        function reclaim(uint256 id, address owner) external;
    }
    pragma solidity >=0.8.4;
    interface ENS {
        // Logged when the owner of a node assigns a new owner to a subnode.
        event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
        // Logged when the owner of a node transfers ownership to a new account.
        event Transfer(bytes32 indexed node, address owner);
        // Logged when the resolver for a node changes.
        event NewResolver(bytes32 indexed node, address resolver);
        // Logged when the TTL of a node changes
        event NewTTL(bytes32 indexed node, uint64 ttl);
        // Logged when an operator is added or removed.
        event ApprovalForAll(
            address indexed owner,
            address indexed operator,
            bool approved
        );
        function setRecord(
            bytes32 node,
            address owner,
            address resolver,
            uint64 ttl
        ) external;
        function setSubnodeRecord(
            bytes32 node,
            bytes32 label,
            address owner,
            address resolver,
            uint64 ttl
        ) external;
        function setSubnodeOwner(
            bytes32 node,
            bytes32 label,
            address owner
        ) external returns (bytes32);
        function setResolver(bytes32 node, address resolver) external;
        function setOwner(bytes32 node, address owner) external;
        function setTTL(bytes32 node, uint64 ttl) external;
        function setApprovalForAll(address operator, bool approved) external;
        function owner(bytes32 node) external view returns (address);
        function resolver(bytes32 node) external view returns (address);
        function ttl(bytes32 node) external view returns (uint64);
        function recordExists(bytes32 node) external view returns (bool);
        function isApprovedForAll(
            address owner,
            address operator
        ) external view returns (bool);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    interface IMulticallable {
        function multicall(
            bytes[] calldata data
        ) external returns (bytes[] memory results);
        function multicallWithNodeCheck(
            bytes32,
            bytes[] calldata data
        ) external returns (bytes[] memory results);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    import "./IMulticallable.sol";
    import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
    abstract contract Multicallable is IMulticallable, ERC165 {
        function _multicall(
            bytes32 nodehash,
            bytes[] calldata data
        ) internal returns (bytes[] memory results) {
            results = new bytes[](data.length);
            for (uint256 i = 0; i < data.length; i++) {
                if (nodehash != bytes32(0)) {
                    bytes32 txNamehash = bytes32(data[i][4:36]);
                    require(
                        txNamehash == nodehash,
                        "multicall: All records must have a matching namehash"
                    );
                }
                (bool success, bytes memory result) = address(this).delegatecall(
                    data[i]
                );
                require(success);
                results[i] = result;
            }
            return results;
        }
        // This function provides an extra security check when called
        // from priviledged contracts (such as EthRegistrarController)
        // that can set records on behalf of the node owners
        function multicallWithNodeCheck(
            bytes32 nodehash,
            bytes[] calldata data
        ) external returns (bytes[] memory results) {
            return _multicall(nodehash, data);
        }
        function multicall(
            bytes[] calldata data
        ) public override returns (bytes[] memory results) {
            return _multicall(bytes32(0), data);
        }
        function supportsInterface(
            bytes4 interfaceID
        ) public view virtual override returns (bool) {
            return
                interfaceID == type(IMulticallable).interfaceId ||
                super.supportsInterface(interfaceID);
        }
    }
    //SPDX-License-Identifier: MIT
    pragma solidity >=0.8.17 <0.9.0;
    import "../registry/ENS.sol";
    import "./profiles/ABIResolver.sol";
    import "./profiles/AddrResolver.sol";
    import "./profiles/ContentHashResolver.sol";
    import "./profiles/DNSResolver.sol";
    import "./profiles/InterfaceResolver.sol";
    import "./profiles/NameResolver.sol";
    import "./profiles/PubkeyResolver.sol";
    import "./profiles/TextResolver.sol";
    import "./Multicallable.sol";
    import {ReverseClaimer} from "../reverseRegistrar/ReverseClaimer.sol";
    import {INameWrapper} from "../wrapper/INameWrapper.sol";
    /**
     * A simple resolver anyone can use; only allows the owner of a node to set its
     * address.
     */
    contract PublicResolver is
        Multicallable,
        ABIResolver,
        AddrResolver,
        ContentHashResolver,
        DNSResolver,
        InterfaceResolver,
        NameResolver,
        PubkeyResolver,
        TextResolver,
        ReverseClaimer
    {
        ENS immutable ens;
        INameWrapper immutable nameWrapper;
        address immutable trustedETHController;
        address immutable trustedReverseRegistrar;
        /**
         * A mapping of operators. An address that is authorised for an address
         * may make any changes to the name that the owner could, but may not update
         * the set of authorisations.
         * (owner, operator) => approved
         */
        mapping(address => mapping(address => bool)) private _operatorApprovals;
        /**
         * A mapping of delegates. A delegate that is authorised by an owner
         * for a name may make changes to the name's resolver, but may not update
         * the set of token approvals.
         * (owner, name, delegate) => approved
         */
        mapping(address => mapping(bytes32 => mapping(address => bool)))
            private _tokenApprovals;
        // Logged when an operator is added or removed.
        event ApprovalForAll(
            address indexed owner,
            address indexed operator,
            bool approved
        );
        // Logged when a delegate is approved or  an approval is revoked.
        event Approved(
            address owner,
            bytes32 indexed node,
            address indexed delegate,
            bool indexed approved
        );
        constructor(
            ENS _ens,
            INameWrapper wrapperAddress,
            address _trustedETHController,
            address _trustedReverseRegistrar
        ) ReverseClaimer(_ens, msg.sender) {
            ens = _ens;
            nameWrapper = wrapperAddress;
            trustedETHController = _trustedETHController;
            trustedReverseRegistrar = _trustedReverseRegistrar;
        }
        /**
         * @dev See {IERC1155-setApprovalForAll}.
         */
        function setApprovalForAll(address operator, bool approved) external {
            require(
                msg.sender != operator,
                "ERC1155: setting approval status for self"
            );
            _operatorApprovals[msg.sender][operator] = approved;
            emit ApprovalForAll(msg.sender, operator, approved);
        }
        /**
         * @dev See {IERC1155-isApprovedForAll}.
         */
        function isApprovedForAll(
            address account,
            address operator
        ) public view returns (bool) {
            return _operatorApprovals[account][operator];
        }
        /**
         * @dev Approve a delegate to be able to updated records on a node.
         */
        function approve(bytes32 node, address delegate, bool approved) external {
            require(msg.sender != delegate, "Setting delegate status for self");
            _tokenApprovals[msg.sender][node][delegate] = approved;
            emit Approved(msg.sender, node, delegate, approved);
        }
        /**
         * @dev Check to see if the delegate has been approved by the owner for the node.
         */
        function isApprovedFor(
            address owner,
            bytes32 node,
            address delegate
        ) public view returns (bool) {
            return _tokenApprovals[owner][node][delegate];
        }
        function isAuthorised(bytes32 node) internal view override returns (bool) {
            if (
                msg.sender == trustedETHController ||
                msg.sender == trustedReverseRegistrar
            ) {
                return true;
            }
            address owner = ens.owner(node);
            if (owner == address(nameWrapper)) {
                owner = nameWrapper.ownerOf(uint256(node));
            }
            return
                owner == msg.sender ||
                isApprovedForAll(owner, msg.sender) ||
                isApprovedFor(owner, node, msg.sender);
        }
        function supportsInterface(
            bytes4 interfaceID
        )
            public
            view
            override(
                Multicallable,
                ABIResolver,
                AddrResolver,
                ContentHashResolver,
                DNSResolver,
                InterfaceResolver,
                NameResolver,
                PubkeyResolver,
                TextResolver
            )
            returns (bool)
        {
            return super.supportsInterface(interfaceID);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
    import "./profiles/IVersionableResolver.sol";
    abstract contract ResolverBase is ERC165, IVersionableResolver {
        mapping(bytes32 => uint64) public recordVersions;
        function isAuthorised(bytes32 node) internal view virtual returns (bool);
        modifier authorised(bytes32 node) {
            require(isAuthorised(node));
            _;
        }
        /**
         * Increments the record version associated with an ENS node.
         * May only be called by the owner of that node in the ENS registry.
         * @param node The node to update.
         */
        function clearRecords(bytes32 node) public virtual authorised(node) {
            recordVersions[node]++;
            emit VersionChanged(node, recordVersions[node]);
        }
        function supportsInterface(
            bytes4 interfaceID
        ) public view virtual override returns (bool) {
            return
                interfaceID == type(IVersionableResolver).interfaceId ||
                super.supportsInterface(interfaceID);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    import "./IABIResolver.sol";
    import "../ResolverBase.sol";
    abstract contract ABIResolver is IABIResolver, ResolverBase {
        mapping(uint64 => mapping(bytes32 => mapping(uint256 => bytes))) versionable_abis;
        /**
         * Sets the ABI associated with an ENS node.
         * Nodes may have one ABI of each content type. To remove an ABI, set it to
         * the empty string.
         * @param node The node to update.
         * @param contentType The content type of the ABI
         * @param data The ABI data.
         */
        function setABI(
            bytes32 node,
            uint256 contentType,
            bytes calldata data
        ) external virtual authorised(node) {
            // Content types must be powers of 2
            require(((contentType - 1) & contentType) == 0);
            versionable_abis[recordVersions[node]][node][contentType] = data;
            emit ABIChanged(node, contentType);
        }
        /**
         * Returns the ABI associated with an ENS node.
         * Defined in EIP205.
         * @param node The ENS node to query
         * @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
         * @return contentType The content type of the return value
         * @return data The ABI data
         */
        function ABI(
            bytes32 node,
            uint256 contentTypes
        ) external view virtual override returns (uint256, bytes memory) {
            mapping(uint256 => bytes) storage abiset = versionable_abis[
                recordVersions[node]
            ][node];
            for (
                uint256 contentType = 1;
                contentType <= contentTypes;
                contentType <<= 1
            ) {
                if (
                    (contentType & contentTypes) != 0 &&
                    abiset[contentType].length > 0
                ) {
                    return (contentType, abiset[contentType]);
                }
            }
            return (0, bytes(""));
        }
        function supportsInterface(
            bytes4 interfaceID
        ) public view virtual override returns (bool) {
            return
                interfaceID == type(IABIResolver).interfaceId ||
                super.supportsInterface(interfaceID);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    import "../ResolverBase.sol";
    import "./IAddrResolver.sol";
    import "./IAddressResolver.sol";
    abstract contract AddrResolver is
        IAddrResolver,
        IAddressResolver,
        ResolverBase
    {
        uint256 private constant COIN_TYPE_ETH = 60;
        mapping(uint64 => mapping(bytes32 => mapping(uint256 => bytes))) versionable_addresses;
        /**
         * Sets the address associated with an ENS node.
         * May only be called by the owner of that node in the ENS registry.
         * @param node The node to update.
         * @param a The address to set.
         */
        function setAddr(
            bytes32 node,
            address a
        ) external virtual authorised(node) {
            setAddr(node, COIN_TYPE_ETH, addressToBytes(a));
        }
        /**
         * Returns the address associated with an ENS node.
         * @param node The ENS node to query.
         * @return The associated address.
         */
        function addr(
            bytes32 node
        ) public view virtual override returns (address payable) {
            bytes memory a = addr(node, COIN_TYPE_ETH);
            if (a.length == 0) {
                return payable(0);
            }
            return bytesToAddress(a);
        }
        function setAddr(
            bytes32 node,
            uint256 coinType,
            bytes memory a
        ) public virtual authorised(node) {
            emit AddressChanged(node, coinType, a);
            if (coinType == COIN_TYPE_ETH) {
                emit AddrChanged(node, bytesToAddress(a));
            }
            versionable_addresses[recordVersions[node]][node][coinType] = a;
        }
        function addr(
            bytes32 node,
            uint256 coinType
        ) public view virtual override returns (bytes memory) {
            return versionable_addresses[recordVersions[node]][node][coinType];
        }
        function supportsInterface(
            bytes4 interfaceID
        ) public view virtual override returns (bool) {
            return
                interfaceID == type(IAddrResolver).interfaceId ||
                interfaceID == type(IAddressResolver).interfaceId ||
                super.supportsInterface(interfaceID);
        }
        function bytesToAddress(
            bytes memory b
        ) internal pure returns (address payable a) {
            require(b.length == 20);
            assembly {
                a := div(mload(add(b, 32)), exp(256, 12))
            }
        }
        function addressToBytes(address a) internal pure returns (bytes memory b) {
            b = new bytes(20);
            assembly {
                mstore(add(b, 32), mul(a, exp(256, 12)))
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    import "../ResolverBase.sol";
    import "./IContentHashResolver.sol";
    abstract contract ContentHashResolver is IContentHashResolver, ResolverBase {
        mapping(uint64 => mapping(bytes32 => bytes)) versionable_hashes;
        /**
         * Sets the contenthash associated with an ENS node.
         * May only be called by the owner of that node in the ENS registry.
         * @param node The node to update.
         * @param hash The contenthash to set
         */
        function setContenthash(
            bytes32 node,
            bytes calldata hash
        ) external virtual authorised(node) {
            versionable_hashes[recordVersions[node]][node] = hash;
            emit ContenthashChanged(node, hash);
        }
        /**
         * Returns the contenthash associated with an ENS node.
         * @param node The ENS node to query.
         * @return The associated contenthash.
         */
        function contenthash(
            bytes32 node
        ) external view virtual override returns (bytes memory) {
            return versionable_hashes[recordVersions[node]][node];
        }
        function supportsInterface(
            bytes4 interfaceID
        ) public view virtual override returns (bool) {
            return
                interfaceID == type(IContentHashResolver).interfaceId ||
                super.supportsInterface(interfaceID);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    import "../ResolverBase.sol";
    import "../../dnssec-oracle/RRUtils.sol";
    import "./IDNSRecordResolver.sol";
    import "./IDNSZoneResolver.sol";
    abstract contract DNSResolver is
        IDNSRecordResolver,
        IDNSZoneResolver,
        ResolverBase
    {
        using RRUtils for *;
        using BytesUtils for bytes;
        // Zone hashes for the domains.
        // A zone hash is an EIP-1577 content hash in binary format that should point to a
        // resource containing a single zonefile.
        // node => contenthash
        mapping(uint64 => mapping(bytes32 => bytes)) private versionable_zonehashes;
        // The records themselves.  Stored as binary RRSETs
        // node => version => name => resource => data
        mapping(uint64 => mapping(bytes32 => mapping(bytes32 => mapping(uint16 => bytes))))
            private versionable_records;
        // Count of number of entries for a given name.  Required for DNS resolvers
        // when resolving wildcards.
        // node => version => name => number of records
        mapping(uint64 => mapping(bytes32 => mapping(bytes32 => uint16)))
            private versionable_nameEntriesCount;
        /**
         * Set one or more DNS records.  Records are supplied in wire-format.
         * Records with the same node/name/resource must be supplied one after the
         * other to ensure the data is updated correctly. For example, if the data
         * was supplied:
         *     a.example.com IN A 1.2.3.4
         *     a.example.com IN A 5.6.7.8
         *     www.example.com IN CNAME a.example.com.
         * then this would store the two A records for a.example.com correctly as a
         * single RRSET, however if the data was supplied:
         *     a.example.com IN A 1.2.3.4
         *     www.example.com IN CNAME a.example.com.
         *     a.example.com IN A 5.6.7.8
         * then this would store the first A record, the CNAME, then the second A
         * record which would overwrite the first.
         *
         * @param node the namehash of the node for which to set the records
         * @param data the DNS wire format records to set
         */
        function setDNSRecords(
            bytes32 node,
            bytes calldata data
        ) external virtual authorised(node) {
            uint16 resource = 0;
            uint256 offset = 0;
            bytes memory name;
            bytes memory value;
            bytes32 nameHash;
            uint64 version = recordVersions[node];
            // Iterate over the data to add the resource records
            for (
                RRUtils.RRIterator memory iter = data.iterateRRs(0);
                !iter.done();
                iter.next()
            ) {
                if (resource == 0) {
                    resource = iter.dnstype;
                    name = iter.name();
                    nameHash = keccak256(abi.encodePacked(name));
                    value = bytes(iter.rdata());
                } else {
                    bytes memory newName = iter.name();
                    if (resource != iter.dnstype || !name.equals(newName)) {
                        setDNSRRSet(
                            node,
                            name,
                            resource,
                            data,
                            offset,
                            iter.offset - offset,
                            value.length == 0,
                            version
                        );
                        resource = iter.dnstype;
                        offset = iter.offset;
                        name = newName;
                        nameHash = keccak256(name);
                        value = bytes(iter.rdata());
                    }
                }
            }
            if (name.length > 0) {
                setDNSRRSet(
                    node,
                    name,
                    resource,
                    data,
                    offset,
                    data.length - offset,
                    value.length == 0,
                    version
                );
            }
        }
        /**
         * Obtain a DNS record.
         * @param node the namehash of the node for which to fetch the record
         * @param name the keccak-256 hash of the fully-qualified name for which to fetch the record
         * @param resource the ID of the resource as per https://en.wikipedia.org/wiki/List_of_DNS_record_types
         * @return the DNS record in wire format if present, otherwise empty
         */
        function dnsRecord(
            bytes32 node,
            bytes32 name,
            uint16 resource
        ) public view virtual override returns (bytes memory) {
            return versionable_records[recordVersions[node]][node][name][resource];
        }
        /**
         * Check if a given node has records.
         * @param node the namehash of the node for which to check the records
         * @param name the namehash of the node for which to check the records
         */
        function hasDNSRecords(
            bytes32 node,
            bytes32 name
        ) public view virtual returns (bool) {
            return (versionable_nameEntriesCount[recordVersions[node]][node][
                name
            ] != 0);
        }
        /**
         * setZonehash sets the hash for the zone.
         * May only be called by the owner of that node in the ENS registry.
         * @param node The node to update.
         * @param hash The zonehash to set
         */
        function setZonehash(
            bytes32 node,
            bytes calldata hash
        ) external virtual authorised(node) {
            uint64 currentRecordVersion = recordVersions[node];
            bytes memory oldhash = versionable_zonehashes[currentRecordVersion][
                node
            ];
            versionable_zonehashes[currentRecordVersion][node] = hash;
            emit DNSZonehashChanged(node, oldhash, hash);
        }
        /**
         * zonehash obtains the hash for the zone.
         * @param node The ENS node to query.
         * @return The associated contenthash.
         */
        function zonehash(
            bytes32 node
        ) external view virtual override returns (bytes memory) {
            return versionable_zonehashes[recordVersions[node]][node];
        }
        function supportsInterface(
            bytes4 interfaceID
        ) public view virtual override returns (bool) {
            return
                interfaceID == type(IDNSRecordResolver).interfaceId ||
                interfaceID == type(IDNSZoneResolver).interfaceId ||
                super.supportsInterface(interfaceID);
        }
        function setDNSRRSet(
            bytes32 node,
            bytes memory name,
            uint16 resource,
            bytes memory data,
            uint256 offset,
            uint256 size,
            bool deleteRecord,
            uint64 version
        ) private {
            bytes32 nameHash = keccak256(name);
            bytes memory rrData = data.substring(offset, size);
            if (deleteRecord) {
                if (
                    versionable_records[version][node][nameHash][resource].length !=
                    0
                ) {
                    versionable_nameEntriesCount[version][node][nameHash]--;
                }
                delete (versionable_records[version][node][nameHash][resource]);
                emit DNSRecordDeleted(node, name, resource);
            } else {
                if (
                    versionable_records[version][node][nameHash][resource].length ==
                    0
                ) {
                    versionable_nameEntriesCount[version][node][nameHash]++;
                }
                versionable_records[version][node][nameHash][resource] = rrData;
                emit DNSRecordChanged(node, name, resource, rrData);
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    interface IABIResolver {
        event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
        /**
         * Returns the ABI associated with an ENS node.
         * Defined in EIP205.
         * @param node The ENS node to query
         * @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
         * @return contentType The content type of the return value
         * @return data The ABI data
         */
        function ABI(
            bytes32 node,
            uint256 contentTypes
        ) external view returns (uint256, bytes memory);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    /**
     * Interface for the legacy (ETH-only) addr function.
     */
    interface IAddrResolver {
        event AddrChanged(bytes32 indexed node, address a);
        /**
         * Returns the address associated with an ENS node.
         * @param node The ENS node to query.
         * @return The associated address.
         */
        function addr(bytes32 node) external view returns (address payable);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    /**
     * Interface for the new (multicoin) addr function.
     */
    interface IAddressResolver {
        event AddressChanged(
            bytes32 indexed node,
            uint256 coinType,
            bytes newAddress
        );
        function addr(
            bytes32 node,
            uint256 coinType
        ) external view returns (bytes memory);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    interface IContentHashResolver {
        event ContenthashChanged(bytes32 indexed node, bytes hash);
        /**
         * Returns the contenthash associated with an ENS node.
         * @param node The ENS node to query.
         * @return The associated contenthash.
         */
        function contenthash(bytes32 node) external view returns (bytes memory);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    interface IDNSRecordResolver {
        // DNSRecordChanged is emitted whenever a given node/name/resource's RRSET is updated.
        event DNSRecordChanged(
            bytes32 indexed node,
            bytes name,
            uint16 resource,
            bytes record
        );
        // DNSRecordDeleted is emitted whenever a given node/name/resource's RRSET is deleted.
        event DNSRecordDeleted(bytes32 indexed node, bytes name, uint16 resource);
        /**
         * Obtain a DNS record.
         * @param node the namehash of the node for which to fetch the record
         * @param name the keccak-256 hash of the fully-qualified name for which to fetch the record
         * @param resource the ID of the resource as per https://en.wikipedia.org/wiki/List_of_DNS_record_types
         * @return the DNS record in wire format if present, otherwise empty
         */
        function dnsRecord(
            bytes32 node,
            bytes32 name,
            uint16 resource
        ) external view returns (bytes memory);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    interface IDNSZoneResolver {
        // DNSZonehashChanged is emitted whenever a given node's zone hash is updated.
        event DNSZonehashChanged(
            bytes32 indexed node,
            bytes lastzonehash,
            bytes zonehash
        );
        /**
         * zonehash obtains the hash for the zone.
         * @param node The ENS node to query.
         * @return The associated contenthash.
         */
        function zonehash(bytes32 node) external view returns (bytes memory);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    interface IInterfaceResolver {
        event InterfaceChanged(
            bytes32 indexed node,
            bytes4 indexed interfaceID,
            address implementer
        );
        /**
         * Returns the address of a contract that implements the specified interface for this name.
         * If an implementer has not been set for this interfaceID and name, the resolver will query
         * the contract at `addr()`. If `addr()` is set, a contract exists at that address, and that
         * contract implements EIP165 and returns `true` for the specified interfaceID, its address
         * will be returned.
         * @param node The ENS node to query.
         * @param interfaceID The EIP 165 interface ID to check for.
         * @return The address that implements this interface, or 0 if the interface is unsupported.
         */
        function interfaceImplementer(
            bytes32 node,
            bytes4 interfaceID
        ) external view returns (address);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    interface INameResolver {
        event NameChanged(bytes32 indexed node, string name);
        /**
         * Returns the name associated with an ENS node, for reverse records.
         * Defined in EIP181.
         * @param node The ENS node to query.
         * @return The associated name.
         */
        function name(bytes32 node) external view returns (string memory);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    interface IPubkeyResolver {
        event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
        /**
         * Returns the SECP256k1 public key associated with an ENS node.
         * Defined in EIP 619.
         * @param node The ENS node to query
         * @return x The X coordinate of the curve point for the public key.
         * @return y The Y coordinate of the curve point for the public key.
         */
        function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    interface ITextResolver {
        event TextChanged(
            bytes32 indexed node,
            string indexed indexedKey,
            string key,
            string value
        );
        /**
         * Returns the text data associated with an ENS node and key.
         * @param node The ENS node to query.
         * @param key The text data key to query.
         * @return The associated text data.
         */
        function text(
            bytes32 node,
            string calldata key
        ) external view returns (string memory);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    interface IVersionableResolver {
        event VersionChanged(bytes32 indexed node, uint64 newVersion);
        function recordVersions(bytes32 node) external view returns (uint64);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
    import "../ResolverBase.sol";
    import "./AddrResolver.sol";
    import "./IInterfaceResolver.sol";
    abstract contract InterfaceResolver is IInterfaceResolver, AddrResolver {
        mapping(uint64 => mapping(bytes32 => mapping(bytes4 => address))) versionable_interfaces;
        /**
         * Sets an interface associated with a name.
         * Setting the address to 0 restores the default behaviour of querying the contract at `addr()` for interface support.
         * @param node The node to update.
         * @param interfaceID The EIP 165 interface ID.
         * @param implementer The address of a contract that implements this interface for this node.
         */
        function setInterface(
            bytes32 node,
            bytes4 interfaceID,
            address implementer
        ) external virtual authorised(node) {
            versionable_interfaces[recordVersions[node]][node][
                interfaceID
            ] = implementer;
            emit InterfaceChanged(node, interfaceID, implementer);
        }
        /**
         * Returns the address of a contract that implements the specified interface for this name.
         * If an implementer has not been set for this interfaceID and name, the resolver will query
         * the contract at `addr()`. If `addr()` is set, a contract exists at that address, and that
         * contract implements EIP165 and returns `true` for the specified interfaceID, its address
         * will be returned.
         * @param node The ENS node to query.
         * @param interfaceID The EIP 165 interface ID to check for.
         * @return The address that implements this interface, or 0 if the interface is unsupported.
         */
        function interfaceImplementer(
            bytes32 node,
            bytes4 interfaceID
        ) external view virtual override returns (address) {
            address implementer = versionable_interfaces[recordVersions[node]][
                node
            ][interfaceID];
            if (implementer != address(0)) {
                return implementer;
            }
            address a = addr(node);
            if (a == address(0)) {
                return address(0);
            }
            (bool success, bytes memory returnData) = a.staticcall(
                abi.encodeWithSignature(
                    "supportsInterface(bytes4)",
                    type(IERC165).interfaceId
                )
            );
            if (!success || returnData.length < 32 || returnData[31] == 0) {
                // EIP 165 not supported by target
                return address(0);
            }
            (success, returnData) = a.staticcall(
                abi.encodeWithSignature("supportsInterface(bytes4)", interfaceID)
            );
            if (!success || returnData.length < 32 || returnData[31] == 0) {
                // Specified interface not supported by target
                return address(0);
            }
            return a;
        }
        function supportsInterface(
            bytes4 interfaceID
        ) public view virtual override returns (bool) {
            return
                interfaceID == type(IInterfaceResolver).interfaceId ||
                super.supportsInterface(interfaceID);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    import "../ResolverBase.sol";
    import "./INameResolver.sol";
    abstract contract NameResolver is INameResolver, ResolverBase {
        mapping(uint64 => mapping(bytes32 => string)) versionable_names;
        /**
         * Sets the name associated with an ENS node, for reverse records.
         * May only be called by the owner of that node in the ENS registry.
         * @param node The node to update.
         */
        function setName(
            bytes32 node,
            string calldata newName
        ) external virtual authorised(node) {
            versionable_names[recordVersions[node]][node] = newName;
            emit NameChanged(node, newName);
        }
        /**
         * Returns the name associated with an ENS node, for reverse records.
         * Defined in EIP181.
         * @param node The ENS node to query.
         * @return The associated name.
         */
        function name(
            bytes32 node
        ) external view virtual override returns (string memory) {
            return versionable_names[recordVersions[node]][node];
        }
        function supportsInterface(
            bytes4 interfaceID
        ) public view virtual override returns (bool) {
            return
                interfaceID == type(INameResolver).interfaceId ||
                super.supportsInterface(interfaceID);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    import "../ResolverBase.sol";
    import "./IPubkeyResolver.sol";
    abstract contract PubkeyResolver is IPubkeyResolver, ResolverBase {
        struct PublicKey {
            bytes32 x;
            bytes32 y;
        }
        mapping(uint64 => mapping(bytes32 => PublicKey)) versionable_pubkeys;
        /**
         * Sets the SECP256k1 public key associated with an ENS node.
         * @param node The ENS node to query
         * @param x the X coordinate of the curve point for the public key.
         * @param y the Y coordinate of the curve point for the public key.
         */
        function setPubkey(
            bytes32 node,
            bytes32 x,
            bytes32 y
        ) external virtual authorised(node) {
            versionable_pubkeys[recordVersions[node]][node] = PublicKey(x, y);
            emit PubkeyChanged(node, x, y);
        }
        /**
         * Returns the SECP256k1 public key associated with an ENS node.
         * Defined in EIP 619.
         * @param node The ENS node to query
         * @return x The X coordinate of the curve point for the public key.
         * @return y The Y coordinate of the curve point for the public key.
         */
        function pubkey(
            bytes32 node
        ) external view virtual override returns (bytes32 x, bytes32 y) {
            uint64 currentRecordVersion = recordVersions[node];
            return (
                versionable_pubkeys[currentRecordVersion][node].x,
                versionable_pubkeys[currentRecordVersion][node].y
            );
        }
        function supportsInterface(
            bytes4 interfaceID
        ) public view virtual override returns (bool) {
            return
                interfaceID == type(IPubkeyResolver).interfaceId ||
                super.supportsInterface(interfaceID);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.4;
    import "../ResolverBase.sol";
    import "./ITextResolver.sol";
    abstract contract TextResolver is ITextResolver, ResolverBase {
        mapping(uint64 => mapping(bytes32 => mapping(string => string))) versionable_texts;
        /**
         * Sets the text data associated with an ENS node and key.
         * May only be called by the owner of that node in the ENS registry.
         * @param node The node to update.
         * @param key The key to set.
         * @param value The text data value to set.
         */
        function setText(
            bytes32 node,
            string calldata key,
            string calldata value
        ) external virtual authorised(node) {
            versionable_texts[recordVersions[node]][node][key] = value;
            emit TextChanged(node, key, key, value);
        }
        /**
         * Returns the text data associated with an ENS node and key.
         * @param node The ENS node to query.
         * @param key The text data key to query.
         * @return The associated text data.
         */
        function text(
            bytes32 node,
            string calldata key
        ) external view virtual override returns (string memory) {
            return versionable_texts[recordVersions[node]][node][key];
        }
        function supportsInterface(
            bytes4 interfaceID
        ) public view virtual override returns (bool) {
            return
                interfaceID == type(ITextResolver).interfaceId ||
                super.supportsInterface(interfaceID);
        }
    }
    pragma solidity >=0.8.4;
    interface IReverseRegistrar {
        function setDefaultResolver(address resolver) external;
        function claim(address owner) external returns (bytes32);
        function claimForAddr(
            address addr,
            address owner,
            address resolver
        ) external returns (bytes32);
        function claimWithResolver(
            address owner,
            address resolver
        ) external returns (bytes32);
        function setName(string memory name) external returns (bytes32);
        function setNameForAddr(
            address addr,
            address owner,
            address resolver,
            string memory name
        ) external returns (bytes32);
        function node(address addr) external pure returns (bytes32);
    }
    //SPDX-License-Identifier: MIT
    pragma solidity >=0.8.17 <0.9.0;
    import {ENS} from "../registry/ENS.sol";
    import {IReverseRegistrar} from "../reverseRegistrar/IReverseRegistrar.sol";
    contract ReverseClaimer {
        bytes32 constant ADDR_REVERSE_NODE =
            0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;
        constructor(ENS ens, address claimant) {
            IReverseRegistrar reverseRegistrar = IReverseRegistrar(
                ens.owner(ADDR_REVERSE_NODE)
            );
            reverseRegistrar.claim(claimant);
        }
    }
    //SPDX-License-Identifier: MIT
    pragma solidity ~0.8.17;
    interface IMetadataService {
        function uri(uint256) external view returns (string memory);
    }
    //SPDX-License-Identifier: MIT
    pragma solidity ~0.8.17;
    import "../registry/ENS.sol";
    import "../ethregistrar/IBaseRegistrar.sol";
    import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
    import "./IMetadataService.sol";
    import "./INameWrapperUpgrade.sol";
    uint32 constant CANNOT_UNWRAP = 1;
    uint32 constant CANNOT_BURN_FUSES = 2;
    uint32 constant CANNOT_TRANSFER = 4;
    uint32 constant CANNOT_SET_RESOLVER = 8;
    uint32 constant CANNOT_SET_TTL = 16;
    uint32 constant CANNOT_CREATE_SUBDOMAIN = 32;
    uint32 constant CANNOT_APPROVE = 64;
    //uint16 reserved for parent controlled fuses from bit 17 to bit 32
    uint32 constant PARENT_CANNOT_CONTROL = 1 << 16;
    uint32 constant IS_DOT_ETH = 1 << 17;
    uint32 constant CAN_EXTEND_EXPIRY = 1 << 18;
    uint32 constant CAN_DO_EVERYTHING = 0;
    uint32 constant PARENT_CONTROLLED_FUSES = 0xFFFF0000;
    // all fuses apart from IS_DOT_ETH
    uint32 constant USER_SETTABLE_FUSES = 0xFFFDFFFF;
    interface INameWrapper is IERC1155 {
        event NameWrapped(
            bytes32 indexed node,
            bytes name,
            address owner,
            uint32 fuses,
            uint64 expiry
        );
        event NameUnwrapped(bytes32 indexed node, address owner);
        event FusesSet(bytes32 indexed node, uint32 fuses);
        event ExpiryExtended(bytes32 indexed node, uint64 expiry);
        function ens() external view returns (ENS);
        function registrar() external view returns (IBaseRegistrar);
        function metadataService() external view returns (IMetadataService);
        function names(bytes32) external view returns (bytes memory);
        function name() external view returns (string memory);
        function upgradeContract() external view returns (INameWrapperUpgrade);
        function supportsInterface(bytes4 interfaceID) external view returns (bool);
        function wrap(
            bytes calldata name,
            address wrappedOwner,
            address resolver
        ) external;
        function wrapETH2LD(
            string calldata label,
            address wrappedOwner,
            uint16 ownerControlledFuses,
            address resolver
        ) external returns (uint64 expires);
        function registerAndWrapETH2LD(
            string calldata label,
            address wrappedOwner,
            uint256 duration,
            address resolver,
            uint16 ownerControlledFuses
        ) external returns (uint256 registrarExpiry);
        function renew(
            uint256 labelHash,
            uint256 duration
        ) external returns (uint256 expires);
        function unwrap(bytes32 node, bytes32 label, address owner) external;
        function unwrapETH2LD(
            bytes32 label,
            address newRegistrant,
            address newController
        ) external;
        function upgrade(bytes calldata name, bytes calldata extraData) external;
        function setFuses(
            bytes32 node,
            uint16 ownerControlledFuses
        ) external returns (uint32 newFuses);
        function setChildFuses(
            bytes32 parentNode,
            bytes32 labelhash,
            uint32 fuses,
            uint64 expiry
        ) external;
        function setSubnodeRecord(
            bytes32 node,
            string calldata label,
            address owner,
            address resolver,
            uint64 ttl,
            uint32 fuses,
            uint64 expiry
        ) external returns (bytes32);
        function setRecord(
            bytes32 node,
            address owner,
            address resolver,
            uint64 ttl
        ) external;
        function setSubnodeOwner(
            bytes32 node,
            string calldata label,
            address newOwner,
            uint32 fuses,
            uint64 expiry
        ) external returns (bytes32);
        function extendExpiry(
            bytes32 node,
            bytes32 labelhash,
            uint64 expiry
        ) external returns (uint64);
        function canModifyName(
            bytes32 node,
            address addr
        ) external view returns (bool);
        function setResolver(bytes32 node, address resolver) external;
        function setTTL(bytes32 node, uint64 ttl) external;
        function ownerOf(uint256 id) external view returns (address owner);
        function approve(address to, uint256 tokenId) external;
        function getApproved(uint256 tokenId) external view returns (address);
        function getData(
            uint256 id
        ) external view returns (address, uint32, uint64);
        function setMetadataService(IMetadataService _metadataService) external;
        function uri(uint256 tokenId) external view returns (string memory);
        function setUpgradeContract(INameWrapperUpgrade _upgradeAddress) external;
        function allFusesBurned(
            bytes32 node,
            uint32 fuseMask
        ) external view returns (bool);
        function isWrapped(bytes32) external view returns (bool);
        function isWrapped(bytes32, bytes32) external view returns (bool);
    }
    //SPDX-License-Identifier: MIT
    pragma solidity ~0.8.17;
    interface INameWrapperUpgrade {
        function wrapFromUpgrade(
            bytes calldata name,
            address wrappedOwner,
            uint32 fuses,
            uint64 expiry,
            address approved,
            bytes calldata extraData
        ) external;
    }
    

    File 2 of 2: ENSRegistryWithFallback
    // File: @ensdomains/ens/contracts/ENS.sol
    
    pragma solidity >=0.4.24;
    
    interface ENS {
    
        // Logged when the owner of a node assigns a new owner to a subnode.
        event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
    
        // Logged when the owner of a node transfers ownership to a new account.
        event Transfer(bytes32 indexed node, address owner);
    
        // Logged when the resolver for a node changes.
        event NewResolver(bytes32 indexed node, address resolver);
    
        // Logged when the TTL of a node changes
        event NewTTL(bytes32 indexed node, uint64 ttl);
    
        // Logged when an operator is added or removed.
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
    
        function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external;
        function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external;
        function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external returns(bytes32);
        function setResolver(bytes32 node, address resolver) external;
        function setOwner(bytes32 node, address owner) external;
        function setTTL(bytes32 node, uint64 ttl) external;
        function setApprovalForAll(address operator, bool approved) external;
        function owner(bytes32 node) external view returns (address);
        function resolver(bytes32 node) external view returns (address);
        function ttl(bytes32 node) external view returns (uint64);
        function recordExists(bytes32 node) external view returns (bool);
        function isApprovedForAll(address owner, address operator) external view returns (bool);
    }
    
    // File: @ensdomains/ens/contracts/ENSRegistry.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * The ENS registry contract.
     */
    contract ENSRegistry is ENS {
    
        struct Record {
            address owner;
            address resolver;
            uint64 ttl;
        }
    
        mapping (bytes32 => Record) records;
        mapping (address => mapping(address => bool)) operators;
    
        // Permits modifications only by the owner of the specified node.
        modifier authorised(bytes32 node) {
            address owner = records[node].owner;
            require(owner == msg.sender || operators[owner][msg.sender]);
            _;
        }
    
        /**
         * @dev Constructs a new ENS registrar.
         */
        constructor() public {
            records[0x0].owner = msg.sender;
        }
    
        /**
         * @dev Sets the record for a node.
         * @param node The node to update.
         * @param owner The address of the new owner.
         * @param resolver The address of the resolver.
         * @param ttl The TTL in seconds.
         */
        function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external {
            setOwner(node, owner);
            _setResolverAndTTL(node, resolver, ttl);
        }
    
        /**
         * @dev Sets the record for a subnode.
         * @param node The parent node.
         * @param label The hash of the label specifying the subnode.
         * @param owner The address of the new owner.
         * @param resolver The address of the resolver.
         * @param ttl The TTL in seconds.
         */
        function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external {
            bytes32 subnode = setSubnodeOwner(node, label, owner);
            _setResolverAndTTL(subnode, resolver, ttl);
        }
    
        /**
         * @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node.
         * @param node The node to transfer ownership of.
         * @param owner The address of the new owner.
         */
        function setOwner(bytes32 node, address owner) public authorised(node) {
            _setOwner(node, owner);
            emit Transfer(node, owner);
        }
    
        /**
         * @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node.
         * @param node The parent node.
         * @param label The hash of the label specifying the subnode.
         * @param owner The address of the new owner.
         */
        function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public authorised(node) returns(bytes32) {
            bytes32 subnode = keccak256(abi.encodePacked(node, label));
            _setOwner(subnode, owner);
            emit NewOwner(node, label, owner);
            return subnode;
        }
    
        /**
         * @dev Sets the resolver address for the specified node.
         * @param node The node to update.
         * @param resolver The address of the resolver.
         */
        function setResolver(bytes32 node, address resolver) public authorised(node) {
            emit NewResolver(node, resolver);
            records[node].resolver = resolver;
        }
    
        /**
         * @dev Sets the TTL for the specified node.
         * @param node The node to update.
         * @param ttl The TTL in seconds.
         */
        function setTTL(bytes32 node, uint64 ttl) public authorised(node) {
            emit NewTTL(node, ttl);
            records[node].ttl = ttl;
        }
    
        /**
         * @dev Enable or disable approval for a third party ("operator") to manage
         *  all of `msg.sender`'s ENS records. Emits the ApprovalForAll event.
         * @param operator Address to add to the set of authorized operators.
         * @param approved True if the operator is approved, false to revoke approval.
         */
        function setApprovalForAll(address operator, bool approved) external {
            operators[msg.sender][operator] = approved;
            emit ApprovalForAll(msg.sender, operator, approved);
        }
    
        /**
         * @dev Returns the address that owns the specified node.
         * @param node The specified node.
         * @return address of the owner.
         */
        function owner(bytes32 node) public view returns (address) {
            address addr = records[node].owner;
            if (addr == address(this)) {
                return address(0x0);
            }
    
            return addr;
        }
    
        /**
         * @dev Returns the address of the resolver for the specified node.
         * @param node The specified node.
         * @return address of the resolver.
         */
        function resolver(bytes32 node) public view returns (address) {
            return records[node].resolver;
        }
    
        /**
         * @dev Returns the TTL of a node, and any records associated with it.
         * @param node The specified node.
         * @return ttl of the node.
         */
        function ttl(bytes32 node) public view returns (uint64) {
            return records[node].ttl;
        }
    
        /**
         * @dev Returns whether a record has been imported to the registry.
         * @param node The specified node.
         * @return Bool if record exists
         */
        function recordExists(bytes32 node) public view returns (bool) {
            return records[node].owner != address(0x0);
        }
    
        /**
         * @dev Query if an address is an authorized operator for another address.
         * @param owner The address that owns the records.
         * @param operator The address that acts on behalf of the owner.
         * @return True if `operator` is an approved operator for `owner`, false otherwise.
         */
        function isApprovedForAll(address owner, address operator) external view returns (bool) {
            return operators[owner][operator];
        }
    
        function _setOwner(bytes32 node, address owner) internal {
            records[node].owner = owner;
        }
    
        function _setResolverAndTTL(bytes32 node, address resolver, uint64 ttl) internal {
            if(resolver != records[node].resolver) {
                records[node].resolver = resolver;
                emit NewResolver(node, resolver);
            }
    
            if(ttl != records[node].ttl) {
                records[node].ttl = ttl;
                emit NewTTL(node, ttl);
            }
        }
    }
    
    // File: @ensdomains/ens/contracts/ENSRegistryWithFallback.sol
    
    pragma solidity ^0.5.0;
    
    
    
    /**
     * The ENS registry contract.
     */
    contract ENSRegistryWithFallback is ENSRegistry {
    
        ENS public old;
    
        /**
         * @dev Constructs a new ENS registrar.
         */
        constructor(ENS _old) public ENSRegistry() {
            old = _old;
        }
    
        /**
         * @dev Returns the address of the resolver for the specified node.
         * @param node The specified node.
         * @return address of the resolver.
         */
        function resolver(bytes32 node) public view returns (address) {
            if (!recordExists(node)) {
                return old.resolver(node);
            }
    
            return super.resolver(node);
        }
    
        /**
         * @dev Returns the address that owns the specified node.
         * @param node The specified node.
         * @return address of the owner.
         */
        function owner(bytes32 node) public view returns (address) {
            if (!recordExists(node)) {
                return old.owner(node);
            }
    
            return super.owner(node);
        }
    
        /**
         * @dev Returns the TTL of a node, and any records associated with it.
         * @param node The specified node.
         * @return ttl of the node.
         */
        function ttl(bytes32 node) public view returns (uint64) {
            if (!recordExists(node)) {
                return old.ttl(node);
            }
    
            return super.ttl(node);
        }
    
        function _setOwner(bytes32 node, address owner) internal {
            address addr = owner;
            if (addr == address(0x0)) {
                addr = address(this);
            }
    
            super._setOwner(node, addr);
        }
    }