creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "github/resolverworks/TheOffchainResolver.sol/src/TOR.sol": {
        "content": "/// @author raffy.eth\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\n// interfaces\nimport {ENS} from \"@ensdomains/ens-contracts/contracts/registry/ENS.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {IExtendedResolver} from \"@ensdomains/ens-contracts/contracts/resolvers/profiles/IExtendedResolver.sol\";\nimport {IExtendedDNSResolver} from \"@ensdomains/ens-contracts/contracts/resolvers/profiles/IExtendedDNSResolver.sol\";\nimport {IAddrResolver} from \"@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddrResolver.sol\";\nimport {IAddressResolver} from \"@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddressResolver.sol\";\nimport {ITextResolver} from \"@ensdomains/ens-contracts/contracts/resolvers/profiles/ITextResolver.sol\";\nimport {INameResolver} from \"@ensdomains/ens-contracts/contracts/resolvers/profiles/INameResolver.sol\";\nimport {IPubkeyResolver} from \"@ensdomains/ens-contracts/contracts/resolvers/profiles/IPubkeyResolver.sol\";\nimport {IContentHashResolver} from \"@ensdomains/ens-contracts/contracts/resolvers/profiles/IContentHashResolver.sol\";\nimport {IMulticallable} from \"@ensdomains/ens-contracts/contracts/resolvers/IMulticallable.sol\";\n\n// libraries\nimport {ECDSA} from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport {BytesUtils} from \"@ensdomains/ens-contracts/contracts/wrapper/BytesUtils.sol\";\nimport {HexUtils} from \"@ensdomains/ens-contracts/contracts/utils/HexUtils.sol\";\n\n// https://eips.ethereum.org/EIPS/eip-3668\nerror OffchainLookup(address from, string[] urls, bytes request, bytes4 callback, bytes carry);\n\ninterface IOnchainResolver {\n\tfunction onchain(bytes32 node) external view returns (bool);\n\tevent OnchainChanged(bytes32 indexed node, bool on);\n}\n\ncontract TOR is IERC165, ITextResolver, IAddrResolver, IAddressResolver, IPubkeyResolver, IContentHashResolver, \n\t\tIMulticallable, IExtendedResolver, IExtendedDNSResolver, IOnchainResolver, INameResolver {\n\tusing BytesUtils for bytes;\n\tusing HexUtils for bytes;\n\n\terror Unauthorized(address owner); // not operator of node\n\terror InvalidContext(bytes context); // context too short or invalid signer\n\terror Unreachable(bytes name);\n\terror CCIPReadExpired(uint256 t); // ccip response is stale\n\terror CCIPReadUntrusted(address signed, address expect);\n\terror NodeCheck(bytes32 node);\n\n\tuint256 constant COIN_TYPE_ETH = 60;\n\tuint256 constant COIN_TYPE_FALLBACK = 0xb32cdf4d3c016cb0f079f205ad61c36b1a837fb3e95c70a94bdedfca0518a010; // https://adraffy.github.io/keccak.js/test/demo.html#algo=keccak-256&s=fallback&escape=1&encoding=utf8\n\tstring constant TEXT_CONTEXT = \"ccip.context\";\n\tbool constant REPLACE_WITH_ONCHAIN = true;\n\tbool constant OFFCHAIN_ONLY = false;\n\tbool constant CALL_WITH_NULL_NODE = true;\n\tbool constant CALL_UNMODIFIED = false;\n\tbytes4 constant PREFIX_ONLY_OFF = 0x000000FF;\n\tbytes4 constant PREFIX_ONLY_ON = ~PREFIX_ONLY_OFF;\n\tuint256 constant ERC165_GAS_LIMIT = 30000; // https://eips.ethereum.org/EIPS/eip-165\n\t\n\tENS immutable ens;\n\tconstructor(ENS a) {\n\t\tens = a;\n\n\t}\n\n\tfunction supportsInterface(bytes4 x) external pure returns (bool) {\n\t\treturn x == type(IERC165).interfaceId\n\t\t\t|| x == type(ITextResolver).interfaceId\n\t\t\t|| x == type(IAddrResolver).interfaceId\n\t\t\t|| x == type(IAddressResolver).interfaceId\n\t\t\t|| x == type(IPubkeyResolver).interfaceId\n\t\t\t|| x == type(IContentHashResolver).interfaceId\n\t\t\t|| x == type(INameResolver).interfaceId\n\t\t\t|| x == type(IMulticallable).interfaceId\n\t\t\t|| x == type(IExtendedResolver).interfaceId\n\t\t\t|| x == type(IExtendedDNSResolver).interfaceId\n\t\t\t|| x == type(IOnchainResolver).interfaceId\n\t\t\t|| x == 0x73302a25; // https://adraffy.github.io/keccak.js/test/demo.html#algo=evm&s=ccip.context&escape=1&encoding=utf8\n\t}\n\n\t// utils\n\tmodifier requireOperator(bytes32 node) {\n\t\taddress owner = ens.owner(node);\n\t\tif (owner != msg.sender && !ens.isApprovedForAll(owner, msg.sender)) revert Unauthorized(owner);\n\t\t_;\n\t}\n\tfunction slotForCoin(bytes32 node, uint256 cty) internal pure returns (uint256) {\n\t\treturn uint256(keccak256(abi.encodeCall(IAddressResolver.addr, (node, cty))));\n\t}\n\tfunction slotForText(bytes32 node, string memory key) internal pure returns (uint256) {\n\t\treturn uint256(keccak256(abi.encodeCall(ITextResolver.text, (node, key))));\n\t}\n\tfunction slotForSelector(bytes4 selector, bytes32 node) internal pure returns (uint256) {\n\t\treturn uint256(keccak256(abi.encodeWithSelector(selector, node)));\n\t}\n\n\t// getters (structured)\n\tfunction addr(bytes32 node) external view returns (address payable a) {\n\t\t(bytes32 extnode, address resolver) = determineExternalFallback(node);\n\t\tif (resolver != address(0) && IERC165(resolver).supportsInterface{gas: ERC165_GAS_LIMIT}(type(IAddrResolver).interfaceId)) {\n\t\t\ta = IAddrResolver(resolver).addr(extnode);\n\t\t}\n\t\tif (a == address(0)) {\n\t\t\ta = payable(address(bytes20(getTiny(slotForCoin(node, COIN_TYPE_ETH)))));\n\t\t}\n\t}\n\tfunction pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y) {\n\t\t(bytes32 extnode, address resolver) = determineExternalFallback(node);\n\t\tif (resolver != address(0) && IERC165(resolver).supportsInterface{gas: ERC165_GAS_LIMIT}(type(IPubkeyResolver).interfaceId)) {\n\t\t\t(x, y) = IPubkeyResolver(resolver).pubkey(extnode);\n\t\t}\n\t\tif (x == 0 && y == 0) {\n\t\t\tbytes memory v = getTiny(slotForSelector(IPubkeyResolver.pubkey.selector, node));\n\t\t\tif (v.length == 64) (x, y) = abi.decode(v, (bytes32, bytes32));\n\t\t}\n\t}\n\n\t// getters (bytes-like)\n\tfunction addr(bytes32, uint256) external view returns (bytes memory) {\n\t\treturn reflectGetBytes(msg.data);\n\t}\n\tfunction text(bytes32, string calldata) external view returns (string memory) {\n\t\treturn string(reflectGetBytes(msg.data));\n\t}\n\tfunction contenthash(bytes32) external view returns (bytes memory) {\n\t\treturn reflectGetBytes(msg.data);\n\t}\n\tfunction name(bytes32) external view returns (string memory) {\n\t\treturn string(reflectGetBytes(msg.data));\n\t}\n\tfunction reflectGetBytes(bytes memory request) internal view returns (bytes memory v) {\n\t\tbytes32 node;\n\t\tassembly { node := mload(add(request, 36)) }\n\t\tuint256 slot = uint256(keccak256(request)); // hash before we mangle\n\t\tv = getTiny(slot);\n\t\tif (v.length == 0) {\n\t\t\t(bytes32 extnode, address resolver) = determineExternalFallback(node);\n\t\t\tif (resolver != address(0)) {\n\t\t\t\tassembly { mstore(add(request, 36), extnode) } // mangled\n\t\t\t\t(bool ok, bytes memory u) = resolver.staticcall(request);\n\t\t\t\tif (ok) {\n\t\t\t\t\tv = abi.decode(u, (bytes));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// TOR helpers\n\tfunction parseContext(bytes memory v) internal pure returns (string[] memory urls, address signer) {\n\t\t// {SIGNER} {ENDPOINT}\n\t\t// \"0x51050ec063d393217B436747617aD1C2285Aeeee http://a\" => (2 + 40 + 1 + 8)\n\t\tif (v.length < 51) revert InvalidContext(v);\n\t\tbool valid;\n\t\t(signer, valid) = v.hexToAddress(2, 42); // unchecked 0x-prefix\n\t\tif (!valid) revert InvalidContext(v);\n\t\tassembly {\n\t\t\tlet size := mload(v)\n\t\t\tv := add(v, 43) // drop address\n\t\t\tmstore(v, sub(size, 43))\n\t\t}\n\t\turls = new string[](1); // TODO: support multiple URLs\n\t\turls[0] = string(v);\n\t}\n\tfunction verifyOffchain(bytes calldata ccip, bytes memory carry) internal view returns (bytes memory request, bytes memory response, bool replace) {\n\t\tbytes memory sig;\n\t\tuint64 expires;\n\t\t(sig, expires, response) = abi.decode(ccip, (bytes, uint64, bytes));\n\t\tif (expires < block.timestamp) revert CCIPReadExpired(expires);\n\t\taddress signer;\n\t\t(request, signer, replace) = abi.decode(carry, (bytes, address, bool));\n\t\tbytes32 hash = keccak256(abi.encodePacked(address(this), expires, keccak256(request), keccak256(response)));\n\t\taddress signed = ECDSA.recover(hash, sig);\n\t\tif (signed != signer) revert CCIPReadUntrusted(signed, signer);\n\t}\n\n\t// IExtendedDNSResolver\n\tfunction resolve(bytes calldata dnsname, bytes calldata data, bytes calldata context) external view returns (bytes memory) {\n\t\t(string[] memory urls, address signer) = parseContext(context);\n\t\tbytes memory request = abi.encodeWithSelector(IExtendedResolver.resolve.selector, dnsname, data);\n\t\trevert OffchainLookup(address(this), urls, request, this.buggedCallback.selector, abi.encode(abi.encode(request, signer, false), address(this)));\n\t}\n\tfunction buggedCallback(bytes calldata response, bytes calldata buggedExtraData) external view returns (bytes memory v) {\n\t\t(, v, ) = verifyOffchain(response, abi.decode(buggedExtraData, (bytes)));\n\t}\n\n\t// IExtendedResolver\n\tfunction resolve(bytes calldata dnsname, bytes calldata data) external view returns (bytes memory) {\n\t\tunchecked {\n\t\t\tbytes32 node = dnsname.namehash(0);\n\t\t\tif (bytes4(data) == PREFIX_ONLY_ON) {\n\t\t\t\treturn resolveOnchain(data[4:], CALL_UNMODIFIED);\n\t\t\t} else if (bytes4(data) == PREFIX_ONLY_OFF) {\n\t\t\t\tif (onchain(node)) {\n\t\t\t\t\treturn resolveOnchain(data[4:], CALL_WITH_NULL_NODE);\n\t\t\t\t} else {\n\t\t\t\t\tresolveOffchain(dnsname, data[4:], OFFCHAIN_ONLY);\n\t\t\t\t}\n\t\t\t} else if (onchain(node)) { // manditory on-chain\n\t\t\t\treturn resolveOnchain(data, CALL_UNMODIFIED);\n\t\t\t} else { // off-chain then replace with on-chain\n\t\t\t\tif (bytes4(data) == IMulticallable.multicall.selector) {\n\t\t\t\t\tbytes[] memory a = abi.decode(data[4:], (bytes[]));\n\t\t\t\t\tbytes[] memory b = new bytes[](a.length);\n\t\t\t\t\t// if one record is missing, go off-chain\n\t\t\t\t\tfor (uint256 i; i < a.length; i += 1) {\n\t\t\t\t\t\tbytes memory v = getEncodedFallbackValue(a[i]);\n\t\t\t\t\t\tif (v.length == 0) resolveOffchain(dnsname, data, REPLACE_WITH_ONCHAIN);\n\t\t\t\t\t\tb[i] = v;\n\t\t\t\t\t}\n\t\t\t\t\treturn abi.encode(b); // multi-answerable on-chain\n\t\t\t\t} else {\n\t\t\t\t\tbytes memory v = getEncodedFallbackValue(data);\n\t\t\t\t\tif (v.length != 0) return v; // answerable on-chain\n\t\t\t\t\tresolveOffchain(dnsname, data, OFFCHAIN_ONLY);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfunction resolveOnchain(bytes calldata data, bool clear) internal view returns (bytes memory result) {\n\t\tif (bytes4(data) == IMulticallable.multicall.selector) {\n\t\t\tbytes[] memory a = abi.decode(data[4:], (bytes[]));\n\t\t\tfor (uint256 i; i < a.length; i += 1) {\n\t\t\t\tbytes memory v = a[i];\n\t\t\t\tif (clear) assembly { mstore(add(v, 36), 0) } // clear the node\n\t\t\t\t(, a[i]) = address(this).staticcall(v);\n\t\t\t}\n\t\t\tresult = abi.encode(a);\n\t\t} else {\n\t\t\tbytes memory v = data;\n\t\t\tif (clear) assembly { mstore(add(v, 36), 0) } // clear the node\n\t\t\t(, result) = address(this).staticcall(v);\n\t\t}\n\t}\n\tfunction resolveOffchain(bytes calldata dnsname, bytes calldata data, bool replace) internal view {\n\t\t(string[] memory urls, address signer) = parseContext(findContext(dnsname));\n\t\tbytes memory request = abi.encodeWithSelector(IExtendedResolver.resolve.selector, dnsname, data);\n\t\trevert OffchainLookup(address(this), urls, request, this.ensCallback.selector, abi.encode(request, signer, replace));\n\t}\n\tfunction findContext(bytes calldata dnsname) internal view returns (bytes memory context) {\n\t\tunchecked {\n\t\t\tuint256 offset;\n\t\t\twhile (true) {\n\t\t\t\t// find the first node in direct lineage...\n\t\t\t\tbytes32 node = dnsname.namehash(offset);\n\t\t\t\tif (ens.resolver(node) == address(this)) { // ...that is TOR\n\t\t\t\t\tcontext = getTiny(slotForText(node, TEXT_CONTEXT));\n\t\t\t\t\tif (context.length != 0) break; // ...and has non-null context\n\t\t\t\t}\n\t\t\t\tuint256 size = uint256(uint8(dnsname[offset]));\n\t\t\t\tif (size == 0) revert Unreachable(dnsname);\n\t\t\t\toffset += 1 + size;\n\t\t\t}\n\t\t}\n\t}\n\tfunction ensCallback(bytes calldata ccip, bytes calldata carry) external view returns (bytes memory) {\n\t\tunchecked {\n\t\t\t(bytes memory request, bytes memory response, bool replace) = verifyOffchain(ccip, carry);\n\t\t\t// single record calls that had on-chain values would of been answered on-chain\n\t\t\t// so we only need to handle multicall() replacement \n\t\t\tif (!replace) return response;\n\t\t\tassembly {\n\t\t\t\tmstore(add(request, 4), sub(mload(request), 4)) // trim resolve() selector\n\t\t\t\trequest := add(request, 4)\n\t\t\t}\n\t\t\t(, request) = abi.decode(request, (bytes, bytes));\n\t\t\tassembly {\n\t\t\t\tmstore(add(request, 4), sub(mload(request), 4)) // trim multicall() selector\n\t\t\t\trequest := add(request, 4)\n\t\t\t}\n\t\t\tbytes[] memory a = abi.decode(request,  (bytes[]));\n\t\t\tbytes[] memory b = abi.decode(response, (bytes[]));\n\t\t\tfor (uint256 i; i < a.length; i += 1) {\n\t\t\t\tbytes memory v = getEncodedFallbackValue(a[i]);\n\t\t\t\tif (v.length != 0) b[i] = v; // replace with on-chain\n\t\t\t}\n\t\t\treturn abi.encode(b);\n\t\t}\n\t}\n\tfunction determineExternalFallback(bytes32 node) internal view returns (bytes32 extnode, address resolver) {\n\t\tbytes memory v = getTiny(slotForCoin(node, COIN_TYPE_FALLBACK));\n\t\tif (v.length == 20) { // resolver using same node\n\t\t\textnode = node;\n\t\t\tresolver = address(bytes20(v));\n\t\t} else {\n\t\t\tif (v.length == 32) { // differnt node \n\t\t\t\textnode = bytes32(v);\n\t\t\t} else if (v.length != 0) { // external fallback disabled\n\t\t\t\t// extnode = 0 => resolver = 0\n\t\t\t} else { // default\n\t\t\t\t// derived: namehash(\"_\" + node)\n\t\t\t\t// https://adraffy.github.io/keccak.js/test/demo.html#algo=keccak-256&s=_&escape=1&encoding=utf8\n\t\t\t\textnode = keccak256(abi.encode(node, 0xcd5edcba1904ce1b09e94c8a2d2a85375599856ca21c793571193054498b51d7));\n\t\t\t}\n\t\t\t// Q: should this be ENSIP-10?\n\t\t\t// A: no, since we're calling on-chain methods\n\t\t\tresolver = ens.resolver(extnode); \n\t\t}\n\t}\n\tfunction getEncodedFallbackValue(bytes memory request) internal view returns (bytes memory encoded) {\n\t\t(bool ok, bytes memory v) = address(this).staticcall(request);\n\t\tif (ok && !isNullAssumingPadded(v)) {\n\t\t\t// unfortunately it is impossible to determine if an arbitrary abi-encoded response is null\n\t\t\t// abi.encode('') = 0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000\n\t\t\t// https://adraffy.github.io/keccak.js/test/demo.html#algo=keccak-256&s=0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000&escape=1&encoding=hex\n\t\t\tif (keccak256(v) != 0x569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd) {\n\t\t\t\tencoded = v;\n\t\t\t}\n\t\t}\n\t}\n\tfunction isNullAssumingPadded(bytes memory v) internal pure returns (bool ret) {\n\t\tassembly {\n\t\t\tlet p := add(v, 32)\n\t\t\tlet e := add(p, mload(v))\n\t\t\tfor { ret := 1 } lt(p, e) { p := add(p, 32) } {\n\t\t\t\tif iszero(iszero(mload(p))) { // != 0\n\t\t\t\t\tret := 0\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// multicall (for efficient multi-record writes)\n\t// Q: allow ccip-read through this mechanism?\n\t// A: no, too complex (mixed targets) and not ENSIP-10 compatible\n\tfunction multicall(bytes[] calldata calls) external returns (bytes[] memory) {\n\t\treturn _multicall(0, calls);\n\t}\n\tfunction multicallWithNodeCheck(bytes32 nodehash, bytes[] calldata calls) external returns (bytes[] memory) {\n\t\treturn _multicall(nodehash, calls);\n\t}\n\tfunction _multicall(bytes32 node, bytes[] calldata calls) internal returns (bytes[] memory answers) {\n\t\tunchecked {\n\t\t\tanswers = new bytes[](calls.length);\n\t\t\tfor (uint256 i; i < calls.length; i += 1) {\n\t\t\t\tif (node != 0) {\n\t\t\t\t\tbytes32 check = bytes32(calls[i][4:36]);\n\t\t\t\t\tif (check != node) revert NodeCheck(check);\n\t\t\t\t}\n\t\t\t\t(bool ok, bytes memory v) = address(this).delegatecall(calls[i]);\n\t\t\t\trequire(ok);\n\t\t\t\tanswers[i] = v;\n\t\t\t}\n\t\t}\n\t}\n\n\t// setters\n\tfunction setAddr(bytes32 node, address a) external {\n\t\tsetAddr(node, COIN_TYPE_ETH, a == address(0) ? bytes('') : abi.encodePacked(a));\n\t}\n\tfunction setAddr(bytes32 node, uint256 cty, bytes memory v) requireOperator(node) public {\n\t\tsetTiny(slotForCoin(node, cty), v);\n\t\temit AddressChanged(node, cty, v);\n\t\tif (cty == COIN_TYPE_ETH) emit AddrChanged(node, address(bytes20(v)));\n\t}\n\tfunction setText(bytes32 node, string calldata key, string calldata s) requireOperator(node) external {\n\t\tsetTiny(slotForText(node, key), bytes(s));\n\t\temit TextChanged(node, key, key, s);\n\t}\n\tfunction setContenthash(bytes32 node, bytes calldata v) requireOperator(node) external {\n\t\tsetTiny(slotForSelector(IContentHashResolver.contenthash.selector, node), v);\n\t\temit ContenthashChanged(node, v);\n\t}\n\tfunction setPubkey(bytes32 node, bytes32 x, bytes32 y) requireOperator(node) external {\n\t\tsetTiny(slotForSelector(IPubkeyResolver.pubkey.selector, node), x == 0 && y == 0 ? bytes('') : abi.encode(x, y));\n\t\temit PubkeyChanged(node, x, y);\n\t}\n\n\t// IOnchainResolver\n\tfunction toggleOnchain(bytes32 node) requireOperator(node) external {\n\t\tuint256 slot = slotForSelector(IOnchainResolver.onchain.selector, node);\n\t\tbool on;\n\t\tassembly { \n\t\t\ton := iszero(sload(slot))\n\t\t\tsstore(slot, on)\n\t\t}\n\t\temit OnchainChanged(node, on);\n\t}\n\tfunction onchain(bytes32 node) public view returns (bool) {\t\t\n\t\tuint256 slot = slotForSelector(IOnchainResolver.onchain.selector, node);\n\t\tassembly { slot := sload(slot) }\n\t\treturn slot != 0;\n\t}\n\t\n\t// ************************************************************\n\t// TinyKV.sol: https://github.com/adraffy/TinyKV.sol\n\n\t// header: first 4 bytes\n\t// [00000000_00000000000000000000000000000000000000000000000000000000] // null (0 slot)\n\t// [00000001_XX000000000000000000000000000000000000000000000000000000] // 1 byte (1 slot)\n\t// [0000001C_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX] // 28 bytes (1 slot\n\t// [0000001D_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX][XX000000...] // 29 bytes (2 slots)\n\tfunction tinySlots(uint256 size) internal pure returns (uint256) {\n\t\tunchecked {\n\t\t\treturn size != 0 ? (size + 35) >> 5 : 0; // ceil((4 + size) / 32)\n\t\t}\n\t}\n\tfunction setTiny(uint256 slot, bytes memory v) internal {\n\t\tunchecked {\n\t\t\tuint256 head;\n\t\t\tassembly { head := sload(slot) }\n\t\t\tuint256 size;\n\t\t\tassembly { size := mload(v) }\n\t\t\tuint256 n0 = tinySlots(head >> 224);\n\t\t\tuint256 n1 = tinySlots(size);\n\t\t\tassembly {\n\t\t\t\t// overwrite\n\t\t\t\tif gt(n1, 0) {\n\t\t\t\t\tsstore(slot, or(shl(224, size), shr(32, mload(add(v, 32)))))\n\t\t\t\t\tlet ptr := add(v, 60)\n\t\t\t\t\tfor { let i := 1 } lt(i, n1) { i := add(i, 1) } {\n\t\t\t\t\t\tsstore(add(slot, i), mload(ptr))\n\t\t\t\t\t\tptr := add(ptr, 32)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// clear unused\n\t\t\t\tfor { let i := n1 } lt(i, n0) { i := add(i, 1) } {\n\t\t\t\t\tsstore(add(slot, i), 0)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfunction getTiny(uint256 slot) internal view returns (bytes memory v) {\n\t\tunchecked {\n\t\t\tuint256 head;\n\t\t\tassembly { head := sload(slot) }\n\t\t\tuint256 size = head >> 224;\n\t\t\tif (size != 0) {\n\t\t\t\tv = new bytes(size);\n\t\t\t\tuint256 n = tinySlots(size);\n\t\t\t\tassembly {\n\t\t\t\t\tmstore(add(v, 32), shl(32, head))\n\t\t\t\t\tlet p := add(v, 60)\n\t\t\t\t\tfor { let i := 1 } lt(i, n) { i := add(i, 1) } {\n\t\t\t\t\t\tmstore(p, sload(add(slot, i)))\n\t\t\t\t\t\tp := add(p, 32)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
      },
      "@ensdomains/ens-contracts/contracts/utils/HexUtils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nlibrary HexUtils {\n    /**\n     * @dev Attempts to parse bytes32 from a hex string\n     * @param str The string to parse\n     * @param idx The offset to start parsing at\n     * @param lastIdx The (exclusive) last index in `str` to consider. Use `str.length` to scan the whole string.\n     */\n    function hexStringToBytes32(\n        bytes memory str,\n        uint256 idx,\n        uint256 lastIdx\n    ) internal pure returns (bytes32 r, bool valid) {\n        uint256 hexLength = lastIdx - idx;\n        if ((hexLength != 64 && hexLength != 40) || hexLength % 2 == 1) {\n            revert(\"Invalid string length\");\n        }\n        valid = true;\n        assembly {\n            // check that the index to read to is not past the end of the string\n            if gt(lastIdx, mload(str)) {\n                revert(0, 0)\n            }\n\n            function getHex(c) -> ascii {\n                // chars 48-57: 0-9\n                if and(gt(c, 47), lt(c, 58)) {\n                    ascii := sub(c, 48)\n                    leave\n                }\n                // chars 65-70: A-F\n                if and(gt(c, 64), lt(c, 71)) {\n                    ascii := add(sub(c, 65), 10)\n                    leave\n                }\n                // chars 97-102: a-f\n                if and(gt(c, 96), lt(c, 103)) {\n                    ascii := add(sub(c, 97), 10)\n                    leave\n                }\n                // invalid char\n                ascii := 0xff\n            }\n\n            let ptr := add(str, 32)\n            for {\n                let i := idx\n            } lt(i, lastIdx) {\n                i := add(i, 2)\n            } {\n                let byte1 := getHex(byte(0, mload(add(ptr, i))))\n                let byte2 := getHex(byte(0, mload(add(ptr, add(i, 1)))))\n                // if either byte is invalid, set invalid and break loop\n                if or(eq(byte1, 0xff), eq(byte2, 0xff)) {\n                    valid := false\n                    break\n                }\n                let combined := or(shl(4, byte1), byte2)\n                r := or(shl(8, r), combined)\n            }\n        }\n    }\n\n    /**\n     * @dev Attempts to parse an address from a hex string\n     * @param str The string to parse\n     * @param idx The offset to start parsing at\n     * @param lastIdx The (exclusive) last index in `str` to consider. Use `str.length` to scan the whole string.\n     */\n    function hexToAddress(\n        bytes memory str,\n        uint256 idx,\n        uint256 lastIdx\n    ) internal pure returns (address, bool) {\n        if (lastIdx - idx < 40) return (address(0x0), false);\n        (bytes32 r, bool valid) = hexStringToBytes32(str, idx, lastIdx);\n        return (address(uint160(uint256(r))), valid);\n    }\n}\n"
      },
      "@ensdomains/ens-contracts/contracts/wrapper/BytesUtils.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity ~0.8.17;\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(\n        bytes memory self,\n        uint256 offset,\n        uint256 len\n    ) 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     * @dev Returns the ENS namehash of a DNS-encoded name.\n     * @param self The DNS-encoded name to hash.\n     * @param offset The offset at which to start hashing.\n     * @return The namehash of the name.\n     */\n    function namehash(\n        bytes memory self,\n        uint256 offset\n    ) internal pure returns (bytes32) {\n        (bytes32 labelhash, uint256 newOffset) = readLabel(self, offset);\n        if (labelhash == bytes32(0)) {\n            require(offset == self.length - 1, \"namehash: Junk at end of name\");\n            return bytes32(0);\n        }\n        return\n            keccak256(abi.encodePacked(namehash(self, newOffset), labelhash));\n    }\n\n    /**\n     * @dev Returns the keccak-256 hash of a DNS-encoded label, and the offset to the start of the next label.\n     * @param self The byte string to read a label from.\n     * @param idx The index to read a label at.\n     * @return labelhash The hash of the label at the specified index, or 0 if it is the last label.\n     * @return newIdx The index of the start of the next label.\n     */\n    function readLabel(\n        bytes memory self,\n        uint256 idx\n    ) internal pure returns (bytes32 labelhash, uint256 newIdx) {\n        require(idx < self.length, \"readLabel: Index out of bounds\");\n        uint256 len = uint256(uint8(self[idx]));\n        if (len > 0) {\n            labelhash = keccak(self, idx + 1, len);\n        } else {\n            labelhash = bytes32(0);\n        }\n        newIdx = idx + len + 1;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS\n    }\n\n    /**\n     * @dev The signature derives the `address(0)`.\n     */\n    error ECDSAInvalidSignature();\n\n    /**\n     * @dev The signature has an invalid length.\n     */\n    error ECDSAInvalidSignatureLength(uint256 length);\n\n    /**\n     * @dev The signature has an S value that is in the upper half order.\n     */\n    error ECDSAInvalidSignatureS(bytes32 s);\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not\n     * return address(0) without also returning an error description. Errors are documented using an enum (error type)\n     * and a bytes32 providing additional information about the error.\n     *\n     * If no error is returned, then the address can be used for verification purposes.\n     *\n     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     */\n    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {\n        unchecked {\n            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n            // We do not check for an overflow here since the shift operation results in 0 or 1.\n            uint8 v = uint8((uint256(vs) >> 255) + 27);\n            return tryRecover(hash, v, r, s);\n        }\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     */\n    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError, bytes32) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS, s);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature, bytes32(0));\n        }\n\n        return (signer, RecoverError.NoError, bytes32(0));\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.\n     */\n    function _throwError(RecoverError error, bytes32 errorArg) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert ECDSAInvalidSignature();\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert ECDSAInvalidSignatureLength(uint256(errorArg));\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert ECDSAInvalidSignatureS(errorArg);\n        }\n    }\n}\n"
      },
      "@ensdomains/ens-contracts/contracts/resolvers/IMulticallable.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IMulticallable {\n    function multicall(\n        bytes[] calldata data\n    ) external returns (bytes[] memory results);\n\n    function multicallWithNodeCheck(\n        bytes32,\n        bytes[] calldata data\n    ) external returns (bytes[] memory results);\n}\n"
      },
      "@ensdomains/ens-contracts/contracts/resolvers/profiles/IContentHashResolver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4;\n\ninterface IContentHashResolver {\n    event ContenthashChanged(bytes32 indexed node, bytes hash);\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}\n"
      },
      "@ensdomains/ens-contracts/contracts/resolvers/profiles/IPubkeyResolver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4;\n\ninterface IPubkeyResolver {\n    event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);\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}\n"
      },
      "@ensdomains/ens-contracts/contracts/resolvers/profiles/INameResolver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4;\n\ninterface INameResolver {\n    event NameChanged(bytes32 indexed node, string name);\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}\n"
      },
      "@ensdomains/ens-contracts/contracts/resolvers/profiles/ITextResolver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4;\n\ninterface ITextResolver {\n    event TextChanged(\n        bytes32 indexed node,\n        string indexed indexedKey,\n        string key,\n        string value\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(\n        bytes32 node,\n        string calldata key\n    ) external view returns (string memory);\n}\n"
      },
      "@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddressResolver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4;\n\n/**\n * Interface for the new (multicoin) addr function.\n */\ninterface IAddressResolver {\n    event AddressChanged(\n        bytes32 indexed node,\n        uint256 coinType,\n        bytes newAddress\n    );\n\n    function addr(\n        bytes32 node,\n        uint256 coinType\n    ) external view returns (bytes memory);\n}\n"
      },
      "@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddrResolver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.4;\n\n/**\n * Interface for the legacy (ETH-only) addr function.\n */\ninterface IAddrResolver {\n    event AddrChanged(bytes32 indexed node, address a);\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) external view returns (address payable);\n}\n"
      },
      "@ensdomains/ens-contracts/contracts/resolvers/profiles/IExtendedDNSResolver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IExtendedDNSResolver {\n    function resolve(\n        bytes memory name,\n        bytes memory data,\n        bytes memory context\n    ) external view returns (bytes memory);\n}\n"
      },
      "@ensdomains/ens-contracts/contracts/resolvers/profiles/IExtendedResolver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IExtendedResolver {\n    function resolve(\n        bytes memory name,\n        bytes memory data\n    ) external view returns (bytes memory);\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
      },
      "@ensdomains/ens-contracts/contracts/registry/ENS.sol": {
        "content": "pragma solidity >=0.8.4;\n\ninterface ENS {\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(\n        address indexed owner,\n        address indexed operator,\n        bool approved\n    );\n\n    function setRecord(\n        bytes32 node,\n        address owner,\n        address resolver,\n        uint64 ttl\n    ) external;\n\n    function setSubnodeRecord(\n        bytes32 node,\n        bytes32 label,\n        address owner,\n        address resolver,\n        uint64 ttl\n    ) external;\n\n    function setSubnodeOwner(\n        bytes32 node,\n        bytes32 label,\n        address owner\n    ) external returns (bytes32);\n\n    function setResolver(bytes32 node, address resolver) external;\n\n    function setOwner(bytes32 node, address owner) external;\n\n    function setTTL(bytes32 node, uint64 ttl) external;\n\n    function setApprovalForAll(address operator, bool approved) external;\n\n    function owner(bytes32 node) external view returns (address);\n\n    function resolver(bytes32 node) external view returns (address);\n\n    function ttl(bytes32 node) external view returns (uint64);\n\n    function recordExists(bytes32 node) external view returns (bool);\n\n    function isApprovedForAll(\n        address owner,\n        address operator\n    ) external view returns (bool);\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": false,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      }
    }
  }}