creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/CCIPRewriter.sol": {
        "content": "/// @author raffy.eth\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\n// interfaces\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {ENS} from \"@ensdomains/ens-contracts/contracts/registry/ENS.sol\";\nimport {IExtendedResolver} from \"@ensdomains/ens-contracts/contracts/resolvers/profiles/IExtendedResolver.sol\";\nimport {IMulticallable} from \"@ensdomains/ens-contracts/contracts/resolvers/IMulticallable.sol\";\n\n// libraries\nimport {Base32} from \"./Base32.sol\";\nimport {BytesUtils} from \"@ensdomains/ens-contracts/contracts/wrapper/BytesUtils.sol\";\n\n// bases\nimport {ReverseClaimer} from \"@ensdomains/ens-contracts/contracts/reverseRegistrar/ReverseClaimer.sol\";\n\n// https://eips.ethereum.org/EIPS/eip-3668\nerror OffchainLookup(address from, string[] urls, bytes request, bytes4 callback, bytes carry);\n\ncontract CCIPRewriter is IERC165, IExtendedResolver, ReverseClaimer {\n\tusing BytesUtils for bytes;\n\n\terror Unreachable(bytes name); \n\terror InvalidBase32(bytes name);\n\t\n\tENS immutable ens;\n\tconstructor(ENS _ens) ReverseClaimer(_ens, msg.sender) {\n\t\tens = _ens;\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(IExtendedResolver).interfaceId\n\t\t\t|| x == 0x87f60257; // https://adraffy.github.io/keccak.js/test/demo.html#algo=evm&s=CCIPRewriter&escape=1&encoding=utf8\n\t}\n\n\t// IExtendedResolver\n\tfunction resolve(bytes memory name, bytes memory data) external view returns (bytes memory v) {\n\t\tunchecked {\n\t\t\t(, uint256 offset, uint256 size) = _findSelf(name);\n\t\t\tif (offset == 0 || size == 0) return new bytes(64);\n\t\t\toffset -= size;\n\t\t\tuint256 name_ptr;\n\t\t\tassembly { name_ptr := add(add(name, 32), offset) }\n\t\t\t(bool valid, bytes memory url) = Base32.decode(name_ptr, size);\n\t\t\tif (!valid) revert InvalidBase32(name);\n\t\t\tstring[] memory urls = new string[](1);\n\t\t\turls[0] = string(url);\n\t\t\tassembly { \n\t\t\t\tmstore8(sub(name_ptr, 1), 0) // terminate\n\t\t\t\tmstore(name, offset) // truncate\n\t\t\t}\n\t\t\t(, address resolver, bool wild, ) = _findResolver(name);\n\t\t\tif (resolver == address(0)) return new bytes(64);\n\t\t\tbytes32 node = name.namehash(0);\n\t\t\tassembly { mstore(add(data, 36), node) } // rewrite the target\n\t\t\tbool ok;\n\t\t\tif (wild) {\n\t\t\t\t(ok, v) = resolver.staticcall(abi.encodeCall(IExtendedResolver.resolve, (name, data)));\n\t\t\t\tif (ok) {\n\t\t\t\t\tv = abi.decode(v, (bytes));\n\t\t\t\t} else {\n\t\t\t\t\tif (bytes4(v) != OffchainLookup.selector) assembly { revert(add(v, 32), mload(v)) }\n\t\t\t\t\tassembly {\n\t\t\t\t\t\tmstore(add(v, 4), sub(mload(v), 4)) \n\t\t\t\t\t\tv := add(v, 4)\n\t\t\t\t\t}\n\t\t\t\t\t(address sender, , bytes memory request, bytes4 callback, bytes memory carry) = abi.decode(v, (address, string[], bytes, bytes4, bytes));\n\t\t\t\t\trevert OffchainLookup(address(this), urls, request, this.resolveCallback.selector, abi.encode(sender, callback, carry));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t(ok, v) = resolver.staticcall(data);\n\t\t\t\tif (!ok) assembly { revert(add(v, 32), mload(v)) } // propagate error\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction resolveCallback(bytes calldata response, bytes calldata extra) external view returns (bytes memory) {\n\t\t(address sender, bytes4 callback, bytes memory carry) = abi.decode(extra, (address, bytes4, bytes));\n\t\t(bool ok, bytes memory v) = sender.staticcall(abi.encodeWithSelector(callback, response, carry));\n\t\tif (!ok) assembly { revert(add(v, 32), mload(v)) }\n\t\tassembly { return(add(v, 32), mload(v)) }\n\t}\n\n\tfunction _findSelf(bytes memory name) internal view returns (bytes32 node, uint256 offset, uint256 size) {\n\t\tunchecked {\n\t\t\twhile (true) {\n\t\t\t\tnode = name.namehash(offset);\n\t\t\t\tif (ens.resolver(node) == address(this)) break;\n\t\t\t\tsize = uint256(uint8(name[offset]));\n\t\t\t\tif (size == 0) revert Unreachable(name);\n\t\t\t\toffset += 1 + size;\n\t\t\t}\n\t\t}\n\t}\n\tfunction _findResolver(bytes memory name) internal view returns (bytes32 node, address resolver, bool wild, uint256 offset) {\n\t\tunchecked {\n\t\t\twhile (true) {\n\t\t\t\tnode = name.namehash(offset);\n\t\t\t\tresolver = ens.resolver(node);\n\t\t\t\tif (resolver != address(0)) break;\n\t\t\t\toffset += 1 + uint256(uint8(name[offset]));\n\t\t\t}\n \t\t\ttry IERC165(resolver).supportsInterface{gas: 30000}(type(IExtendedResolver).interfaceId) returns (bool quacks) {\n\t\t\t\twild = quacks;\n\t\t\t} catch {\n\t\t\t}\n\t\t\tif (offset != 0 && !wild) revert Unreachable(name);\n\t\t}\n\t}\n\n}"
      },
      "lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\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"
      },
      "lib/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"
      },
      "lib/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"
      },
      "lib/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"
      },
      "src/Base32.sol": {
        "content": "/// @author raffy.eth\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nlibrary Base32 {\n\n\tfunction decode(uint256 pos, uint256 len) internal pure returns (bool ok, bytes memory) {\n\t\tunchecked {\n\t\t\tuint256 n = (len * 5) >> 3;\n\t\t\tbytes memory v = new bytes(n);\n\t\t\tuint256 clip;\n\t\t\tuint256 ammo;\n\t\t\tuint256 bits;\n\t\t\tuint256 word;\n\t\t\tfor (uint256 i; i < n; i += 1) {\n\t\t\t\twhile (bits < 8) {\n\t\t\t\t\tif (ammo == 0) {\n\t\t\t\t\t\tammo = 32;\n\t\t\t\t\t\tassembly { clip := mload(pos) }\n\t\t\t\t\t\tpos += ammo;\n\t\t\t\t\t}\n\t\t\t\t\tuint256 x = _indexOf(clip >> 248);\n\t\t\t\t\tif (x == 32) return (false, '');\n\t\t\t\t\tclip <<= 8;\n\t\t\t\t\tammo -= 1;\n\t\t\t\t\tword = (word << 5) | x;\n\t\t\t\t\tbits += 5;\n\t\t\t\t}\n\t\t\t\tv[i] = bytes1(uint8(word >> (bits -= 8)));\n\t\t\t}\n\t\t\treturn (true, v);\n\t\t}\n\t}\n\n\t// \"abcdefghijklmnopqrstuvwxyz234567\";\n\tfunction _indexOf(uint256 x) internal pure returns (uint256) {\n\t\tif (x >= 97 && x <= 122) {\n\t\t\treturn x - 97;\n\t\t} else if (x >= 50 && x <= 55) {\n\t\t\treturn x - 24; // 50-26\n\t\t} else {\n\t\t\treturn 32;\n\t\t}\n\t}\n\n}"
      },
      "lib/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"
      },
      "lib/ens-contracts/contracts/reverseRegistrar/ReverseClaimer.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity >=0.8.17 <0.9.0;\n\nimport {ENS} from \"../registry/ENS.sol\";\nimport {IReverseRegistrar} from \"../reverseRegistrar/IReverseRegistrar.sol\";\n\ncontract ReverseClaimer {\n    bytes32 constant ADDR_REVERSE_NODE =\n        0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;\n\n    constructor(ENS ens, address claimant) {\n        IReverseRegistrar reverseRegistrar = IReverseRegistrar(\n            ens.owner(ADDR_REVERSE_NODE)\n        );\n        reverseRegistrar.claim(claimant);\n    }\n}\n"
      },
      "lib/ens-contracts/contracts/reverseRegistrar/IReverseRegistrar.sol": {
        "content": "pragma solidity >=0.8.4;\n\ninterface IReverseRegistrar {\n    function setDefaultResolver(address resolver) external;\n\n    function claim(address owner) external returns (bytes32);\n\n    function claimForAddr(\n        address addr,\n        address owner,\n        address resolver\n    ) external returns (bytes32);\n\n    function claimWithResolver(\n        address owner,\n        address resolver\n    ) external returns (bytes32);\n\n    function setName(string memory name) external returns (bytes32);\n\n    function setNameForAddr(\n        address addr,\n        address owner,\n        address resolver,\n        string memory name\n    ) external returns (bytes32);\n\n    function node(address addr) external pure returns (bytes32);\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
        "@ensdomains/ens-contracts/=lib/ens-contracts/",
        "forge-std/=lib/forge-std/src/",
        "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
        "ens-contracts/=lib/ens-contracts/contracts/",
        "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/",
        "openzeppelin/=lib/openzeppelin-contracts/contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "viaIR": false,
      "libraries": {}
    }
  }}