{
  "language": "Solidity",
  "sources": {
    "contracts/dnsregistrar/DNSClaimChecker.sol": {
      "content": "pragma solidity ^0.8.4;\n\nimport \"../dnssec-oracle/DNSSEC.sol\";\nimport \"../dnssec-oracle/BytesUtils.sol\";\nimport \"../dnssec-oracle/RRUtils.sol\";\nimport \"@ensdomains/buffer/contracts/Buffer.sol\";\n\nlibrary DNSClaimChecker {\n\n    using BytesUtils for bytes;\n    using RRUtils for *;\n    using Buffer for Buffer.buffer;\n\n    uint16 constant CLASS_INET = 1;\n    uint16 constant TYPE_TXT = 16;\n\n    function getOwnerAddress(DNSSEC oracle, bytes memory name, bytes memory proof)\n        internal\n        view\n        returns (address, bool)\n    {\n        // Add \"_ens.\" to the front of the name.\n        Buffer.buffer memory buf;\n        buf.init(name.length + 5);\n        buf.append(\"\\x04_ens\");\n        buf.append(name);\n        bytes20 hash;\n        uint32 expiration;\n        // Check the provided TXT record has been validated by the oracle\n        (, expiration, hash) = oracle.rrdata(TYPE_TXT, buf.buf);\n        if (hash == bytes20(0) && proof.length == 0) return (address(0x0), false);\n\n        require(hash == bytes20(keccak256(proof)));\n\n        for (RRUtils.RRIterator memory iter = proof.iterateRRs(0); !iter.done(); iter.next()) {\n            require(RRUtils.serialNumberGte(expiration + iter.ttl, uint32(block.timestamp)), \"DNS record is stale; refresh or delete it before proceeding.\");\n\n            bool found;\n            address addr;\n            (addr, found) = parseRR(proof, iter.rdataOffset);\n            if (found) {\n                return (addr, true);\n            }\n        }\n\n        return (address(0x0), false);\n    }\n\n    function parseRR(bytes memory rdata, uint idx) internal pure returns (address, bool) {\n        while (idx < rdata.length) {\n            uint len = rdata.readUint8(idx); idx += 1;\n\n            bool found;\n            address addr;\n            (addr, found) = parseString(rdata, idx, len);\n\n            if (found) return (addr, true);\n            idx += len;\n        }\n\n        return (address(0x0), false);\n    }\n\n    function parseString(bytes memory str, uint idx, uint len) internal pure returns (address, bool) {\n        // TODO: More robust parsing that handles whitespace and multiple key/value pairs\n        if (str.readUint32(idx) != 0x613d3078) return (address(0x0), false); // 0x613d3078 == 'a=0x'\n        if (len < 44) return (address(0x0), false);\n        return hexToAddress(str, idx + 4);\n    }\n\n    function hexToAddress(bytes memory str, uint idx) internal pure returns (address, bool) {\n        if (str.length - idx < 40) return (address(0x0), false);\n        uint ret = 0;\n        for (uint i = idx; i < idx + 40; i++) {\n            ret <<= 4;\n            uint x = str.readUint8(i);\n            if (x >= 48 && x < 58) {\n                ret |= x - 48;\n            } else if (x >= 65 && x < 71) {\n                ret |= x - 55;\n            } else if (x >= 97 && x < 103) {\n                ret |= x - 87;\n            } else {\n                return (address(0x0), false);\n            }\n        }\n        return (address(uint160(ret)), true);\n    }\n}\n"
    },
    "contracts/dnssec-oracle/DNSSEC.sol": {
      "content": "pragma solidity ^0.8.4;\npragma experimental ABIEncoderV2;\n\nabstract contract DNSSEC {\n\n    bytes public anchors;\n\n    struct RRSetWithSignature {\n        bytes rrset;\n        bytes sig;\n    }\n\n    event AlgorithmUpdated(uint8 id, address addr);\n    event DigestUpdated(uint8 id, address addr);\n    event NSEC3DigestUpdated(uint8 id, address addr);\n    event RRSetUpdated(bytes name, bytes rrset);\n\n    function submitRRSets(RRSetWithSignature[] memory input, bytes calldata proof) public virtual returns (bytes memory);\n    function submitRRSet(RRSetWithSignature calldata input, bytes calldata proof) public virtual returns (bytes memory);\n    function deleteRRSet(uint16 deleteType, bytes calldata deleteName, RRSetWithSignature calldata nsec, bytes calldata proof) public virtual;\n    function deleteRRSetNSEC3(uint16 deleteType, bytes memory deleteName, RRSetWithSignature memory closestEncloser, RRSetWithSignature memory nextClosest, bytes memory dnskey) public virtual;\n    function rrdata(uint16 dnstype, bytes calldata name) external virtual view returns (uint32, uint32, bytes20);\n}\n"
    },
    "contracts/dnssec-oracle/BytesUtils.sol": {
      "content": "pragma solidity ^0.8.4;\n\nlibrary BytesUtils {\n    /*\n    * @dev Returns the keccak-256 hash of a byte range.\n    * @param self The byte string to hash.\n    * @param offset The position to start hashing at.\n    * @param len The number of bytes to hash.\n    * @return The hash of the byte range.\n    */\n    function keccak(bytes memory self, uint offset, uint len) internal pure returns (bytes32 ret) {\n        require(offset + len <= self.length);\n        assembly {\n            ret := keccak256(add(add(self, 32), offset), len)\n        }\n    }\n\n\n    /*\n    * @dev Returns a positive number if `other` comes lexicographically after\n    *      `self`, a negative number if it comes before, or zero if the\n    *      contents of the two bytes are equal.\n    * @param self The first bytes to compare.\n    * @param other The second bytes to compare.\n    * @return The result of the comparison.\n    */\n    function compare(bytes memory self, bytes memory other) internal pure returns (int) {\n        return compare(self, 0, self.length, other, 0, other.length);\n    }\n\n    /*\n    * @dev Returns a positive number if `other` comes lexicographically after\n    *      `self`, a negative number if it comes before, or zero if the\n    *      contents of the two bytes are equal. Comparison is done per-rune,\n    *      on unicode codepoints.\n    * @param self The first bytes to compare.\n    * @param offset The offset of self.\n    * @param len    The length of self.\n    * @param other The second bytes to compare.\n    * @param otheroffset The offset of the other string.\n    * @param otherlen    The length of the other string.\n    * @return The result of the comparison.\n    */\n    function compare(bytes memory self, uint offset, uint len, bytes memory other, uint otheroffset, uint otherlen) internal pure returns (int) {\n        uint shortest = len;\n        if (otherlen < len)\n        shortest = otherlen;\n\n        uint selfptr;\n        uint otherptr;\n\n        assembly {\n            selfptr := add(self, add(offset, 32))\n            otherptr := add(other, add(otheroffset, 32))\n        }\n        for (uint idx = 0; idx < shortest; idx += 32) {\n            uint a;\n            uint b;\n            assembly {\n                a := mload(selfptr)\n                b := mload(otherptr)\n            }\n            if (a != b) {\n                // Mask out irrelevant bytes and check again\n                uint mask;\n                if (shortest > 32) {\n                    mask = type(uint256).max;\n                } else {\n                    mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);\n                }\n                int diff = int(a & mask) - int(b & mask);\n                if (diff != 0)\n                return diff;\n            }\n            selfptr += 32;\n            otherptr += 32;\n        }\n\n        return int(len) - int(otherlen);\n    }\n\n    /*\n    * @dev Returns true if the two byte ranges are equal.\n    * @param self The first byte range to compare.\n    * @param offset The offset into the first byte range.\n    * @param other The second byte range to compare.\n    * @param otherOffset The offset into the second byte range.\n    * @param len The number of bytes to compare\n    * @return True if the byte ranges are equal, false otherwise.\n    */\n    function equals(bytes memory self, uint offset, bytes memory other, uint otherOffset, uint len) internal pure returns (bool) {\n        return keccak(self, offset, len) == keccak(other, otherOffset, len);\n    }\n\n    /*\n    * @dev Returns true if the two byte ranges are equal with offsets.\n    * @param self The first byte range to compare.\n    * @param offset The offset into the first byte range.\n    * @param other The second byte range to compare.\n    * @param otherOffset The offset into the second byte range.\n    * @return True if the byte ranges are equal, false otherwise.\n    */\n    function equals(bytes memory self, uint offset, bytes memory other, uint otherOffset) internal pure returns (bool) {\n        return keccak(self, offset, self.length - offset) == keccak(other, otherOffset, other.length - otherOffset);\n    }\n\n    /*\n    * @dev Compares a range of 'self' to all of 'other' and returns True iff\n    *      they are equal.\n    * @param self The first byte range to compare.\n    * @param offset The offset into the first byte range.\n    * @param other The second byte range to compare.\n    * @return True if the byte ranges are equal, false otherwise.\n    */\n    function equals(bytes memory self, uint offset, bytes memory other) internal pure returns (bool) {\n        return self.length >= offset + other.length && equals(self, offset, other, 0, other.length);\n    }\n\n    /*\n    * @dev Returns true if the two byte ranges are equal.\n    * @param self The first byte range to compare.\n    * @param other The second byte range to compare.\n    * @return True if the byte ranges are equal, false otherwise.\n    */\n    function equals(bytes memory self, bytes memory other) internal pure returns(bool) {\n        return self.length == other.length && equals(self, 0, other, 0, self.length);\n    }\n\n    /*\n    * @dev Returns the 8-bit number at the specified index of self.\n    * @param self The byte string.\n    * @param idx The index into the bytes\n    * @return The specified 8 bits of the string, interpreted as an integer.\n    */\n    function readUint8(bytes memory self, uint idx) internal pure returns (uint8 ret) {\n        return uint8(self[idx]);\n    }\n\n    /*\n    * @dev Returns the 16-bit number at the specified index of self.\n    * @param self The byte string.\n    * @param idx The index into the bytes\n    * @return The specified 16 bits of the string, interpreted as an integer.\n    */\n    function readUint16(bytes memory self, uint idx) internal pure returns (uint16 ret) {\n        require(idx + 2 <= self.length);\n        assembly {\n            ret := and(mload(add(add(self, 2), idx)), 0xFFFF)\n        }\n    }\n\n    /*\n    * @dev Returns the 32-bit number at the specified index of self.\n    * @param self The byte string.\n    * @param idx The index into the bytes\n    * @return The specified 32 bits of the string, interpreted as an integer.\n    */\n    function readUint32(bytes memory self, uint idx) internal pure returns (uint32 ret) {\n        require(idx + 4 <= self.length);\n        assembly {\n            ret := and(mload(add(add(self, 4), idx)), 0xFFFFFFFF)\n        }\n    }\n\n    /*\n    * @dev Returns the 32 byte value at the specified index of self.\n    * @param self The byte string.\n    * @param idx The index into the bytes\n    * @return The specified 32 bytes of the string.\n    */\n    function readBytes32(bytes memory self, uint idx) internal pure returns (bytes32 ret) {\n        require(idx + 32 <= self.length);\n        assembly {\n            ret := mload(add(add(self, 32), idx))\n        }\n    }\n\n    /*\n    * @dev Returns the 32 byte value at the specified index of self.\n    * @param self The byte string.\n    * @param idx The index into the bytes\n    * @return The specified 32 bytes of the string.\n    */\n    function readBytes20(bytes memory self, uint idx) internal pure returns (bytes20 ret) {\n        require(idx + 20 <= self.length);\n        assembly {\n            ret := and(mload(add(add(self, 32), idx)), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000)\n        }\n    }\n\n    /*\n    * @dev Returns the n byte value at the specified index of self.\n    * @param self The byte string.\n    * @param idx The index into the bytes.\n    * @param len The number of bytes.\n    * @return The specified 32 bytes of the string.\n    */\n    function readBytesN(bytes memory self, uint idx, uint len) internal pure returns (bytes32 ret) {\n        require(len <= 32);\n        require(idx + len <= self.length);\n        assembly {\n            let mask := not(sub(exp(256, sub(32, len)), 1))\n            ret := and(mload(add(add(self, 32), idx)),  mask)\n        }\n    }\n\n    function memcpy(uint dest, uint src, uint len) private pure {\n        // Copy word-length chunks while possible\n        for (; len >= 32; len -= 32) {\n            assembly {\n                mstore(dest, mload(src))\n            }\n            dest += 32;\n            src += 32;\n        }\n\n        // Copy remaining bytes\n        unchecked {\n            uint mask = (256 ** (32 - len)) - 1;\n            assembly {\n                let srcpart := and(mload(src), not(mask))\n                let destpart := and(mload(dest), mask)\n                mstore(dest, or(destpart, srcpart))\n            }\n        }\n    }\n\n    /*\n    * @dev Copies a substring into a new byte string.\n    * @param self The byte string to copy from.\n    * @param offset The offset to start copying at.\n    * @param len The number of bytes to copy.\n    */\n    function substring(bytes memory self, uint offset, uint len) internal pure returns(bytes memory) {\n        require(offset + len <= self.length);\n\n        bytes memory ret = new bytes(len);\n        uint dest;\n        uint src;\n\n        assembly {\n            dest := add(ret, 32)\n            src := add(add(self, 32), offset)\n        }\n        memcpy(dest, src, len);\n\n        return ret;\n    }\n\n    // Maps characters from 0x30 to 0x7A to their base32 values.\n    // 0xFF represents invalid characters in that range.\n    bytes constant base32HexTable = hex'00010203040506070809FFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1FFFFFFFFFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1F';\n\n    /**\n     * @dev Decodes unpadded base32 data of up to one word in length.\n     * @param self The data to decode.\n     * @param off Offset into the string to start at.\n     * @param len Number of characters to decode.\n     * @return The decoded data, left aligned.\n     */\n    function base32HexDecodeWord(bytes memory self, uint off, uint len) internal pure returns(bytes32) {\n        require(len <= 52);\n\n        uint ret = 0;\n        uint8 decoded;\n        for(uint i = 0; i < len; i++) {\n            bytes1 char = self[off + i];\n            require(char >= 0x30 && char <= 0x7A);\n            decoded = uint8(base32HexTable[uint(uint8(char)) - 0x30]);\n            require(decoded <= 0x20);\n            if(i == len - 1) {\n                break;\n            }\n            ret = (ret << 5) | decoded;\n        }\n\n        uint bitlen = len * 5;\n        if(len % 8 == 0) {\n            // Multiple of 8 characters, no padding\n            ret = (ret << 5) | decoded;\n        } else if(len % 8 == 2) {\n            // Two extra characters - 1 byte\n            ret = (ret << 3) | (decoded >> 2);\n            bitlen -= 2;\n        } else if(len % 8 == 4) {\n            // Four extra characters - 2 bytes\n            ret = (ret << 1) | (decoded >> 4);\n            bitlen -= 4;\n        } else if(len % 8 == 5) {\n            // Five extra characters - 3 bytes\n            ret = (ret << 4) | (decoded >> 1);\n            bitlen -= 1;\n        } else if(len % 8 == 7) {\n            // Seven extra characters - 4 bytes\n            ret = (ret << 2) | (decoded >> 3);\n            bitlen -= 3;\n        } else {\n            revert();\n        }\n\n        return bytes32(ret << (256 - bitlen));\n    }\n}"
    },
    "contracts/dnssec-oracle/RRUtils.sol": {
      "content": "pragma solidity ^0.8.4;\n\nimport \"./BytesUtils.sol\";\nimport \"@ensdomains/buffer/contracts/Buffer.sol\";\n\n/**\n* @dev RRUtils is a library that provides utilities for parsing DNS resource records.\n*/\nlibrary RRUtils {\n    using BytesUtils for *;\n    using Buffer for *;\n\n    /**\n    * @dev Returns the number of bytes in the DNS name at 'offset' in 'self'.\n    * @param self The byte array to read a name from.\n    * @param offset The offset to start reading at.\n    * @return The length of the DNS name at 'offset', in bytes.\n    */\n    function nameLength(bytes memory self, uint offset) internal pure returns(uint) {\n        uint idx = offset;\n        while (true) {\n            assert(idx < self.length);\n            uint labelLen = self.readUint8(idx);\n            idx += labelLen + 1;\n            if (labelLen == 0) {\n                break;\n            }\n        }\n        return idx - offset;\n    }\n\n    /**\n    * @dev Returns a DNS format name at the specified offset of self.\n    * @param self The byte array to read a name from.\n    * @param offset The offset to start reading at.\n    * @return ret The name.\n    */\n    function readName(bytes memory self, uint offset) internal pure returns(bytes memory ret) {\n        uint len = nameLength(self, offset);\n        return self.substring(offset, len);\n    }\n\n    /**\n    * @dev Returns the number of labels in the DNS name at 'offset' in 'self'.\n    * @param self The byte array to read a name from.\n    * @param offset The offset to start reading at.\n    * @return The number of labels in the DNS name at 'offset', in bytes.\n    */\n    function labelCount(bytes memory self, uint offset) internal pure returns(uint) {\n        uint count = 0;\n        while (true) {\n            assert(offset < self.length);\n            uint labelLen = self.readUint8(offset);\n            offset += labelLen + 1;\n            if (labelLen == 0) {\n                break;\n            }\n            count += 1;\n        }\n        return count;\n    }\n\n    uint constant RRSIG_TYPE = 0;\n    uint constant RRSIG_ALGORITHM = 2;\n    uint constant RRSIG_LABELS = 3;\n    uint constant RRSIG_TTL = 4;\n    uint constant RRSIG_EXPIRATION = 8;\n    uint constant RRSIG_INCEPTION = 12;\n    uint constant RRSIG_KEY_TAG = 16;\n    uint constant RRSIG_SIGNER_NAME = 18;\n\n    struct SignedSet {\n        uint16 typeCovered;\n        uint8 algorithm;\n        uint8 labels;\n        uint32 ttl;\n        uint32 expiration;\n        uint32 inception;\n        uint16 keytag;\n        bytes signerName;\n        bytes data;\n        bytes name;\n    }\n\n    function readSignedSet(bytes memory data) internal pure returns(SignedSet memory self) {\n        self.typeCovered = data.readUint16(RRSIG_TYPE);\n        self.algorithm = data.readUint8(RRSIG_ALGORITHM);\n        self.labels = data.readUint8(RRSIG_LABELS);\n        self.ttl = data.readUint32(RRSIG_TTL);\n        self.expiration = data.readUint32(RRSIG_EXPIRATION);\n        self.inception = data.readUint32(RRSIG_INCEPTION);\n        self.keytag = data.readUint16(RRSIG_KEY_TAG);\n        self.signerName = readName(data, RRSIG_SIGNER_NAME);\n        self.data = data.substring(RRSIG_SIGNER_NAME + self.signerName.length, data.length - RRSIG_SIGNER_NAME - self.signerName.length);\n    }\n\n    function rrs(SignedSet memory rrset) internal pure returns(RRIterator memory) {\n        return iterateRRs(rrset.data, 0);\n    }\n\n    /**\n    * @dev An iterator over resource records.\n    */\n    struct RRIterator {\n        bytes data;\n        uint offset;\n        uint16 dnstype;\n        uint16 class;\n        uint32 ttl;\n        uint rdataOffset;\n        uint nextOffset;\n    }\n\n    /**\n    * @dev Begins iterating over resource records.\n    * @param self The byte string to read from.\n    * @param offset The offset to start reading at.\n    * @return ret An iterator object.\n    */\n    function iterateRRs(bytes memory self, uint offset) internal pure returns (RRIterator memory ret) {\n        ret.data = self;\n        ret.nextOffset = offset;\n        next(ret);\n    }\n\n    /**\n    * @dev Returns true iff there are more RRs to iterate.\n    * @param iter The iterator to check.\n    * @return True iff the iterator has finished.\n    */\n    function done(RRIterator memory iter) internal pure returns(bool) {\n        return iter.offset >= iter.data.length;\n    }\n\n    /**\n    * @dev Moves the iterator to the next resource record.\n    * @param iter The iterator to advance.\n    */\n    function next(RRIterator memory iter) internal pure {\n        iter.offset = iter.nextOffset;\n        if (iter.offset >= iter.data.length) {\n            return;\n        }\n\n        // Skip the name\n        uint off = iter.offset + nameLength(iter.data, iter.offset);\n\n        // Read type, class, and ttl\n        iter.dnstype = iter.data.readUint16(off);\n        off += 2;\n        iter.class = iter.data.readUint16(off);\n        off += 2;\n        iter.ttl = iter.data.readUint32(off);\n        off += 4;\n\n        // Read the rdata\n        uint rdataLength = iter.data.readUint16(off);\n        off += 2;\n        iter.rdataOffset = off;\n        iter.nextOffset = off + rdataLength;\n    }\n\n    /**\n    * @dev Returns the name of the current record.\n    * @param iter The iterator.\n    * @return A new bytes object containing the owner name from the RR.\n    */\n    function name(RRIterator memory iter) internal pure returns(bytes memory) {\n        return iter.data.substring(iter.offset, nameLength(iter.data, iter.offset));\n    }\n\n    /**\n    * @dev Returns the rdata portion of the current record.\n    * @param iter The iterator.\n    * @return A new bytes object containing the RR's RDATA.\n    */\n    function rdata(RRIterator memory iter) internal pure returns(bytes memory) {\n        return iter.data.substring(iter.rdataOffset, iter.nextOffset - iter.rdataOffset);\n    }\n\n    uint constant DNSKEY_FLAGS = 0;\n    uint constant DNSKEY_PROTOCOL = 2;\n    uint constant DNSKEY_ALGORITHM = 3;\n    uint constant DNSKEY_PUBKEY = 4;\n\n    struct DNSKEY {\n        uint16 flags;\n        uint8 protocol;\n        uint8 algorithm;\n        bytes publicKey;\n    }\n\n    function readDNSKEY(bytes memory data, uint offset, uint length) internal pure returns(DNSKEY memory self) {\n        self.flags = data.readUint16(offset + DNSKEY_FLAGS);\n        self.protocol = data.readUint8(offset + DNSKEY_PROTOCOL);\n        self.algorithm = data.readUint8(offset + DNSKEY_ALGORITHM);\n        self.publicKey = data.substring(offset + DNSKEY_PUBKEY, length - DNSKEY_PUBKEY);\n    } \n\n    uint constant DS_KEY_TAG = 0;\n    uint constant DS_ALGORITHM = 2;\n    uint constant DS_DIGEST_TYPE = 3;\n    uint constant DS_DIGEST = 4;\n\n    struct DS {\n        uint16 keytag;\n        uint8 algorithm;\n        uint8 digestType;\n        bytes digest;\n    }\n\n    function readDS(bytes memory data, uint offset, uint length) internal pure returns(DS memory self) {\n        self.keytag = data.readUint16(offset + DS_KEY_TAG);\n        self.algorithm = data.readUint8(offset + DS_ALGORITHM);\n        self.digestType = data.readUint8(offset + DS_DIGEST_TYPE);\n        self.digest = data.substring(offset + DS_DIGEST, length - DS_DIGEST);\n    }\n\n    struct NSEC3 {\n        uint8 hashAlgorithm;\n        uint8 flags;\n        uint16 iterations;\n        bytes salt;\n        bytes32 nextHashedOwnerName;\n        bytes typeBitmap;\n    }\n\n    uint constant NSEC3_HASH_ALGORITHM = 0;\n    uint constant NSEC3_FLAGS = 1;\n    uint constant NSEC3_ITERATIONS = 2;\n    uint constant NSEC3_SALT_LENGTH = 4;\n    uint constant NSEC3_SALT = 5;\n\n    function readNSEC3(bytes memory data, uint offset, uint length) internal pure returns(NSEC3 memory self) {\n        uint end = offset + length;\n        self.hashAlgorithm = data.readUint8(offset + NSEC3_HASH_ALGORITHM);\n        self.flags = data.readUint8(offset + NSEC3_FLAGS);\n        self.iterations = data.readUint16(offset + NSEC3_ITERATIONS);\n        uint8 saltLength = data.readUint8(offset + NSEC3_SALT_LENGTH);\n        offset = offset + NSEC3_SALT;\n        self.salt = data.substring(offset, saltLength);\n        offset += saltLength;\n        uint8 nextLength = data.readUint8(offset);\n        require(nextLength <= 32);\n        offset += 1;\n        self.nextHashedOwnerName = data.readBytesN(offset, nextLength);\n        offset += nextLength;\n        self.typeBitmap = data.substring(offset, end - offset);\n    }\n\n    function checkTypeBitmap(NSEC3 memory self, uint16 rrtype) internal pure returns(bool) {\n        return checkTypeBitmap(self.typeBitmap, 0, rrtype);\n    }\n\n    /**\n    * @dev Checks if a given RR type exists in a type bitmap.\n    * @param bitmap The byte string to read the type bitmap from.\n    * @param offset The offset to start reading at.\n    * @param rrtype The RR type to check for.\n    * @return True if the type is found in the bitmap, false otherwise.\n    */\n    function checkTypeBitmap(bytes memory bitmap, uint offset, uint16 rrtype) internal pure returns (bool) {\n        uint8 typeWindow = uint8(rrtype >> 8);\n        uint8 windowByte = uint8((rrtype & 0xff) / 8);\n        uint8 windowBitmask = uint8(uint8(1) << (uint8(7) - uint8(rrtype & 0x7)));\n        for (uint off = offset; off < bitmap.length;) {\n            uint8 window = bitmap.readUint8(off);\n            uint8 len = bitmap.readUint8(off + 1);\n            if (typeWindow < window) {\n                // We've gone past our window; it's not here.\n                return false;\n            } else if (typeWindow == window) {\n                // Check this type bitmap\n                if (len <= windowByte) {\n                    // Our type is past the end of the bitmap\n                    return false;\n                }\n                return (bitmap.readUint8(off + windowByte + 2) & windowBitmask) != 0;\n            } else {\n                // Skip this type bitmap\n                off += len + 2;\n            }\n        }\n\n        return false;\n    }\n\n    function compareNames(bytes memory self, bytes memory other) internal pure returns (int) {\n        if (self.equals(other)) {\n            return 0;\n        }\n\n        uint off;\n        uint otheroff;\n        uint prevoff;\n        uint otherprevoff;\n        uint counts = labelCount(self, 0);\n        uint othercounts = labelCount(other, 0);\n\n        // Keep removing labels from the front of the name until both names are equal length\n        while (counts > othercounts) {\n            prevoff = off;\n            off = progress(self, off);\n            counts--;\n        }\n\n        while (othercounts > counts) {\n            otherprevoff = otheroff;\n            otheroff = progress(other, otheroff);\n            othercounts--;\n        }\n\n        // Compare the last nonequal labels to each other\n        while (counts > 0 && !self.equals(off, other, otheroff)) {\n            prevoff = off;\n            off = progress(self, off);\n            otherprevoff = otheroff;\n            otheroff = progress(other, otheroff);\n            counts -= 1;\n        }\n\n        if (off == 0) {\n            return -1;\n        }\n        if(otheroff == 0) {\n            return 1;\n        }\n\n        return self.compare(prevoff + 1, self.readUint8(prevoff), other, otherprevoff + 1, other.readUint8(otherprevoff));\n    }\n\n    /**\n     * @dev Compares two serial numbers using RFC1982 serial number math.\n     */\n    function serialNumberGte(uint32 i1, uint32 i2) internal pure returns(bool) {\n        return int32(i1) - int32(i2) >= 0;\n    }\n\n    function progress(bytes memory body, uint off) internal pure returns(uint) {\n        return off + 1 + body.readUint8(off);\n    }\n\n    /**\n     * @dev Computes the keytag for a chunk of data.\n     * @param data The data to compute a keytag for.\n     * @return The computed key tag.\n     */\n    function computeKeytag(bytes memory data) internal pure returns (uint16) {\n        /* This function probably deserves some explanation.\n         * The DNSSEC keytag function is a checksum that relies on summing up individual bytes\n         * from the input string, with some mild bitshifting. Here's a Naive solidity implementation:\n         *\n         *     function computeKeytag(bytes memory data) internal pure returns (uint16) {\n         *         uint ac;\n         *         for (uint i = 0; i < data.length; i++) {\n         *             ac += i & 1 == 0 ? uint16(data.readUint8(i)) << 8 : data.readUint8(i);\n         *         }\n         *         return uint16(ac + (ac >> 16));\n         *     }\n         *\n         * The EVM, with its 256 bit words, is exceedingly inefficient at doing byte-by-byte operations;\n         * the code above, on reasonable length inputs, consumes over 100k gas. But we can make the EVM's\n         * large words work in our favour.\n         *\n         * The code below works by treating the input as a series of 256 bit words. It first masks out\n         * even and odd bytes from each input word, adding them to two separate accumulators `ac1` and `ac2`.\n         * The bytes are separated by empty bytes, so as long as no individual sum exceeds 2^16-1, we're\n         * effectively summing 16 different numbers with each EVM ADD opcode.\n         *\n         * Once it's added up all the inputs, it has to add all the 16 bit values in `ac1` and `ac2` together.\n         * It does this using the same trick - mask out every other value, shift to align them, add them together.\n         * After the first addition on both accumulators, there's enough room to add the two accumulators together,\n         * and the remaining sums can be done just on ac1.\n         */\n        unchecked {\n            require(data.length <= 8192, \"Long keys not permitted\");\n            uint ac1;\n            uint ac2;\n            for(uint i = 0; i < data.length + 31; i += 32) {\n                uint word;\n                assembly {\n                    word := mload(add(add(data, 32), i))\n                }\n                if(i + 32 > data.length) {\n                    uint unused = 256 - (data.length - i) * 8;\n                    word = (word >> unused) << unused;\n                }\n                ac1 += (word & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8;\n                ac2 += (word & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF);\n            }\n            ac1 = (ac1 & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF)\n                + ((ac1 & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16);\n            ac2 = (ac2 & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF)\n                + ((ac2 & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16);\n            ac1 = (ac1 << 8) + ac2;\n            ac1 = (ac1 & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF)\n                + ((ac1 & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32);\n            ac1 = (ac1 & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF)\n                + ((ac1 & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64);\n            ac1 = (ac1 & 0x00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)\n                + (ac1 >> 128);\n            ac1 += (ac1 >> 16) & 0xFFFF;\n            return uint16(ac1);\n        }\n    }\n}"
    },
    "@ensdomains/buffer/contracts/Buffer.sol": {
      "content": "pragma solidity ^0.8.4;\n\n/**\n* @dev A library for working with mutable byte buffers in Solidity.\n*\n* Byte buffers are mutable and expandable, and provide a variety of primitives\n* for writing to them. At any time you can fetch a bytes object containing the\n* current contents of the buffer. The bytes object should not be stored between\n* operations, as it may change due to resizing of the buffer.\n*/\nlibrary Buffer {\n    /**\n    * @dev Represents a mutable buffer. Buffers have a current value (buf) and\n    *      a capacity. The capacity may be longer than the current value, in\n    *      which case it can be extended without the need to allocate more memory.\n    */\n    struct buffer {\n        bytes buf;\n        uint capacity;\n    }\n\n    /**\n    * @dev Initializes a buffer with an initial capacity.\n    * @param buf The buffer to initialize.\n    * @param capacity The number of bytes of space to allocate the buffer.\n    * @return The buffer, for chaining.\n    */\n    function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {\n        if (capacity % 32 != 0) {\n            capacity += 32 - (capacity % 32);\n        }\n        // Allocate space for the buffer data\n        buf.capacity = capacity;\n        assembly {\n            let ptr := mload(0x40)\n            mstore(buf, ptr)\n            mstore(ptr, 0)\n            mstore(0x40, add(32, add(ptr, capacity)))\n        }\n        return buf;\n    }\n\n    /**\n    * @dev Initializes a new buffer from an existing bytes object.\n    *      Changes to the buffer may mutate the original value.\n    * @param b The bytes object to initialize the buffer with.\n    * @return A new buffer.\n    */\n    function fromBytes(bytes memory b) internal pure returns(buffer memory) {\n        buffer memory buf;\n        buf.buf = b;\n        buf.capacity = b.length;\n        return buf;\n    }\n\n    function resize(buffer memory buf, uint capacity) private pure {\n        bytes memory oldbuf = buf.buf;\n        init(buf, capacity);\n        append(buf, oldbuf);\n    }\n\n    function max(uint a, uint b) private pure returns(uint) {\n        if (a > b) {\n            return a;\n        }\n        return b;\n    }\n\n    /**\n    * @dev Sets buffer length to 0.\n    * @param buf The buffer to truncate.\n    * @return The original buffer, for chaining..\n    */\n    function truncate(buffer memory buf) internal pure returns (buffer memory) {\n        assembly {\n            let bufptr := mload(buf)\n            mstore(bufptr, 0)\n        }\n        return buf;\n    }\n\n    /**\n    * @dev Writes a byte string to a buffer. Resizes if doing so would exceed\n    *      the capacity of the buffer.\n    * @param buf The buffer to append to.\n    * @param off The start offset to write to.\n    * @param data The data to append.\n    * @param len The number of bytes to copy.\n    * @return The original buffer, for chaining.\n    */\n    function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns(buffer memory) {\n        require(len <= data.length);\n\n        if (off + len > buf.capacity) {\n            resize(buf, max(buf.capacity, len + off) * 2);\n        }\n\n        uint dest;\n        uint src;\n        assembly {\n            // Memory address of the buffer data\n            let bufptr := mload(buf)\n            // Length of existing buffer data\n            let buflen := mload(bufptr)\n            // Start address = buffer address + offset + sizeof(buffer length)\n            dest := add(add(bufptr, 32), off)\n            // Update buffer length if we're extending it\n            if gt(add(len, off), buflen) {\n                mstore(bufptr, add(len, off))\n            }\n            src := add(data, 32)\n        }\n\n        // Copy word-length chunks while possible\n        for (; len >= 32; len -= 32) {\n            assembly {\n                mstore(dest, mload(src))\n            }\n            dest += 32;\n            src += 32;\n        }\n\n        // Copy remaining bytes\n        unchecked {\n            uint mask = (256 ** (32 - len)) - 1;\n            assembly {\n                let srcpart := and(mload(src), not(mask))\n                let destpart := and(mload(dest), mask)\n                mstore(dest, or(destpart, srcpart))\n            }\n        }\n\n        return buf;\n    }\n\n    /**\n    * @dev Appends a byte string to a buffer. Resizes if doing so would exceed\n    *      the capacity of the buffer.\n    * @param buf The buffer to append to.\n    * @param data The data to append.\n    * @param len The number of bytes to copy.\n    * @return The original buffer, for chaining.\n    */\n    function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) {\n        return write(buf, buf.buf.length, data, len);\n    }\n\n    /**\n    * @dev Appends a byte string to a buffer. Resizes if doing so would exceed\n    *      the capacity of the buffer.\n    * @param buf The buffer to append to.\n    * @param data The data to append.\n    * @return The original buffer, for chaining.\n    */\n    function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {\n        return write(buf, buf.buf.length, data, data.length);\n    }\n\n    /**\n    * @dev Writes a byte to the buffer. Resizes if doing so would exceed the\n    *      capacity of the buffer.\n    * @param buf The buffer to append to.\n    * @param off The offset to write the byte at.\n    * @param data The data to append.\n    * @return The original buffer, for chaining.\n    */\n    function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns(buffer memory) {\n        if (off >= buf.capacity) {\n            resize(buf, buf.capacity * 2);\n        }\n\n        assembly {\n            // Memory address of the buffer data\n            let bufptr := mload(buf)\n            // Length of existing buffer data\n            let buflen := mload(bufptr)\n            // Address = buffer address + sizeof(buffer length) + off\n            let dest := add(add(bufptr, off), 32)\n            mstore8(dest, data)\n            // Update buffer length if we extended it\n            if eq(off, buflen) {\n                mstore(bufptr, add(buflen, 1))\n            }\n        }\n        return buf;\n    }\n\n    /**\n    * @dev Appends a byte to the buffer. Resizes if doing so would exceed the\n    *      capacity of the buffer.\n    * @param buf The buffer to append to.\n    * @param data The data to append.\n    * @return The original buffer, for chaining.\n    */\n    function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {\n        return writeUint8(buf, buf.buf.length, data);\n    }\n\n    /**\n    * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would\n    *      exceed the capacity of the buffer.\n    * @param buf The buffer to append to.\n    * @param off The offset to write at.\n    * @param data The data to append.\n    * @param len The number of bytes to write (left-aligned).\n    * @return The original buffer, for chaining.\n    */\n    function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns(buffer memory) {\n        if (len + off > buf.capacity) {\n            resize(buf, (len + off) * 2);\n        }\n\n        unchecked {\n            uint mask = (256 ** len) - 1;\n            // Right-align data\n            data = data >> (8 * (32 - len));\n            assembly {\n                // Memory address of the buffer data\n                let bufptr := mload(buf)\n                // Address = buffer address + sizeof(buffer length) + off + len\n                let dest := add(add(bufptr, off), len)\n                mstore(dest, or(and(mload(dest), not(mask)), data))\n                // Update buffer length if we extended it\n                if gt(add(off, len), mload(bufptr)) {\n                    mstore(bufptr, add(off, len))\n                }\n            }\n        }\n        return buf;\n    }\n\n    /**\n    * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the\n    *      capacity of the buffer.\n    * @param buf The buffer to append to.\n    * @param off The offset to write at.\n    * @param data The data to append.\n    * @return The original buffer, for chaining.\n    */\n    function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) {\n        return write(buf, off, bytes32(data), 20);\n    }\n\n    /**\n    * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed\n    *      the capacity of the buffer.\n    * @param buf The buffer to append to.\n    * @param data The data to append.\n    * @return The original buffer, for chhaining.\n    */\n    function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {\n        return write(buf, buf.buf.length, bytes32(data), 20);\n    }\n\n    /**\n    * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed\n    *      the capacity of the buffer.\n    * @param buf The buffer to append to.\n    * @param data The data to append.\n    * @return The original buffer, for chaining.\n    */\n    function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {\n        return write(buf, buf.buf.length, data, 32);\n    }\n\n    /**\n    * @dev Writes an integer to the buffer. Resizes if doing so would exceed\n    *      the capacity of the buffer.\n    * @param buf The buffer to append to.\n    * @param off The offset to write at.\n    * @param data The data to append.\n    * @param len The number of bytes to write (right-aligned).\n    * @return The original buffer, for chaining.\n    */\n    function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns(buffer memory) {\n        if (len + off > buf.capacity) {\n            resize(buf, (len + off) * 2);\n        }\n\n        uint mask = (256 ** len) - 1;\n        assembly {\n            // Memory address of the buffer data\n            let bufptr := mload(buf)\n            // Address = buffer address + off + sizeof(buffer length) + len\n            let dest := add(add(bufptr, off), len)\n            mstore(dest, or(and(mload(dest), not(mask)), data))\n            // Update buffer length if we extended it\n            if gt(add(off, len), mload(bufptr)) {\n                mstore(bufptr, add(off, len))\n            }\n        }\n        return buf;\n    }\n\n    /**\n     * @dev Appends a byte to the end of the buffer. Resizes if doing so would\n     * exceed the capacity of the buffer.\n     * @param buf The buffer to append to.\n     * @param data The data to append.\n     * @return The original buffer.\n     */\n    function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {\n        return writeInt(buf, buf.buf.length, data, len);\n    }\n}\n"
    },
    "contracts/dnsregistrar/DNSRegistrar.sol": {
      "content": "pragma solidity ^0.8.4;\npragma experimental ABIEncoderV2;\n\nimport \"../dnssec-oracle/BytesUtils.sol\";\nimport \"../dnssec-oracle/DNSSEC.sol\";\nimport \"../registry/ENSRegistry.sol\";\nimport \"../root/Root.sol\";\nimport \"./DNSClaimChecker.sol\";\nimport \"./PublicSuffixList.sol\";\nimport \"../resolvers/profiles/AddrResolver.sol\";\n\ninterface IDNSRegistrar {\n    function claim(bytes memory name, bytes memory proof) external;\n    function proveAndClaim(bytes memory name, DNSSEC.RRSetWithSignature[] memory input, bytes memory proof) external;\n    function proveAndClaimWithResolver(bytes memory name, DNSSEC.RRSetWithSignature[] memory input, bytes memory proof, address resolver, address addr) external;\n}\n\n/**\n * @dev An ENS registrar that allows the owner of a DNS name to claim the\n *      corresponding name in ENS.\n */\ncontract DNSRegistrar is IDNSRegistrar {\n    using BytesUtils for bytes;\n\n    DNSSEC public oracle;\n    ENS public ens;\n    PublicSuffixList public suffixes;\n\n    bytes4 constant private INTERFACE_META_ID = bytes4(keccak256(\"supportsInterface(bytes4)\"));\n\n    event Claim(bytes32 indexed node, address indexed owner, bytes dnsname);\n    event NewOracle(address oracle);\n    event NewPublicSuffixList(address suffixes);\n\n    constructor(DNSSEC _dnssec, PublicSuffixList _suffixes, ENS _ens) {\n        oracle = _dnssec;\n        emit NewOracle(address(oracle));\n        suffixes = _suffixes;\n        emit NewPublicSuffixList(address(suffixes));\n        ens = _ens;\n    }\n\n    /**\n     * @dev This contract's owner-only functions can be invoked by the owner of the ENS root.\n     */\n    modifier onlyOwner {\n        Root root = Root(ens.owner(bytes32(0)));\n        address owner = root.owner();\n        require(msg.sender == owner);\n        _;\n    }\n\n    function setOracle(DNSSEC _dnssec) public onlyOwner {\n        oracle = _dnssec;\n        emit NewOracle(address(oracle));\n    }\n\n    function setPublicSuffixList(PublicSuffixList _suffixes) public onlyOwner {\n        suffixes = _suffixes;\n        emit NewPublicSuffixList(address(suffixes));\n    }\n\n    /**\n     * @dev Claims a name by proving ownership of its DNS equivalent.\n     * @param name The name to claim, in DNS wire format.\n     * @param proof A DNS RRSet proving ownership of the name. Must be verified\n     *        in the DNSSEC oracle before calling. This RRSET must contain a TXT\n     *        record for '_ens.' + name, with the value 'a=0x...'. Ownership of\n     *        the name will be transferred to the address specified in the TXT\n     *        record.\n     */\n    function claim(bytes memory name, bytes memory proof) public override {\n        (bytes32 rootNode, bytes32 labelHash, address addr) = _claim(name, proof);\n        ens.setSubnodeOwner(rootNode, labelHash, addr);\n    }\n\n    /**\n     * @dev Submits proofs to the DNSSEC oracle, then claims a name using those proofs.\n     * @param name The name to claim, in DNS wire format.\n     * @param input The data to be passed to the Oracle's `submitProofs` function. The last\n     *        proof must be the TXT record required by the registrar.\n     * @param proof The proof record for the first element in input.\n     */\n    function proveAndClaim(bytes memory name, DNSSEC.RRSetWithSignature[] memory input, bytes memory proof) public override {\n        proof = oracle.submitRRSets(input, proof);\n        claim(name, proof);\n    }\n\n    function proveAndClaimWithResolver(bytes memory name, DNSSEC.RRSetWithSignature[] memory input, bytes memory proof, address resolver, address addr) public override {\n        proof = oracle.submitRRSets(input, proof);\n        (bytes32 rootNode, bytes32 labelHash, address owner) = _claim(name, proof);\n        require(msg.sender == owner, \"Only owner can call proveAndClaimWithResolver\");\n        if(addr != address(0)) {\n            require(resolver != address(0), \"Cannot set addr if resolver is not set\");\n            // Set ourselves as the owner so we can set a record on the resolver\n            ens.setSubnodeRecord(rootNode, labelHash, address(this), resolver, 0);\n            bytes32 node = keccak256(abi.encodePacked(rootNode, labelHash));\n            // Set the resolver record\n            AddrResolver(resolver).setAddr(node, addr);\n            // Transfer the record to the owner\n            ens.setOwner(node, owner);\n        } else {\n            ens.setSubnodeRecord(rootNode, labelHash, owner, resolver, 0);\n        }\n    }\n\n    function supportsInterface(bytes4 interfaceID) external pure returns (bool) {\n        return interfaceID == INTERFACE_META_ID ||\n               interfaceID == type(IDNSRegistrar).interfaceId;\n    }\n\n    function _claim(bytes memory name, bytes memory proof) internal returns(bytes32 rootNode, bytes32 labelHash, address addr) {\n        // Get the first label\n        uint labelLen = name.readUint8(0);\n        labelHash = name.keccak(1, labelLen);\n\n        // Parent name must be in the public suffix list.\n        bytes memory parentName = name.substring(labelLen + 1, name.length - labelLen - 1);\n        require(suffixes.isPublicSuffix(parentName), \"Parent name must be a public suffix\");\n\n        // Make sure the parent name is enabled\n        rootNode = enableNode(parentName, 0);\n\n        (addr,) = DNSClaimChecker.getOwnerAddress(oracle, name, proof);\n\n        emit Claim(keccak256(abi.encodePacked(rootNode, labelHash)), addr, name);\n    }\n\n    function enableNode(bytes memory domain, uint offset) internal returns(bytes32 node) {\n        uint len = domain.readUint8(offset);\n        if(len == 0) {\n            return bytes32(0);\n        }\n\n        bytes32 parentNode = enableNode(domain, offset + len + 1);\n        bytes32 label = domain.keccak(offset + 1, len);\n        node = keccak256(abi.encodePacked(parentNode, label));\n        address owner = ens.owner(node);\n        require(owner == address(0) || owner == address(this), \"Cannot enable a name owned by someone else\");\n        if(owner != address(this)) {\n            if(parentNode == bytes32(0)) {\n                Root root = Root(ens.owner(bytes32(0)));\n                root.setSubnodeOwner(label, address(this));\n            } else {\n                ens.setSubnodeOwner(parentNode, label, address(this));\n            }\n        }\n        return node;\n    }\n}\n"
    },
    "contracts/registry/ENSRegistry.sol": {
      "content": "pragma solidity >=0.8.4;\n\nimport \"./ENS.sol\";\n\n/**\n * The ENS registry contract.\n */\ncontract ENSRegistry is ENS {\n\n    struct Record {\n        address owner;\n        address resolver;\n        uint64 ttl;\n    }\n\n    mapping (bytes32 => Record) records;\n    mapping (address => mapping(address => bool)) operators;\n\n    // Permits modifications only by the owner of the specified node.\n    modifier authorised(bytes32 node) {\n        address owner = records[node].owner;\n        require(owner == msg.sender || operators[owner][msg.sender]);\n        _;\n    }\n\n    /**\n     * @dev Constructs a new ENS registrar.\n     */\n    constructor() public {\n        records[0x0].owner = msg.sender;\n    }\n\n    /**\n     * @dev Sets the record for a node.\n     * @param node The node to update.\n     * @param owner The address of the new owner.\n     * @param resolver The address of the resolver.\n     * @param ttl The TTL in seconds.\n     */\n    function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external virtual override {\n        setOwner(node, owner);\n        _setResolverAndTTL(node, resolver, ttl);\n    }\n\n    /**\n     * @dev Sets the record for a subnode.\n     * @param node The parent node.\n     * @param label The hash of the label specifying the subnode.\n     * @param owner The address of the new owner.\n     * @param resolver The address of the resolver.\n     * @param ttl The TTL in seconds.\n     */\n    function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external virtual override {\n        bytes32 subnode = setSubnodeOwner(node, label, owner);\n        _setResolverAndTTL(subnode, resolver, ttl);\n    }\n\n    /**\n     * @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node.\n     * @param node The node to transfer ownership of.\n     * @param owner The address of the new owner.\n     */\n    function setOwner(bytes32 node, address owner) public virtual override authorised(node) {\n        _setOwner(node, owner);\n        emit Transfer(node, owner);\n    }\n\n    /**\n     * @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node.\n     * @param node The parent node.\n     * @param label The hash of the label specifying the subnode.\n     * @param owner The address of the new owner.\n     */\n    function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public virtual override authorised(node) returns(bytes32) {\n        bytes32 subnode = keccak256(abi.encodePacked(node, label));\n        _setOwner(subnode, owner);\n        emit NewOwner(node, label, owner);\n        return subnode;\n    }\n\n    /**\n     * @dev Sets the resolver address for the specified node.\n     * @param node The node to update.\n     * @param resolver The address of the resolver.\n     */\n    function setResolver(bytes32 node, address resolver) public virtual override authorised(node) {\n        emit NewResolver(node, resolver);\n        records[node].resolver = resolver;\n    }\n\n    /**\n     * @dev Sets the TTL for the specified node.\n     * @param node The node to update.\n     * @param ttl The TTL in seconds.\n     */\n    function setTTL(bytes32 node, uint64 ttl) public virtual override authorised(node) {\n        emit NewTTL(node, ttl);\n        records[node].ttl = ttl;\n    }\n\n    /**\n     * @dev Enable or disable approval for a third party (\"operator\") to manage\n     *  all of `msg.sender`'s ENS records. Emits the ApprovalForAll event.\n     * @param operator Address to add to the set of authorized operators.\n     * @param approved True if the operator is approved, false to revoke approval.\n     */\n    function setApprovalForAll(address operator, bool approved) external virtual override {\n        operators[msg.sender][operator] = approved;\n        emit ApprovalForAll(msg.sender, operator, approved);\n    }\n\n    /**\n     * @dev Returns the address that owns the specified node.\n     * @param node The specified node.\n     * @return address of the owner.\n     */\n    function owner(bytes32 node) public virtual override view returns (address) {\n        address addr = records[node].owner;\n        if (addr == address(this)) {\n            return address(0x0);\n        }\n\n        return addr;\n    }\n\n    /**\n     * @dev Returns the address of the resolver for the specified node.\n     * @param node The specified node.\n     * @return address of the resolver.\n     */\n    function resolver(bytes32 node) public virtual override view returns (address) {\n        return records[node].resolver;\n    }\n\n    /**\n     * @dev Returns the TTL of a node, and any records associated with it.\n     * @param node The specified node.\n     * @return ttl of the node.\n     */\n    function ttl(bytes32 node) public virtual override view returns (uint64) {\n        return records[node].ttl;\n    }\n\n    /**\n     * @dev Returns whether a record has been imported to the registry.\n     * @param node The specified node.\n     * @return Bool if record exists\n     */\n    function recordExists(bytes32 node) public virtual override view returns (bool) {\n        return records[node].owner != address(0x0);\n    }\n\n    /**\n     * @dev Query if an address is an authorized operator for another address.\n     * @param owner The address that owns the records.\n     * @param operator The address that acts on behalf of the owner.\n     * @return True if `operator` is an approved operator for `owner`, false otherwise.\n     */\n    function isApprovedForAll(address owner, address operator) external virtual override view returns (bool) {\n        return operators[owner][operator];\n    }\n\n    function _setOwner(bytes32 node, address owner) internal virtual {\n        records[node].owner = owner;\n    }\n\n    function _setResolverAndTTL(bytes32 node, address resolver, uint64 ttl) internal {\n        if(resolver != records[node].resolver) {\n            records[node].resolver = resolver;\n            emit NewResolver(node, resolver);\n        }\n\n        if(ttl != records[node].ttl) {\n            records[node].ttl = ttl;\n            emit NewTTL(node, ttl);\n        }\n    }\n}\n"
    },
    "contracts/root/Root.sol": {
      "content": "pragma solidity ^0.8.4;\n\nimport \"../registry/ENS.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./Controllable.sol\";\n\ncontract Root is Ownable, Controllable {\n    bytes32 private constant ROOT_NODE = bytes32(0);\n\n    bytes4 private constant INTERFACE_META_ID =\n        bytes4(keccak256(\"supportsInterface(bytes4)\"));\n\n    event TLDLocked(bytes32 indexed label);\n\n    ENS public ens;\n    mapping(bytes32 => bool) public locked;\n\n    constructor(ENS _ens) public {\n        ens = _ens;\n    }\n\n    function setSubnodeOwner(bytes32 label, address owner)\n        external\n        onlyController\n    {\n        require(!locked[label]);\n        ens.setSubnodeOwner(ROOT_NODE, label, owner);\n    }\n\n    function setResolver(address resolver) external onlyOwner {\n        ens.setResolver(ROOT_NODE, resolver);\n    }\n\n    function lock(bytes32 label) external onlyOwner {\n        emit TLDLocked(label);\n        locked[label] = true;\n    }\n\n    function supportsInterface(bytes4 interfaceID)\n        external\n        pure\n        returns (bool)\n    {\n        return interfaceID == INTERFACE_META_ID;\n    }\n}\n"
    },
    "contracts/dnsregistrar/PublicSuffixList.sol": {
      "content": "pragma solidity ^0.8.4;\n\ninterface PublicSuffixList {\n    function isPublicSuffix(bytes calldata name) external view returns(bool);\n}\n"
    },
    "contracts/resolvers/profiles/AddrResolver.sol": {
      "content": "pragma solidity >=0.8.4;\nimport \"../ResolverBase.sol\";\n\nabstract contract AddrResolver is ResolverBase {\n    bytes4 constant private ADDR_INTERFACE_ID = 0x3b3b57de;\n    bytes4 constant private ADDRESS_INTERFACE_ID = 0xf1cb7e06;\n    uint constant private COIN_TYPE_ETH = 60;\n\n    event AddrChanged(bytes32 indexed node, address a);\n    event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);\n\n    mapping(bytes32=>mapping(uint=>bytes)) _addresses;\n\n    /**\n     * Sets the address associated with an ENS node.\n     * May only be called by the owner of that node in the ENS registry.\n     * @param node The node to update.\n     * @param a The address to set.\n     */\n    function setAddr(bytes32 node, address a) external authorised(node) {\n        setAddr(node, COIN_TYPE_ETH, addressToBytes(a));\n    }\n\n    /**\n     * Returns the address associated with an ENS node.\n     * @param node The ENS node to query.\n     * @return The associated address.\n     */\n    function addr(bytes32 node) public view returns (address payable) {\n        bytes memory a = addr(node, COIN_TYPE_ETH);\n        if(a.length == 0) {\n            return payable(0);\n        }\n        return bytesToAddress(a);\n    }\n\n    function setAddr(bytes32 node, uint coinType, bytes memory a) public authorised(node) {\n        emit AddressChanged(node, coinType, a);\n        if(coinType == COIN_TYPE_ETH) {\n            emit AddrChanged(node, bytesToAddress(a));\n        }\n        _addresses[node][coinType] = a;\n    }\n\n    function addr(bytes32 node, uint coinType) public view returns(bytes memory) {\n        return _addresses[node][coinType];\n    }\n\n    function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {\n        return interfaceID == ADDR_INTERFACE_ID || interfaceID == ADDRESS_INTERFACE_ID || super.supportsInterface(interfaceID);\n    }\n\n    function bytesToAddress(bytes memory b) internal pure returns(address payable a) {\n        require(b.length == 20);\n        assembly {\n            a := div(mload(add(b, 32)), exp(256, 12))\n        }\n    }\n\n    function addressToBytes(address a) internal pure returns(bytes memory b) {\n        b = new bytes(20);\n        assembly {\n            mstore(add(b, 32), mul(a, exp(256, 12)))\n        }\n    }\n}\n"
    },
    "contracts/registry/ENS.sol": {
      "content": "pragma solidity >=0.8.4;\n\ninterface ENS {\n\n    // Logged when the owner of a node assigns a new owner to a subnode.\n    event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);\n\n    // Logged when the owner of a node transfers ownership to a new account.\n    event Transfer(bytes32 indexed node, address owner);\n\n    // Logged when the resolver for a node changes.\n    event NewResolver(bytes32 indexed node, address resolver);\n\n    // Logged when the TTL of a node changes\n    event NewTTL(bytes32 indexed node, uint64 ttl);\n\n    // Logged when an operator is added or removed.\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external virtual;\n    function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external virtual;\n    function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external virtual returns(bytes32);\n    function setResolver(bytes32 node, address resolver) external virtual;\n    function setOwner(bytes32 node, address owner) external virtual;\n    function setTTL(bytes32 node, uint64 ttl) external virtual;\n    function setApprovalForAll(address operator, bool approved) external virtual;\n    function owner(bytes32 node) external virtual view returns (address);\n    function resolver(bytes32 node) external virtual view returns (address);\n    function ttl(bytes32 node) external virtual view returns (uint64);\n    function recordExists(bytes32 node) external virtual view returns (bool);\n    function isApprovedForAll(address owner, address operator) external virtual view returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/access/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor () {\n        address msgSender = _msgSender();\n        _owner = msgSender;\n        emit OwnershipTransferred(address(0), msgSender);\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        emit OwnershipTransferred(_owner, address(0));\n        _owner = address(0);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        emit OwnershipTransferred(_owner, newOwner);\n        _owner = newOwner;\n    }\n}\n"
    },
    "contracts/root/Controllable.sol": {
      "content": "pragma solidity ^0.8.4;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract Controllable is Ownable {\n    mapping(address => bool) public controllers;\n\n    event ControllerChanged(address indexed controller, bool enabled);\n\n    modifier onlyController {\n        require(\n            controllers[msg.sender],\n            \"Controllable: Caller is not a controller\"\n        );\n        _;\n    }\n\n    function setController(address controller, bool enabled) public onlyOwner {\n        controllers[controller] = enabled;\n        emit ControllerChanged(controller, enabled);\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n        return msg.data;\n    }\n}\n"
    },
    "contracts/resolvers/ResolverBase.sol": {
      "content": "pragma solidity >=0.8.4;\nabstract contract ResolverBase {\n    bytes4 private constant INTERFACE_META_ID = 0x01ffc9a7;\n\n    function supportsInterface(bytes4 interfaceID) virtual public pure returns(bool) {\n        return interfaceID == INTERFACE_META_ID;\n    }\n\n    function isAuthorised(bytes32 node) internal virtual view returns(bool);\n\n    modifier authorised(bytes32 node) {\n        require(isAuthorised(node));\n        _;\n    }\n}\n"
    },
    "contracts/resolvers/PublicResolver.sol": {
      "content": "pragma solidity >=0.8.4;\n\nimport \"../registry/ENS.sol\";\nimport \"./profiles/ABIResolver.sol\";\nimport \"./profiles/AddrResolver.sol\";\nimport \"./profiles/ContentHashResolver.sol\";\nimport \"./profiles/DNSResolver.sol\";\nimport \"./profiles/InterfaceResolver.sol\";\nimport \"./profiles/NameResolver.sol\";\nimport \"./profiles/PubkeyResolver.sol\";\nimport \"./profiles/TextResolver.sol\";\n\ninterface INameWrapper {\n    function ownerOf(uint256 id) external view returns (address);\n}\n\n/**\n * A simple resolver anyone can use; only allows the owner of a node to set its\n * address.\n */\ncontract PublicResolver is ABIResolver, AddrResolver, ContentHashResolver, DNSResolver, InterfaceResolver, NameResolver, PubkeyResolver, TextResolver {\n    ENS ens;\n    INameWrapper nameWrapper;\n\n    /**\n     * A mapping of operators. An address that is authorised for an address\n     * may make any changes to the name that the owner could, but may not update\n     * the set of authorisations.\n     * (owner, operator) => approved\n     */\n    mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n    // Logged when an operator is added or removed.\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    constructor(ENS _ens, INameWrapper wrapperAddress){\n        ens = _ens;\n        nameWrapper = wrapperAddress;\n    }\n\n    /**\n     * @dev See {IERC1155-setApprovalForAll}.\n     */\n    function setApprovalForAll(address operator, bool approved) external{\n        require(\n            msg.sender != operator,\n            \"ERC1155: setting approval status for self\"\n        );\n\n        _operatorApprovals[msg.sender][operator] = approved;\n        emit ApprovalForAll(msg.sender, operator, approved);\n    }\n\n    function isAuthorised(bytes32 node) internal override view returns(bool) {\n        address owner = ens.owner(node);\n        if(owner == address(nameWrapper) ){\n            owner = nameWrapper.ownerOf(uint256(node));\n        }\n        return owner == msg.sender || isApprovedForAll(owner, msg.sender);\n    }\n\n    /**\n     * @dev See {IERC1155-isApprovedForAll}.\n     */\n    function isApprovedForAll(address account, address operator) public view returns (bool){\n        return _operatorApprovals[account][operator];\n    }\n\n    function multicall(bytes[] calldata data) external returns(bytes[] memory results) {\n        results = new bytes[](data.length);\n        for(uint i = 0; i < data.length; i++) {\n            (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n            require(success);\n            results[i] = result;\n        }\n        return results;\n    }\n\n    function supportsInterface(bytes4 interfaceID) virtual override(ABIResolver, AddrResolver, ContentHashResolver, DNSResolver, InterfaceResolver, NameResolver, PubkeyResolver, TextResolver) public pure returns(bool) {\n        return super.supportsInterface(interfaceID);\n    }\n}\n"
    },
    "contracts/resolvers/profiles/ABIResolver.sol": {
      "content": "pragma solidity >=0.8.4;\nimport \"../ResolverBase.sol\";\n\nabstract contract ABIResolver is ResolverBase {\n    bytes4 constant private ABI_INTERFACE_ID = 0x2203ab56;\n\n    event ABIChanged(bytes32 indexed node, uint256 indexed contentType);\n\n    mapping(bytes32=>mapping(uint256=>bytes)) abis;\n\n    /**\n     * Sets the ABI associated with an ENS node.\n     * Nodes may have one ABI of each content type. To remove an ABI, set it to\n     * the empty string.\n     * @param node The node to update.\n     * @param contentType The content type of the ABI\n     * @param data The ABI data.\n     */\n    function setABI(bytes32 node, uint256 contentType, bytes calldata data) external authorised(node) {\n        // Content types must be powers of 2\n        require(((contentType - 1) & contentType) == 0);\n\n        abis[node][contentType] = data;\n        emit ABIChanged(node, contentType);\n    }\n\n    /**\n     * Returns the ABI associated with an ENS node.\n     * Defined in EIP205.\n     * @param node The ENS node to query\n     * @param contentTypes A bitwise OR of the ABI formats accepted by the caller.\n     * @return contentType The content type of the return value\n     * @return data The ABI data\n     */\n    function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory) {\n        mapping(uint256=>bytes) storage abiset = abis[node];\n\n        for (uint256 contentType = 1; contentType <= contentTypes; contentType <<= 1) {\n            if ((contentType & contentTypes) != 0 && abiset[contentType].length > 0) {\n                return (contentType, abiset[contentType]);\n            }\n        }\n\n        return (0, bytes(\"\"));\n    }\n\n    function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {\n        return interfaceID == ABI_INTERFACE_ID || super.supportsInterface(interfaceID);\n    }\n}\n"
    },
    "contracts/resolvers/profiles/ContentHashResolver.sol": {
      "content": "pragma solidity >=0.8.4;\nimport \"../ResolverBase.sol\";\n\nabstract contract ContentHashResolver is ResolverBase {\n    bytes4 constant private CONTENT_HASH_INTERFACE_ID = 0xbc1c58d1;\n\n    event ContenthashChanged(bytes32 indexed node, bytes hash);\n\n    mapping(bytes32=>bytes) hashes;\n\n    /**\n     * Sets the contenthash associated with an ENS node.\n     * May only be called by the owner of that node in the ENS registry.\n     * @param node The node to update.\n     * @param hash The contenthash to set\n     */\n    function setContenthash(bytes32 node, bytes calldata hash) external authorised(node) {\n        hashes[node] = hash;\n        emit ContenthashChanged(node, hash);\n    }\n\n    /**\n     * Returns the contenthash associated with an ENS node.\n     * @param node The ENS node to query.\n     * @return The associated contenthash.\n     */\n    function contenthash(bytes32 node) external view returns (bytes memory) {\n        return hashes[node];\n    }\n\n    function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {\n        return interfaceID == CONTENT_HASH_INTERFACE_ID || super.supportsInterface(interfaceID);\n    }\n}\n"
    },
    "contracts/resolvers/profiles/DNSResolver.sol": {
      "content": "pragma solidity >=0.8.4;\nimport \"../ResolverBase.sol\";\nimport \"../../dnssec-oracle/RRUtils.sol\";\n\nabstract contract DNSResolver is ResolverBase {\n    using RRUtils for *;\n    using BytesUtils for bytes;\n\n    bytes4 constant private DNS_RECORD_INTERFACE_ID = 0xa8fa5682;\n    bytes4 constant private DNS_ZONE_INTERFACE_ID = 0x5c47637c;\n\n    // DNSRecordChanged is emitted whenever a given node/name/resource's RRSET is updated.\n    event DNSRecordChanged(bytes32 indexed node, bytes name, uint16 resource, bytes record);\n    // DNSRecordDeleted is emitted whenever a given node/name/resource's RRSET is deleted.\n    event DNSRecordDeleted(bytes32 indexed node, bytes name, uint16 resource);\n    // DNSZoneCleared is emitted whenever a given node's zone information is cleared.\n    event DNSZoneCleared(bytes32 indexed node);\n\n    // DNSZonehashChanged is emitted whenever a given node's zone hash is updated.\n    event DNSZonehashChanged(bytes32 indexed node, bytes lastzonehash, bytes zonehash);\n\n    // Zone hashes for the domains.\n    // A zone hash is an EIP-1577 content hash in binary format that should point to a\n    // resource containing a single zonefile.\n    // node => contenthash\n    mapping(bytes32=>bytes) private zonehashes;\n\n    // Version the mapping for each zone.  This allows users who have lost\n    // track of their entries to effectively delete an entire zone by bumping\n    // the version number.\n    // node => version\n    mapping(bytes32=>uint256) private versions;\n\n    // The records themselves.  Stored as binary RRSETs\n    // node => version => name => resource => data\n    mapping(bytes32=>mapping(uint256=>mapping(bytes32=>mapping(uint16=>bytes)))) private records;\n\n    // Count of number of entries for a given name.  Required for DNS resolvers\n    // when resolving wildcards.\n    // node => version => name => number of records\n    mapping(bytes32=>mapping(uint256=>mapping(bytes32=>uint16))) private nameEntriesCount;\n\n    /**\n     * Set one or more DNS records.  Records are supplied in wire-format.\n     * Records with the same node/name/resource must be supplied one after the\n     * other to ensure the data is updated correctly. For example, if the data\n     * was supplied:\n     *     a.example.com IN A 1.2.3.4\n     *     a.example.com IN A 5.6.7.8\n     *     www.example.com IN CNAME a.example.com.\n     * then this would store the two A records for a.example.com correctly as a\n     * single RRSET, however if the data was supplied:\n     *     a.example.com IN A 1.2.3.4\n     *     www.example.com IN CNAME a.example.com.\n     *     a.example.com IN A 5.6.7.8\n     * then this would store the first A record, the CNAME, then the second A\n     * record which would overwrite the first.\n     *\n     * @param node the namehash of the node for which to set the records\n     * @param data the DNS wire format records to set\n     */\n    function setDNSRecords(bytes32 node, bytes calldata data) external authorised(node) {\n        uint16 resource = 0;\n        uint256 offset = 0;\n        bytes memory name;\n        bytes memory value;\n        bytes32 nameHash;\n        // Iterate over the data to add the resource records\n        for (RRUtils.RRIterator memory iter = data.iterateRRs(0); !iter.done(); iter.next()) {\n            if (resource == 0) {\n                resource = iter.dnstype;\n                name = iter.name();\n                nameHash = keccak256(abi.encodePacked(name));\n                value = bytes(iter.rdata());\n            } else {\n                bytes memory newName = iter.name();\n                if (resource != iter.dnstype || !name.equals(newName)) {\n                    setDNSRRSet(node, name, resource, data, offset, iter.offset - offset, value.length == 0);\n                    resource = iter.dnstype;\n                    offset = iter.offset;\n                    name = newName;\n                    nameHash = keccak256(name);\n                    value = bytes(iter.rdata());\n                }\n            }\n        }\n        if (name.length > 0) {\n            setDNSRRSet(node, name, resource, data, offset, data.length - offset, value.length == 0);\n        }\n    }\n\n    /**\n     * Obtain a DNS record.\n     * @param node the namehash of the node for which to fetch the record\n     * @param name the keccak-256 hash of the fully-qualified name for which to fetch the record\n     * @param resource the ID of the resource as per https://en.wikipedia.org/wiki/List_of_DNS_record_types\n     * @return the DNS record in wire format if present, otherwise empty\n     */\n    function dnsRecord(bytes32 node, bytes32 name, uint16 resource) public view returns (bytes memory) {\n        return records[node][versions[node]][name][resource];\n    }\n\n    /**\n     * Check if a given node has records.\n     * @param node the namehash of the node for which to check the records\n     * @param name the namehash of the node for which to check the records\n     */\n    function hasDNSRecords(bytes32 node, bytes32 name) public view returns (bool) {\n        return (nameEntriesCount[node][versions[node]][name] != 0);\n    }\n\n    /**\n     * Clear all information for a DNS zone.\n     * @param node the namehash of the node for which to clear the zone\n     */\n    function clearDNSZone(bytes32 node) public authorised(node) {\n        versions[node]++;\n        emit DNSZoneCleared(node);\n    }\n\n    /**\n     * setZonehash sets the hash for the zone.\n     * May only be called by the owner of that node in the ENS registry.\n     * @param node The node to update.\n     * @param hash The zonehash to set\n     */\n    function setZonehash(bytes32 node, bytes calldata hash) external authorised(node) {\n        bytes memory oldhash = zonehashes[node];\n        zonehashes[node] = hash;\n        emit DNSZonehashChanged(node, oldhash, hash);\n    }\n\n    /**\n     * zonehash obtains the hash for the zone.\n     * @param node The ENS node to query.\n     * @return The associated contenthash.\n     */\n    function zonehash(bytes32 node) external view returns (bytes memory) {\n        return zonehashes[node];\n    }\n\n    function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {\n        return interfaceID == DNS_RECORD_INTERFACE_ID ||\n               interfaceID == DNS_ZONE_INTERFACE_ID ||\n               super.supportsInterface(interfaceID);\n    }\n\n    function setDNSRRSet(\n        bytes32 node,\n        bytes memory name,\n        uint16 resource,\n        bytes memory data,\n        uint256 offset,\n        uint256 size,\n        bool deleteRecord) private\n    {\n        uint256 version = versions[node];\n        bytes32 nameHash = keccak256(name);\n        bytes memory rrData = data.substring(offset, size);\n        if (deleteRecord) {\n            if (records[node][version][nameHash][resource].length != 0) {\n                nameEntriesCount[node][version][nameHash]--;\n            }\n            delete(records[node][version][nameHash][resource]);\n            emit DNSRecordDeleted(node, name, resource);\n        } else {\n            if (records[node][version][nameHash][resource].length == 0) {\n                nameEntriesCount[node][version][nameHash]++;\n            }\n            records[node][version][nameHash][resource] = rrData;\n            emit DNSRecordChanged(node, name, resource, rrData);\n        }\n    }\n}\n"
    },
    "contracts/resolvers/profiles/InterfaceResolver.sol": {
      "content": "pragma solidity >=0.8.4;\nimport \"../ResolverBase.sol\";\nimport \"./AddrResolver.sol\";\n\nabstract contract InterfaceResolver is ResolverBase, AddrResolver {\n    bytes4 constant private INTERFACE_INTERFACE_ID = bytes4(keccak256(\"interfaceImplementer(bytes32,bytes4)\"));\n    bytes4 private constant INTERFACE_META_ID = 0x01ffc9a7;\n\n    event InterfaceChanged(bytes32 indexed node, bytes4 indexed interfaceID, address implementer);\n\n    mapping(bytes32=>mapping(bytes4=>address)) interfaces;\n\n    /**\n     * Sets an interface associated with a name.\n     * Setting the address to 0 restores the default behaviour of querying the contract at `addr()` for interface support.\n     * @param node The node to update.\n     * @param interfaceID The EIP 165 interface ID.\n     * @param implementer The address of a contract that implements this interface for this node.\n     */\n    function setInterface(bytes32 node, bytes4 interfaceID, address implementer) external authorised(node) {\n        interfaces[node][interfaceID] = implementer;\n        emit InterfaceChanged(node, interfaceID, implementer);\n    }\n\n    /**\n     * Returns the address of a contract that implements the specified interface for this name.\n     * If an implementer has not been set for this interfaceID and name, the resolver will query\n     * the contract at `addr()`. If `addr()` is set, a contract exists at that address, and that\n     * contract implements EIP165 and returns `true` for the specified interfaceID, its address\n     * will be returned.\n     * @param node The ENS node to query.\n     * @param interfaceID The EIP 165 interface ID to check for.\n     * @return The address that implements this interface, or 0 if the interface is unsupported.\n     */\n    function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address) {\n        address implementer = interfaces[node][interfaceID];\n        if(implementer != address(0)) {\n            return implementer;\n        }\n\n        address a = addr(node);\n        if(a == address(0)) {\n            return address(0);\n        }\n\n        (bool success, bytes memory returnData) = a.staticcall(abi.encodeWithSignature(\"supportsInterface(bytes4)\", INTERFACE_META_ID));\n        if(!success || returnData.length < 32 || returnData[31] == 0) {\n            // EIP 165 not supported by target\n            return address(0);\n        }\n\n        (success, returnData) = a.staticcall(abi.encodeWithSignature(\"supportsInterface(bytes4)\", interfaceID));\n        if(!success || returnData.length < 32 || returnData[31] == 0) {\n            // Specified interface not supported by target\n            return address(0);\n        }\n\n        return a;\n    }\n\n    function supportsInterface(bytes4 interfaceID) virtual override(AddrResolver, ResolverBase) public pure returns(bool) {\n        return interfaceID == INTERFACE_INTERFACE_ID || super.supportsInterface(interfaceID);\n    }\n}\n"
    },
    "contracts/resolvers/profiles/NameResolver.sol": {
      "content": "pragma solidity >=0.8.4;\nimport \"../ResolverBase.sol\";\n\nabstract contract NameResolver is ResolverBase {\n    bytes4 constant private NAME_INTERFACE_ID = 0x691f3431;\n\n    event NameChanged(bytes32 indexed node, string name);\n\n    mapping(bytes32=>string) names;\n\n    /**\n     * Sets the name associated with an ENS node, for reverse records.\n     * May only be called by the owner of that node in the ENS registry.\n     * @param node The node to update.\n     * @param name The name to set.\n     */\n    function setName(bytes32 node, string calldata name) external authorised(node) {\n        names[node] = name;\n        emit NameChanged(node, name);\n    }\n\n    /**\n     * Returns the name associated with an ENS node, for reverse records.\n     * Defined in EIP181.\n     * @param node The ENS node to query.\n     * @return The associated name.\n     */\n    function name(bytes32 node) external view returns (string memory) {\n        return names[node];\n    }\n\n    function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {\n        return interfaceID == NAME_INTERFACE_ID || super.supportsInterface(interfaceID);\n    }\n}\n"
    },
    "contracts/resolvers/profiles/PubkeyResolver.sol": {
      "content": "pragma solidity >=0.8.4;\nimport \"../ResolverBase.sol\";\n\nabstract contract PubkeyResolver is ResolverBase {\n    bytes4 constant private PUBKEY_INTERFACE_ID = 0xc8690233;\n\n    event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);\n\n    struct PublicKey {\n        bytes32 x;\n        bytes32 y;\n    }\n\n    mapping(bytes32=>PublicKey) pubkeys;\n\n    /**\n     * Sets the SECP256k1 public key associated with an ENS node.\n     * @param node The ENS node to query\n     * @param x the X coordinate of the curve point for the public key.\n     * @param y the Y coordinate of the curve point for the public key.\n     */\n    function setPubkey(bytes32 node, bytes32 x, bytes32 y) external authorised(node) {\n        pubkeys[node] = PublicKey(x, y);\n        emit PubkeyChanged(node, x, y);\n    }\n\n    /**\n     * Returns the SECP256k1 public key associated with an ENS node.\n     * Defined in EIP 619.\n     * @param node The ENS node to query\n     * @return x The X coordinate of the curve point for the public key.\n     * @return y The Y coordinate of the curve point for the public key.\n     */\n    function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y) {\n        return (pubkeys[node].x, pubkeys[node].y);\n    }\n\n    function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {\n        return interfaceID == PUBKEY_INTERFACE_ID || super.supportsInterface(interfaceID);\n    }\n}\n"
    },
    "contracts/resolvers/profiles/TextResolver.sol": {
      "content": "pragma solidity >=0.8.4;\nimport \"../ResolverBase.sol\";\n\nabstract contract TextResolver is ResolverBase {\n    bytes4 constant private TEXT_INTERFACE_ID = 0x59d1d43c;\n\n    event TextChanged(bytes32 indexed node, string indexed indexedKey, string key);\n\n    mapping(bytes32=>mapping(string=>string)) texts;\n\n    /**\n     * Sets the text data associated with an ENS node and key.\n     * May only be called by the owner of that node in the ENS registry.\n     * @param node The node to update.\n     * @param key The key to set.\n     * @param value The text data value to set.\n     */\n    function setText(bytes32 node, string calldata key, string calldata value) external authorised(node) {\n        texts[node][key] = value;\n        emit TextChanged(node, key, key);\n    }\n\n    /**\n     * Returns the text data associated with an ENS node and key.\n     * @param node The ENS node to query.\n     * @param key The text data key to query.\n     * @return The associated text data.\n     */\n    function text(bytes32 node, string calldata key) external view returns (string memory) {\n        return texts[node][key];\n    }\n\n    function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {\n        return interfaceID == TEXT_INTERFACE_ID || super.supportsInterface(interfaceID);\n    }\n}\n"
    },
    "contracts/resolvers/OwnedResolver.sol": {
      "content": "pragma solidity >=0.8.4;\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./profiles/ABIResolver.sol\";\nimport \"./profiles/AddrResolver.sol\";\nimport \"./profiles/ContentHashResolver.sol\";\nimport \"./profiles/DNSResolver.sol\";\nimport \"./profiles/InterfaceResolver.sol\";\nimport \"./profiles/NameResolver.sol\";\nimport \"./profiles/PubkeyResolver.sol\";\nimport \"./profiles/TextResolver.sol\";\n\n/**\n * A simple resolver anyone can use; only allows the owner of a node to set its\n * address.\n */\ncontract OwnedResolver is Ownable, ABIResolver, AddrResolver, ContentHashResolver, DNSResolver, InterfaceResolver, NameResolver, PubkeyResolver, TextResolver {\n    function isAuthorised(bytes32 node) internal override view returns(bool) {\n        return msg.sender == owner();\n    }\n\n    function supportsInterface(bytes4 interfaceID) virtual override(ABIResolver, AddrResolver, ContentHashResolver, DNSResolver, InterfaceResolver, NameResolver, PubkeyResolver, TextResolver) public pure returns(bool) {\n        return super.supportsInterface(interfaceID);\n    }\n}\n"
    },
    "test/dnssec-oracle/TestRRUtils.sol": {
      "content": "pragma solidity ^0.8.4;\n\nimport \"../../contracts/dnssec-oracle/RRUtils.sol\";\nimport \"../../contracts/dnssec-oracle/BytesUtils.sol\";\n\ncontract TestRRUtils {\n  using BytesUtils for *;\n  using RRUtils for *;\n\n  uint16 constant DNSTYPE_A = 1;\n  uint16 constant DNSTYPE_CNAME = 5;\n  uint16 constant DNSTYPE_MX = 15;\n  uint16 constant DNSTYPE_TEXT = 16;\n  uint16 constant DNSTYPE_RRSIG = 46;\n  uint16 constant DNSTYPE_NSEC = 47;\n  uint16 constant DNSTYPE_TYPE1234 = 1234;\n\n  function testNameLength() public pure {\n    require(hex'00'.nameLength(0) == 1, \"nameLength('.') == 1\");\n    require(hex'0361626300'.nameLength(4) == 1, \"nameLength('.') == 1\");\n    require(hex'0361626300'.nameLength(0) == 5, \"nameLength('abc.') == 5\");\n  }\n\n  function testLabelCount() public pure {\n    require(hex'00'.labelCount(0) == 0, \"labelCount('.') == 0\");\n    require(hex'016100'.labelCount(0) == 1, \"labelCount('a.') == 1\");\n    require(hex'016201610000'.labelCount(0) == 2, \"labelCount('b.a.') == 2\");\n    require(hex'066574686c61620378797a00'.labelCount(6 +1) == 1, \"nameLength('(bthlab).xyz.') == 6\");\n  }\n\n  function testIterateRRs() public pure {\n    // a. IN A 3600 127.0.0.1\n    // b.a. IN A 3600 192.168.1.1\n    bytes memory rrs = hex'0161000001000100000e1000047400000101620161000001000100000e100004c0a80101';\n    string[2] memory names = [hex'016100', hex'0162016100'];\n    string[2] memory rdatas = [hex'74000001', hex'c0a80101'];\n    uint i = 0;\n    for(RRUtils.RRIterator memory iter = rrs.iterateRRs(0); !iter.done(); iter.next()) {\n      require(uint(iter.dnstype) == 1, \"Type matches\");\n      require(uint(iter.class) == 1, \"Class matches\");\n      require(uint(iter.ttl) == 3600, \"TTL matches\");\n      require(keccak256(iter.name()) == keccak256(bytes(names[i])), \"Name matches\");\n      require(keccak256(iter.rdata()) == keccak256(bytes(rdatas[i])), \"Rdata matches\");\n      i++;\n    }\n    require(i == 2, \"Expected 2 records\");\n  }\n\n  function testCheckTypeBitmapTextType() public pure {\n    bytes memory tb = hex'0003000080';\n    require(tb.checkTypeBitmap(0, DNSTYPE_TEXT) == true, \"A record should exist in type bitmap\");\n  }\n\n  function testCheckTypeBitmap() public pure {\n    // From https://tools.ietf.org/html/rfc4034#section-4.3\n    //    alfa.example.com. 86400 IN NSEC host.example.com. (\n    //                               A MX RRSIG NSEC TYPE1234\n    bytes memory tb = hex'FF0006400100000003041b000000000000000000000000000000000000000000000000000020';\n\n    // Exists in bitmap\n    require(tb.checkTypeBitmap(1, DNSTYPE_A) == true, \"A record should exist in type bitmap\");\n    // Does not exist, but in a window that is included\n    require(tb.checkTypeBitmap(1, DNSTYPE_CNAME) == false, \"CNAME record should not exist in type bitmap\");\n    // Does not exist, past the end of a window that is included\n    require(tb.checkTypeBitmap(1, 64) == false, \"Type 64 should not exist in type bitmap\");\n    // Does not exist, in a window that does not exist\n    require(tb.checkTypeBitmap(1, 769) == false, \"Type 769 should not exist in type bitmap\");\n    // Exists in a subsequent window\n    require(tb.checkTypeBitmap(1, DNSTYPE_TYPE1234) == true, \"Type 1234 should exist in type bitmap\");\n    // Does not exist, past the end of the bitmap windows\n    require(tb.checkTypeBitmap(1, 1281) == false, \"Type 1281 should not exist in type bitmap\");\n  }\n\n  // Canonical ordering https://tools.ietf.org/html/rfc4034#section-6.1\n  function testCompareNames() public pure {\n    bytes memory bthLabXyz = hex'066274686c61620378797a00';\n    bytes memory ethLabXyz = hex'066574686c61620378797a00';\n    bytes memory xyz = hex'0378797a00';\n    bytes memory a_b_c  = hex'01610162016300';\n    bytes memory b_b_c  = hex'01620162016300';\n    bytes memory c      = hex'016300';\n    bytes memory d      = hex'016400';\n    bytes memory a_d_c  = hex'01610164016300';\n    bytes memory b_a_c  = hex'01620161016300';\n    bytes memory ab_c_d = hex'0261620163016400';\n    bytes memory a_c_d  = hex'01610163016400';\n\n    require(hex'0301616100'.compareNames(hex'0302616200') <  0,  \"label lengths are correctly checked\");\n    require(a_b_c.compareNames(c)      >  0,  \"one name has a difference of >1 label to with the same root name\");\n    require(a_b_c.compareNames(d)      <  0, \"one name has a difference of >1 label to with different root name\");\n    require(a_b_c.compareNames(a_d_c)  <  0, \"two names start the same but have differences in later labels\");\n    require(a_b_c.compareNames(b_a_c)  >  0, \"the first label sorts later, but the first label sorts earlier\");\n    require(ab_c_d.compareNames(a_c_d) >  0, \"two names where the first label on one is a prefix of the first label on the other\");\n    require(a_b_c.compareNames(b_b_c)  <  0, \"two names where the first label on one is a prefix of the first label on the other\");\n    require(xyz.compareNames(ethLabXyz) < 0, \"xyz comes before ethLab.xyz\");\n    require(bthLabXyz.compareNames(ethLabXyz) < 0, \"bthLab.xyz comes before ethLab.xyz\");\n    require(bthLabXyz.compareNames(bthLabXyz) == 0, \"bthLab.xyz and bthLab.xyz are the same\");\n    require(ethLabXyz.compareNames(bthLabXyz) >  0, \"ethLab.xyz comes after bethLab.xyz\");\n    require(bthLabXyz.compareNames(xyz)       >  0, \"bthLab.xyz comes after xyz\");\n  }\n\n  function testSerialNumberGt() public pure {\n    require(RRUtils.serialNumberGte(1, 0), \"1 >= 0\");\n    require(!RRUtils.serialNumberGte(0, 1), \"!(0 <= 1)\");\n    require(RRUtils.serialNumberGte(0, 0xFFFFFFFF), \"0 >= 0xFFFFFFFF\");\n    require(!RRUtils.serialNumberGte(0xFFFFFFFF, 0), \"!(0 <= 0xFFFFFFFF)\");\n    require(RRUtils.serialNumberGte(0x11111111, 0xAAAAAAAA), \"0x11111111 >= 0xAAAAAAAA\");\n    require(RRUtils.serialNumberGte(1, 1), \"1 >= 1\");\n  }\n\n  function testKeyTag() public view {\n    require(hex'0101030803010001a80020a95566ba42e886bb804cda84e47ef56dbd7aec612615552cec906d2116d0ef207028c51554144dfeafe7c7cb8f005dd18234133ac0710a81182ce1fd14ad2283bc83435f9df2f6313251931a176df0da51e54f42e604860dfb359580250f559cc543c4ffd51cbe3de8cfd06719237f9fc47ee729da06835fa452e825e9a18ebc2ecbcf563474652c33cf56a9033bcdf5d973121797ec8089041b6e03a1b72d0a735b984e03687309332324f27c2dba85e9db15e83a0143382e974b0621c18e625ecec907577d9e7bade95241a81ebbe8a901d4d3276e40b114c0a2e6fc38d19c2e6aab02644b2813f575fc21601e0dee49cd9ee96a43103e524d62873d'.computeKeytag() == 19036, \"Invalid keytag\");\n    require(hex'010003050440000003ba2fa05a75e173bede89eb71831ab14035f2408ad09df4d8dc8f8f72e8f13506feaddf7b04cb14958b82966e3420562302c4002bc4fd088432e160519bb14dae82443850c1423e06085710b5caf070d46b7ba7e481414f6a5fe225fdca984c959091645d0cf1c9a1a313d7e7fb7ba60b967b71a65f8cef2c3768e11b081c8fcf'.computeKeytag() == 21693, \"Invalid keytag (2)\");\n    require(hex'0100030503010001bfa54c38d909fabb0f937d70d775ba0df4c0badb09707d995249406950407a621c794c68b186b15dbf8f9f9ea231e9f96414ccda4eceb50b17a9ac6c4bd4b95da04849e96ee791578b703bc9ae184fb1794bac792a0787f693a40f19f523ee6dbd3599dbaaa9a50437926ecf6438845d1d49448962524f2a1a7a36b3a0a1eca3'.computeKeytag() == 33630);\n    require(hex'0101030803010001acffb409bcc939f831f7a1e5ec88f7a59255ec53040be432027390a4ce896d6f9086f3c5e177fbfe118163aaec7af1462c47945944c4e2c026be5e98bbcded25978272e1e3e079c5094d573f0e83c92f02b32d3513b1550b826929c80dd0f92cac966d17769fd5867b647c3f38029abdc48152eb8f207159ecc5d232c7c1537c79f4b7ac28ff11682f21681bf6d6aba555032bf6f9f036beb2aaa5b3778d6eebfba6bf9ea191be4ab0caea759e2f773a1f9029c73ecb8d5735b9321db085f1b8e2d8038fe2941992548cee0d67dd4547e11dd63af9c9fc1c5466fb684cf009d7197c2cf79e792ab501e6a8a1ca519af2cb9b5f6367e94c0d47502451357be1b5'.computeKeytag() == 20326, \"Invalid keytag (3)\");\n  }\n}"
    },
    "test/dnssec-oracle/TestBytesUtils.sol": {
      "content": "pragma solidity ^0.8.4;\n\nimport \"../../contracts/dnssec-oracle/RRUtils.sol\";\nimport \"../../contracts/dnssec-oracle/BytesUtils.sol\";\n\ncontract TestBytesUtils {\n  using BytesUtils for *;\n\n  function testKeccak() public pure {\n    require(\"\".keccak(0, 0) == bytes32(0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470), \"Incorrect hash of empty string\");\n    require(\"foo\".keccak(0, 3) == bytes32(0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d), \"Incorrect hash of 'foo'\");\n    require(\"foo\".keccak(0, 0) == bytes32(0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470), \"Incorrect hash of empty string\");\n  }\n\n  function testEquals() public pure {\n    require(\"hello\".equals(\"hello\") == true, \"String equality\");\n    require(\"hello\".equals(\"goodbye\") == false, \"String inequality\");\n    require(\"hello\".equals(1, \"ello\") == true, \"Substring to string equality\");\n    require(\"hello\".equals(1, \"jello\", 1, 4) == true, \"Substring to substring equality\");\n    require(\"zhello\".equals(1, \"abchello\", 3) == true,   \"Compare different value with multiple length\");\n  }\n\n  function testComparePartial() public pure {\n    require(\"xax\".compare(1, 1, \"xxbxx\", 2, 1)   < 0 == true,  \"Compare same length\");\n    require(\"xax\".compare(1, 1, \"xxabxx\", 2, 2)  < 0 == true,  \"Compare different length\");\n    require(\"xax\".compare(1, 1, \"xxaxx\", 2, 1)  == 0 == true,  \"Compare same with different offset\");\n  }\n\n  function testCompare() public pure {\n    require(\"a\".compare(\"a\")  == 0 == true,  \"Compare equal\");\n    require(\"a\".compare(\"b\")   < 0 == true,   \"Compare different value with same length\");\n    require(\"b\".compare(\"a\")   > 0 == true,   \"Compare different value with same length\");\n    require(\"aa\".compare(\"ab\") < 0 == true,   \"Compare different value with multiple length\");\n    require(\"a\".compare(\"aa\")  < 0 == true,   \"Compare different value with different length\");\n    require(\"aa\".compare(\"a\")  > 0 == true,   \"Compare different value with different length\");\n    bytes memory longChar = \"1234567890123456789012345678901234\";\n    require(longChar.compare(longChar) == 0 == true,   \"Compares more than 32 bytes char\");\n    bytes memory otherLongChar = \"2234567890123456789012345678901234\";\n    require(longChar.compare(otherLongChar) < 0 == true,   \"Compare long char with difference at start\");\n  }\n\n  function testSubstring() public pure {\n    require(keccak256(bytes(\"hello\".substring(0, 0))) == keccak256(bytes(\"\")), \"Copy 0 bytes\");\n    require(keccak256(bytes(\"hello\".substring(0, 4))) == keccak256(bytes(\"hell\")), \"Copy substring\");\n    require(keccak256(bytes(\"hello\".substring(1, 4))) == keccak256(bytes(\"ello\")), \"Copy substring\");\n    require(keccak256(bytes(\"hello\".substring(0, 5))) == keccak256(bytes(\"hello\")), \"Copy whole string\");\n  }\n\n  function testReadUint8() public pure {\n    require(uint(\"a\".readUint8(0)) == 0x61, \"a == 0x61\");\n    require(uint(\"ba\".readUint8(1)) == 0x61, \"a == 0x61\");\n  }\n\n  function testReadUint16() public pure {\n    require(uint(\"abc\".readUint16(1)) == 0x6263, \"Read uint 16\");\n  }\n\n  function testReadUint32() public pure {\n    require(uint(\"abcde\".readUint32(1)) == 0x62636465, \"Read uint 32\");\n  }\n\n  function testReadBytes20() public pure {\n    require(bytes32(\"abcdefghijklmnopqrstuv\".readBytes20(1)) == bytes32(0x62636465666768696a6b6c6d6e6f707172737475000000000000000000000000), \"readBytes20\");\n  }\n\n  function testReadBytes32() public pure {\n    require(\"0123456789abcdef0123456789abcdef\".readBytes32(0) == bytes32(0x3031323334353637383961626364656630313233343536373839616263646566), \"readBytes32\");\n  }\n\n  function testBase32HexDecodeWord() public pure {\n    require(\"C4\".base32HexDecodeWord(0, 2) == bytes32(bytes1(\"a\")), \"Decode 'a'\");\n    require(\"C5GG\".base32HexDecodeWord(0, 4) == bytes32(bytes2(\"aa\")), \"Decode 'aa'\");\n    require(\"C5GM2\".base32HexDecodeWord(0, 5) == bytes32(bytes3(\"aaa\")), \"Decode 'aaa'\");\n    require(\"C5GM2O8\".base32HexDecodeWord(0, 7) == bytes32(bytes4(\"aaaa\")), \"Decode 'aaaa'\");\n    require(\"C5GM2OB1\".base32HexDecodeWord(0, 8) == bytes32(bytes5(\"aaaaa\")), \"Decode 'aaaaa'\");\n    require(\"c5gm2Ob1\".base32HexDecodeWord(0, 8) == bytes32(bytes5(\"aaaaa\")), \"Decode 'aaaaa' lowercase\");\n    require(\"C5H66P35CPJMGQBADDM6QRJFE1ON4SRKELR7EU3PF8\".base32HexDecodeWord(0, 42) == bytes32(bytes26(\"abcdefghijklmnopqrstuvwxyz\")), \"Decode alphabet\");\n    require(\"c5h66p35cpjmgqbaddm6qrjfe1on4srkelr7eu3pf8\".base32HexDecodeWord(0, 42) == bytes32(bytes26(\"abcdefghijklmnopqrstuvwxyz\")), \"Decode alphabet lowercase\");\n    require(\"C5GM2OB1C5GM2OB1C5GM2OB1C5GM2OB1C5GM2OB1C5GM2OB1C5GG\".base32HexDecodeWord(0, 52) == bytes32(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"), \"Decode 32*'a'\");\n    require(\" bst4hlje7r0o8c8p4o8q582lm0ejmiqt\\x07matoken\\x03xyz\\x00\".base32HexDecodeWord(1, 32) == bytes32(hex\"5f3a48d66e3ec18431192611a2a055b01d3b4b5d\"), \"Decode real bytes32hex\");\n  }\n}"
    },
    "contracts/dnssec-oracle/DNSSECImpl.sol": {
      "content": "pragma solidity ^0.8.4;\npragma experimental ABIEncoderV2;\n\nimport \"./Owned.sol\";\nimport \"./BytesUtils.sol\";\nimport \"./RRUtils.sol\";\nimport \"./DNSSEC.sol\";\nimport \"./algorithms/Algorithm.sol\";\nimport \"./digests/Digest.sol\";\nimport \"./nsec3digests/NSEC3Digest.sol\";\nimport \"@ensdomains/buffer/contracts/Buffer.sol\";\n\n/*\n * @dev An oracle contract that verifies and stores DNSSEC-validated DNS records.\n *\n * TODO: Support for NSEC3 records\n */\ncontract DNSSECImpl is DNSSEC, Owned {\n    using Buffer for Buffer.buffer;\n    using BytesUtils for bytes;\n    using RRUtils for *;\n\n    uint16 constant DNSCLASS_IN = 1;\n\n    uint16 constant DNSTYPE_NS = 2;\n    uint16 constant DNSTYPE_SOA = 6;\n    uint16 constant DNSTYPE_DNAME = 39;\n    uint16 constant DNSTYPE_DS = 43;\n    uint16 constant DNSTYPE_RRSIG = 46;\n    uint16 constant DNSTYPE_NSEC = 47;\n    uint16 constant DNSTYPE_DNSKEY = 48;\n    uint16 constant DNSTYPE_NSEC3 = 50;\n\n    uint constant DNSKEY_FLAG_ZONEKEY = 0x100;\n\n    uint8 constant ALGORITHM_RSASHA256 = 8;\n\n    uint8 constant DIGEST_ALGORITHM_SHA256 = 2;\n\n    struct RRSet {\n        uint32 inception;\n        uint32 expiration;\n        bytes20 hash;\n    }\n\n    // (name, type) => RRSet\n    mapping (bytes32 => mapping(uint16 => RRSet)) rrsets;\n\n    mapping (uint8 => Algorithm) public algorithms;\n    mapping (uint8 => Digest) public digests;\n    mapping (uint8 => NSEC3Digest) public nsec3Digests;\n\n    event Test(uint t);\n    event Marker();\n\n    /**\n     * @dev Constructor.\n     * @param _anchors The binary format RR entries for the root DS records.\n     */\n    constructor(bytes memory _anchors) {\n        // Insert the 'trust anchors' - the key hashes that start the chain\n        // of trust for all other records.\n        anchors = _anchors;\n        rrsets[keccak256(hex\"00\")][DNSTYPE_DS] = RRSet({\n            inception: uint32(0),\n            expiration: uint32(3767581600), // May 22 2089 - the latest date we can encode as of writing this\n            hash: bytes20(keccak256(anchors))\n        });\n        emit RRSetUpdated(hex\"00\", anchors);\n    }\n\n    /**\n     * @dev Sets the contract address for a signature verification algorithm.\n     *      Callable only by the owner.\n     * @param id The algorithm ID\n     * @param algo The address of the algorithm contract.\n     */\n    function setAlgorithm(uint8 id, Algorithm algo) public owner_only {\n        algorithms[id] = algo;\n        emit AlgorithmUpdated(id, address(algo));\n    }\n\n    /**\n     * @dev Sets the contract address for a digest verification algorithm.\n     *      Callable only by the owner.\n     * @param id The digest ID\n     * @param digest The address of the digest contract.\n     */\n    function setDigest(uint8 id, Digest digest) public owner_only {\n        digests[id] = digest;\n        emit DigestUpdated(id, address(digest));\n    }\n\n    /**\n     * @dev Sets the contract address for an NSEC3 digest algorithm.\n     *      Callable only by the owner.\n     * @param id The digest ID\n     * @param digest The address of the digest contract.\n     */\n    function setNSEC3Digest(uint8 id, NSEC3Digest digest) public owner_only {\n        nsec3Digests[id] = digest;\n        emit NSEC3DigestUpdated(id, address(digest));\n    }\n\n    /**\n     * @dev Submits multiple RRSets\n     * @param input A list of RRSets and signatures forming a chain of trust from an existing known-good record.\n     * @param _proof The DNSKEY or DS to validate the first signature against.\n     * @return The last RRSET submitted.\n     */\n    function submitRRSets(RRSetWithSignature[] memory input, bytes calldata _proof) public override returns (bytes memory) {\n        bytes memory proof = _proof;\n        for(uint i = 0; i < input.length; i++) {\n            proof = _submitRRSet(input[i], proof);\n        }\n        return proof;\n    }\n\n    /**\n     * @dev Submits a signed set of RRs to the oracle.\n     *\n     * RRSETs are only accepted if they are signed with a key that is already\n     * trusted, or if they are self-signed, and the signing key is identified by\n     * a DS record that is already trusted.\n     *\n     * @param input The signed RR set. This is in the format described in section\n     *        5.3.2 of RFC4035: The RRDATA section from the RRSIG without the signature\n     *        data, followed by a series of canonicalised RR records that the signature\n     *        applies to.\n     * @param proof The DNSKEY or DS to validate the signature against. Must Already\n     *        have been submitted and proved previously.\n     */\n    function submitRRSet(RRSetWithSignature memory input, bytes memory proof)\n        public override\n        returns (bytes memory)\n    {\n        return _submitRRSet(input, proof);\n    }\n\n    /**\n     * @dev Deletes an RR from the oracle.\n     *\n     * @param deleteType The DNS record type to delete.\n     * @param deleteName which you want to delete\n     * @param nsec The signed NSEC RRset. This is in the format described in section\n     *        5.3.2 of RFC4035: The RRDATA section from the RRSIG without the signature\n     *        data, followed by a series of canonicalised RR records that the signature\n     *        applies to.\n     */\n    function deleteRRSet(uint16 deleteType, bytes memory deleteName, RRSetWithSignature memory nsec, bytes memory proof)\n        public override\n    {\n        RRUtils.SignedSet memory rrset;\n        rrset = validateSignedSet(nsec, proof);\n        require(rrset.typeCovered == DNSTYPE_NSEC);\n\n        // Don't let someone use an old proof to delete a new name\n        require(RRUtils.serialNumberGte(rrset.inception, rrsets[keccak256(deleteName)][deleteType].inception));\n\n        for (RRUtils.RRIterator memory iter = rrset.rrs(); !iter.done(); iter.next()) {\n            // We're dealing with three names here:\n            //   - deleteName is the name the user wants us to delete\n            //   - nsecName is the owner name of the NSEC record\n            //   - nextName is the next name specified in the NSEC record\n            //\n            // And three cases:\n            //   - deleteName equals nsecName, in which case we can delete the\n            //     record if it's not in the type bitmap.\n            //   - nextName comes after nsecName, in which case we can delete\n            //     the record if deleteName comes between nextName and nsecName.\n            //   - nextName comes before nsecName, in which case nextName is the\n            //     zone apex, and deleteName must come after nsecName.\n            checkNsecName(iter, rrset.name, deleteName, deleteType);\n            delete rrsets[keccak256(deleteName)][deleteType];\n            return;\n        }\n        // We should never reach this point\n        revert();\n    }\n\n    function checkNsecName(RRUtils.RRIterator memory iter, bytes memory nsecName, bytes memory deleteName, uint16 deleteType) private pure {\n        uint rdataOffset = iter.rdataOffset;\n        uint nextNameLength = iter.data.nameLength(rdataOffset);\n        uint rDataLength = iter.nextOffset - iter.rdataOffset;\n\n        // We assume that there is always typed bitmap after the next domain name\n        require(rDataLength > nextNameLength);\n\n        int compareResult = deleteName.compareNames(nsecName);\n        if(compareResult == 0) {\n            // Name to delete is on the same label as the NSEC record\n            require(!iter.data.checkTypeBitmap(rdataOffset + nextNameLength, deleteType));\n        } else {\n            // First check if the NSEC next name comes after the NSEC name.\n            bytes memory nextName = iter.data.substring(rdataOffset,nextNameLength);\n            // deleteName must come after nsecName\n            require(compareResult > 0);\n            if(nsecName.compareNames(nextName) < 0) {\n                // deleteName must also come before nextName\n                require(deleteName.compareNames(nextName) < 0);\n            }\n        }\n    }\n\n    /**\n     * @dev Deletes an RR from the oracle using an NSEC3 proof.\n     *      Deleting a record using NSEC3 requires using up to two NSEC3 records. There are two cases:\n     *       1. The name exists, but the record type doesn't. Eg, example.com has A records but no TXT records.\n     *       2. The name does not exist, but a parent name does.\n     *      In the first case, we submit one NSEC3 proof in `closestEncloser` that matches the target name\n     *      but does not have the bit for `deleteType` set in its type bitmap. In the second case, we submit\n     *      two proofs: closestEncloser and nextClosest, that together prove that the name does not exist.\n     *      NSEC3 records are in the format described in section 5.3.2 of RFC4035: The RRDATA section\n     *      from the RRSIG without the signature data, followed by a series of canonicalised RR records\n     *      that the signature applies to.\n     *\n     * @param deleteType The DNS record type to delete.\n     * @param deleteName The name to delete.\n     * @param closestEncloser An NSEC3 proof matching the closest enclosing name - that is,\n     *        the nearest ancestor of the target name that *does* exist.\n     * @param nextClosest An NSEC3 proof covering the next closest name. This proves that the immediate\n     *        subdomain of the closestEncloser does not exist.\n     * @param dnskey An encoded DNSKEY record that has already been submitted to the oracle and can be used\n     *        to verify the signatures closestEncloserSig and nextClosestSig\n     */\n    function deleteRRSetNSEC3(uint16 deleteType, bytes memory deleteName, RRSetWithSignature memory closestEncloser, RRSetWithSignature memory nextClosest, bytes memory dnskey)\n        public override\n    {\n        uint32 originalInception = rrsets[keccak256(deleteName)][deleteType].inception;\n\n        RRUtils.SignedSet memory ce = validateSignedSet(closestEncloser, dnskey);\n        checkNSEC3Validity(ce, deleteName, originalInception);\n\n        RRUtils.SignedSet memory nc;\n        if(nextClosest.rrset.length > 0) {\n            nc = validateSignedSet(nextClosest, dnskey);\n            checkNSEC3Validity(nc, deleteName, originalInception);\n        }\n\n        RRUtils.NSEC3 memory ceNSEC3 = readNSEC3(ce);\n        // The flags field must be 0 or 1 (RFC5155 section 8.2).\n        require(ceNSEC3.flags & 0xfe == 0);\n        // Check that the closest encloser is from the correct zone (RFC5155 section 8.3)\n        // \"The DNAME type bit must not be set and the NS type bit may only be set if the SOA type bit is set.\"\n        require(!ceNSEC3.checkTypeBitmap(DNSTYPE_DNAME) && (!ceNSEC3.checkTypeBitmap(DNSTYPE_NS) || ceNSEC3.checkTypeBitmap(DNSTYPE_SOA)));\n\n        // Case 1: deleteName does exist, but no records of RRTYPE deleteType do.\n        if(isMatchingNSEC3Record(deleteType, deleteName, ce.name, ceNSEC3)) {\n            delete rrsets[keccak256(deleteName)][deleteType];\n        // Case 2: deleteName does not exist.\n        } else if(isCoveringNSEC3Record(deleteName, ce.name, ceNSEC3, nc.name, readNSEC3(nc))) {\n            delete rrsets[keccak256(deleteName)][deleteType];\n        } else {\n            revert();\n        }\n    }\n\n    function checkNSEC3Validity(RRUtils.SignedSet memory nsec, bytes memory deleteName, uint32 originalInception) private pure {\n        // The records must have been signed after the record we're trying to delete\n        require(RRUtils.serialNumberGte(nsec.inception, originalInception));\n\n        // The record must be an NSEC3\n        require(nsec.typeCovered == DNSTYPE_NSEC3);\n\n        // nsecName is of the form <hash>.zone.xyz. <hash> is the NSEC3 hash of the entire name the NSEC3 record matches, while\n        // zone.xyz can be any ancestor of that name. We'll check that, so someone can't use a record on foo.com\n        // as proof of the nonexistence of bar.org.\n        require(checkNSEC3OwnerName(nsec.name, deleteName));\n    }\n\n    function isMatchingNSEC3Record(uint16 deleteType, bytes memory deleteName, bytes memory closestEncloserName, RRUtils.NSEC3 memory closestEncloser) private view returns(bool) {\n        // Check the record matches the hashed name, but the type bitmap does not include the type\n        if(checkNSEC3Name(closestEncloser, closestEncloserName, deleteName)) {\n            return !closestEncloser.checkTypeBitmap(deleteType);\n        }\n\n        return false;\n    }\n\n    function isCoveringNSEC3Record(bytes memory deleteName, bytes memory ceName, RRUtils.NSEC3 memory ce, bytes memory ncName, RRUtils.NSEC3 memory nc) private view returns(bool) {\n        // The flags field must be 0 or 1 (RFC5155 section 8.2).\n        require(nc.flags & 0xfe == 0);\n\n        bytes32 ceNameHash = decodeOwnerNameHash(ceName);\n        bytes32 ncNameHash = decodeOwnerNameHash(ncName);\n\n        uint lastOffset = 0;\n        // Iterate over suffixes of the name to delete until one matches the closest encloser\n        for(uint offset = deleteName.readUint8(0) + 1; offset < deleteName.length; offset += deleteName.readUint8(offset) + 1) {\n            if(hashName(ce, deleteName.substring(offset, deleteName.length - offset)) == ceNameHash) {\n                // Check that the next closest record encloses the name one label longer\n                bytes32 checkHash = hashName(nc, deleteName.substring(lastOffset, deleteName.length - lastOffset));\n                if(ncNameHash < nc.nextHashedOwnerName) {\n                    return checkHash > ncNameHash && checkHash < nc.nextHashedOwnerName;\n                } else {\n                    return checkHash > ncNameHash || checkHash < nc.nextHashedOwnerName;\n                }\n            }\n            lastOffset = offset;\n        }\n        // If we reached the root without finding a match, return false.\n        return false;\n    }\n\n    function readNSEC3(RRUtils.SignedSet memory ss) private pure returns(RRUtils.NSEC3 memory) {\n        RRUtils.RRIterator memory iter = ss.rrs();\n        return iter.data.readNSEC3(iter.rdataOffset, iter.nextOffset - iter.rdataOffset);\n    }\n\n    function checkNSEC3Name(RRUtils.NSEC3 memory nsec, bytes memory ownerName, bytes memory deleteName) private view returns(bool) {\n        // Compute the NSEC3 name hash of the name to delete.\n        bytes32 deleteNameHash = hashName(nsec, deleteName);\n\n        // Decode the NSEC3 name hash from the first label of the NSEC3 owner name.\n        bytes32 nsecNameHash = decodeOwnerNameHash(ownerName);\n\n        return deleteNameHash == nsecNameHash;\n    }\n\n    function hashName(RRUtils.NSEC3 memory nsec, bytes memory name) private view returns(bytes32) {\n        return nsec3Digests[nsec.hashAlgorithm].hash(nsec.salt, name, nsec.iterations);\n    }\n\n    function decodeOwnerNameHash(bytes memory name) private pure returns(bytes32) {\n        return name.base32HexDecodeWord(1, uint(name.readUint8(0)));\n    }\n\n    function checkNSEC3OwnerName(bytes memory nsecName, bytes memory deleteName) private pure returns(bool) {\n        uint nsecNameOffset = nsecName.readUint8(0) + 1;\n        uint deleteNameOffset = 0;\n        while(deleteNameOffset < deleteName.length) {\n            if(deleteName.equals(deleteNameOffset, nsecName, nsecNameOffset)) {\n                return true;\n            }\n            deleteNameOffset += deleteName.readUint8(deleteNameOffset) + 1;\n        }\n        return false;\n    }\n\n    /**\n     * @dev Returns data about the RRs (if any) known to this oracle with the provided type and name.\n     * @param dnstype The DNS record type to query.\n     * @param name The name to query, in DNS label-sequence format.\n     * @return inception The unix timestamp (wrapped) at which the signature for this RRSET was created.\n     * @return expiration The unix timestamp (wrapped) at which the signature for this RRSET expires.\n     * @return hash The hash of the RRset.\n     */\n    function rrdata(uint16 dnstype, bytes calldata name) external override view returns (uint32, uint32, bytes20) {\n        RRSet storage result = rrsets[keccak256(name)][dnstype];\n        return (result.inception, result.expiration, result.hash);\n    }\n\n    function _submitRRSet(RRSetWithSignature memory input, bytes memory proof) internal returns (bytes memory) {\n        RRUtils.SignedSet memory rrset;\n        rrset = validateSignedSet(input, proof);\n\n        RRSet storage storedSet = rrsets[keccak256(rrset.name)][rrset.typeCovered];\n        if (storedSet.hash != bytes20(0)) {\n            // To replace an existing rrset, the signature must be at least as new\n            require(RRUtils.serialNumberGte(rrset.inception, storedSet.inception));\n        }\n        rrsets[keccak256(rrset.name)][rrset.typeCovered] = RRSet({\n            inception: rrset.inception,\n            expiration: rrset.expiration,\n            hash: bytes20(keccak256(rrset.data))\n        });\n\n        emit RRSetUpdated(rrset.name, rrset.data);\n\n        return rrset.data;\n    }\n\n    /**\n     * @dev Submits a signed set of RRs to the oracle.\n     *\n     * RRSETs are only accepted if they are signed with a key that is already\n     * trusted, or if they are self-signed, and the signing key is identified by\n     * a DS record that is already trusted.\n     *\n     * @param input The signed RR set. This is in the format described in section\n     *        5.3.2 of RFC4035: The RRDATA section from the RRSIG without the signature\n     *        data, followed by a series of canonicalised RR records that the signature\n     *        applies to.\n     * @param proof The DNSKEY or DS to validate the signature against. Must Already\n     *        have been submitted and proved previously.\n     */\n    function validateSignedSet(RRSetWithSignature memory input, bytes memory proof) internal view returns(RRUtils.SignedSet memory rrset) {\n        rrset = input.rrset.readSignedSet();\n        require(validProof(rrset.signerName, proof));\n\n        // Do some basic checks on the RRs and extract the name\n        bytes memory name = validateRRs(rrset, rrset.typeCovered);\n        require(name.labelCount(0) == rrset.labels);\n        rrset.name = name;\n\n        // All comparisons involving the Signature Expiration and\n        // Inception fields MUST use \"serial number arithmetic\", as\n        // defined in RFC 1982\n\n        // o  The validator's notion of the current time MUST be less than or\n        //    equal to the time listed in the RRSIG RR's Expiration field.\n        require(RRUtils.serialNumberGte(rrset.expiration, uint32(block.timestamp)));\n\n        // o  The validator's notion of the current time MUST be greater than or\n        //    equal to the time listed in the RRSIG RR's Inception field.\n        require(RRUtils.serialNumberGte(uint32(block.timestamp), rrset.inception));\n\n        // Validate the signature\n        verifySignature(name, rrset, input, proof);\n\n        return rrset;\n    }\n\n    function validProof(bytes memory name, bytes memory proof) internal view returns(bool) {\n        uint16 dnstype = proof.readUint16(proof.nameLength(0));\n        return rrsets[keccak256(name)][dnstype].hash == bytes20(keccak256(proof));\n    }\n\n    /**\n     * @dev Validates a set of RRs.\n     * @param rrset The RR set.\n     * @param typecovered The type covered by the RRSIG record.\n     */\n    function validateRRs(RRUtils.SignedSet memory rrset, uint16 typecovered) internal pure returns (bytes memory name) {\n        // Iterate over all the RRs\n        for (RRUtils.RRIterator memory iter = rrset.rrs(); !iter.done(); iter.next()) {\n            // We only support class IN (Internet)\n            require(iter.class == DNSCLASS_IN);\n\n            if(name.length == 0) {\n                name = iter.name();\n            } else {\n                // Name must be the same on all RRs. We do things this way to avoid copying the name\n                // repeatedly.\n                require(name.length == iter.data.nameLength(iter.offset));\n                require(name.equals(0, iter.data, iter.offset, name.length));\n            }\n\n            // o  The RRSIG RR's Type Covered field MUST equal the RRset's type.\n            require(iter.dnstype == typecovered);\n        }\n    }\n\n    /**\n     * @dev Performs signature verification.\n     *\n     * Throws or reverts if unable to verify the record.\n     *\n     * @param name The name of the RRSIG record, in DNS label-sequence format.\n     * @param data The original data to verify.\n     * @param proof A DS or DNSKEY record that's already verified by the oracle.\n     */\n    function verifySignature(bytes memory name, RRUtils.SignedSet memory rrset, RRSetWithSignature memory data, bytes memory proof) internal view {\n        // o  The RRSIG RR's Signer's Name field MUST be the name of the zone\n        //    that contains the RRset.\n        require(rrset.signerName.length <= name.length);\n        require(rrset.signerName.equals(0, name, name.length - rrset.signerName.length));\n\n        RRUtils.RRIterator memory proofRR = proof.iterateRRs(0);\n        // Check the proof\n        if (proofRR.dnstype == DNSTYPE_DS) {\n            require(verifyWithDS(rrset, data, proofRR));\n        } else if (proofRR.dnstype == DNSTYPE_DNSKEY) {\n            require(verifyWithKnownKey(rrset, data, proofRR));\n        } else {\n            revert(\"No valid proof found\");\n        }\n    }\n\n    /**\n     * @dev Attempts to verify a signed RRSET against an already known public key.\n     * @param rrset The signed set to verify.\n     * @param data The original data the signed set was read from.\n     * @param proof The serialized DS or DNSKEY record to use as proof.\n     * @return True if the RRSET could be verified, false otherwise.\n     */\n    function verifyWithKnownKey(RRUtils.SignedSet memory rrset, RRSetWithSignature memory data, RRUtils.RRIterator memory proof) internal view returns(bool) {\n        // Check the DNSKEY's owner name matches the signer name on the RRSIG\n        require(proof.name().equals(rrset.signerName));\n        for(; !proof.done(); proof.next()) {\n            require(proof.name().equals(rrset.signerName));\n            bytes memory keyrdata = proof.rdata();\n            RRUtils.DNSKEY memory dnskey = keyrdata.readDNSKEY(0, keyrdata.length);\n            if(verifySignatureWithKey(dnskey, keyrdata, rrset, data)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * @dev Attempts to verify some data using a provided key and a signature.\n     * @param dnskey The dns key record to verify the signature with.\n     * @param rrset The signed RRSET being verified.\n     * @param data The original data `rrset` was decoded from.\n     * @return True iff the key verifies the signature.\n     */\n    function verifySignatureWithKey(RRUtils.DNSKEY memory dnskey, bytes memory keyrdata, RRUtils.SignedSet memory rrset, RRSetWithSignature memory data)\n        internal\n        view\n        returns (bool)\n    {\n        // TODO: Check key isn't expired, unless updating key itself\n\n        // The Protocol Field MUST have value 3 (RFC4034 2.1.2)\n        if(dnskey.protocol != 3) {\n            return false;\n        }\n\n        // o The RRSIG RR's Signer's Name, Algorithm, and Key Tag fields MUST\n        //   match the owner name, algorithm, and key tag for some DNSKEY RR in\n        //   the zone's apex DNSKEY RRset.\n        if(dnskey.algorithm != rrset.algorithm) {\n            return false;\n        }\n        uint16 computedkeytag = keyrdata.computeKeytag();\n        if (computedkeytag != rrset.keytag) {\n            return false;\n        }\n\n        // o The matching DNSKEY RR MUST be present in the zone's apex DNSKEY\n        //   RRset, and MUST have the Zone Flag bit (DNSKEY RDATA Flag bit 7)\n        //   set.\n        if (dnskey.flags & DNSKEY_FLAG_ZONEKEY == 0) {\n            return false;\n        }\n\n        return algorithms[dnskey.algorithm].verify(keyrdata, data.rrset, data.sig);\n    }\n\n    /**\n     * @dev Attempts to verify a signed RRSET against an already known hash. This function assumes\n     *      that the record \n     * @param rrset The signed set to verify.\n     * @param data The original data the signed set was read from.\n     * @param proof The serialized DS or DNSKEY record to use as proof.\n     * @return True if the RRSET could be verified, false otherwise.\n     */\n    function verifyWithDS(RRUtils.SignedSet memory rrset, RRSetWithSignature memory data, RRUtils.RRIterator memory proof) internal view returns(bool) {\n        for(RRUtils.RRIterator memory iter = rrset.rrs(); !iter.done(); iter.next()) {\n            require(iter.dnstype == DNSTYPE_DNSKEY);\n            bytes memory keyrdata = iter.rdata();\n            RRUtils.DNSKEY memory dnskey = keyrdata.readDNSKEY(0, keyrdata.length);\n            if (verifySignatureWithKey(dnskey, keyrdata, rrset, data)) {\n                // It's self-signed - look for a DS record to verify it.\n                return verifyKeyWithDS(iter.name(), proof, dnskey, keyrdata);\n            }\n        }\n        return false;\n    }\n\n    /**\n     * @dev Attempts to verify a key using DS records.\n     * @param keyname The DNS name of the key, in DNS label-sequence format.\n     * @param dsrrs The DS records to use in verification.\n     * @param dnskey The dnskey to verify.\n     * @param keyrdata The RDATA section of the key.\n     * @return True if a DS record verifies this key.\n     */\n    function verifyKeyWithDS(bytes memory keyname, RRUtils.RRIterator memory dsrrs, RRUtils.DNSKEY memory dnskey, bytes memory keyrdata)\n        internal view returns (bool)\n    {\n        uint16 keytag = keyrdata.computeKeytag();\n        for (; !dsrrs.done(); dsrrs.next()) {\n            RRUtils.DS memory ds = dsrrs.data.readDS(dsrrs.rdataOffset, dsrrs.nextOffset - dsrrs.rdataOffset);\n            if(ds.keytag != keytag) {\n                continue;\n            }\n            if (ds.algorithm != dnskey.algorithm) {\n                continue;\n            }\n\n            Buffer.buffer memory buf;\n            buf.init(keyname.length + keyrdata.length);\n            buf.append(keyname);\n            buf.append(keyrdata);\n            if (verifyDSHash(ds.digestType, buf.buf, ds.digest)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * @dev Attempts to verify a DS record's hash value against some data.\n     * @param digesttype The digest ID from the DS record.\n     * @param data The data to digest.\n     * @param digest The digest data to check against.\n     * @return True iff the digest matches.\n     */\n    function verifyDSHash(uint8 digesttype, bytes memory data, bytes memory digest) internal view returns (bool) {\n        if (address(digests[digesttype]) == address(0)) {\n            return false;\n        }\n        return digests[digesttype].verify(data, digest);\n    }\n}\n"
    },
    "contracts/dnssec-oracle/Owned.sol": {
      "content": "pragma solidity ^0.8.4;\n\n/**\n* @dev Contract mixin for 'owned' contracts.\n*/\ncontract Owned {\n    address public owner;\n    \n    modifier owner_only() {\n        require(msg.sender == owner);\n        _;\n    }\n\n    constructor() public {\n        owner = msg.sender;\n    }\n\n    function setOwner(address newOwner) public owner_only {\n        owner = newOwner;\n    }\n}\n"
    },
    "contracts/dnssec-oracle/algorithms/Algorithm.sol": {
      "content": "pragma solidity ^0.8.4;\n\n/**\n* @dev An interface for contracts implementing a DNSSEC (signing) algorithm.\n*/\ninterface Algorithm {\n    /**\n    * @dev Verifies a signature.\n    * @param key The public key to verify with.\n    * @param data The signed data to verify.\n    * @param signature The signature to verify.\n    * @return True iff the signature is valid.\n    */\n    function verify(bytes calldata key, bytes calldata data, bytes calldata signature) external virtual view returns (bool);\n}\n"
    },
    "contracts/dnssec-oracle/digests/Digest.sol": {
      "content": "pragma solidity ^0.8.4;\n\n/**\n* @dev An interface for contracts implementing a DNSSEC digest.\n*/\ninterface Digest {\n    /**\n    * @dev Verifies a cryptographic hash.\n    * @param data The data to hash.\n    * @param hash The hash to compare to.\n    * @return True iff the hashed data matches the provided hash value.\n    */\n    function verify(bytes calldata data, bytes calldata hash) external virtual pure returns (bool);\n}\n"
    },
    "contracts/dnssec-oracle/nsec3digests/NSEC3Digest.sol": {
      "content": "pragma solidity ^0.8.4;\n\n/**\n * @dev Interface for contracts that implement NSEC3 digest algorithms.\n */\ninterface NSEC3Digest {\n    /**\n     * @dev Performs an NSEC3 iterated hash.\n     * @param salt The salt value to use on each iteration.\n     * @param data The data to hash.\n     * @param iterations The number of iterations to perform.\n     * @return The result of the iterated hash operation.\n     */\n     function hash(bytes calldata salt, bytes calldata data, uint iterations) external virtual pure returns (bytes32);\n}\n"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": false,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
          "devdoc",
          "userdoc",
          "storageLayout",
          "evm.gasEstimates"
        ],
        "": [
          "ast"
        ]
      }
    },
    "metadata": {
      "useLiteralContent": true
    }
  }
}