Skip to content

Instantly share code, notes, and snippets.

@adraffy
Created January 21, 2024 23:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adraffy/4dbef1e1ef27e4c58c31b1bcca8000d4 to your computer and use it in GitHub Desktop.
Save adraffy/4dbef1e1ef27e4c58c31b1bcca8000d4 to your computer and use it in GitHub Desktop.
pragma solidity ^0.8.23;
import {IERC165} from "@openzeppelin/contracts@4.8.2/utils/introspection/IERC165.sol";
import {ENS} from "https://github.com/ensdomains/ens-contracts/blob/master/contracts/registry/ENS.sol";
import {IExtendedResolver} from "https://github.com/ensdomains/ens-contracts/blob/master/contracts/resolvers/profiles/IExtendedResolver.sol";
import {IMulticallable} from "https://github.com/ensdomains/ens-contracts/blob/master/contracts/resolvers/IMulticallable.sol";
import {BytesUtils} from "https://github.com/ensdomains/ens-contracts/blob/master/contracts/wrapper/BytesUtils.sol";
contract MultiResolver is IERC165, IExtendedResolver {
using BytesUtils for bytes;
address constant ENS_REGISTRY = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
function supportsInterface(bytes4 x) external pure returns (bool) {
return x == type(IERC165).interfaceId // 0x01ffc9a7
|| x == type(IExtendedResolver).interfaceId; // 0x9061b923
}
function findResolver(bytes memory name) public view returns (address resolver, bool wildcard, uint256 offset) {
while (true) {
bytes32 node = name.namehash(offset);
resolver = ENS(ENS_REGISTRY).resolver(node);
if (resolver != address(0)) break;
offset += 1 + uint256(uint8(name[offset]));
}
try IERC165(resolver).supportsInterface(type(IExtendedResolver).interfaceId) returns (bool support) {
require(support || offset == 0);
wildcard = support;
} catch {
revert();
}
}
error OffchainLookup(address sender, string[] urls, bytes callData, bytes4 callbackFunction, bytes extraData);
function resolveCallback(bytes calldata response, bytes calldata wrappedExtraData) external view returns (bytes memory) {
(address resolver, bytes4 callbackFunction, bytes memory extraData) = abi.decode(wrappedExtraData, (address, bytes4, bytes));
(bool success, bytes memory data) = resolver.staticcall(abi.encodeWithSelector(callbackFunction, response, extraData));
if (!success) assembly { revert(add(data, 32), mload(data)) }
return abi.decode(data, (bytes));
}
function resolve(bytes memory name, bytes memory data) external view returns (bytes memory) {
(address resolver, bool wildcard, ) = findResolver(name);
if (wildcard) {
(bool success, bytes memory v) = resolver.staticcall(abi.encodeWithSelector(IExtendedResolver.resolve.selector, name, data));
if (success) return v; // on-chain wildcard
assembly {
mstore(add(v, 4), sub(mload(v), 4))
v := add(v, 4)
}
(
address sender,
string[] memory urls,
bytes memory callData,
bytes4 callbackFunction,
bytes memory extraData
) = abi.decode(v, (address, string[], bytes, bytes4, bytes));
require(sender == resolver);
revert OffchainLookup(
address(this),
urls,
callData,
this.resolveCallback.selector,
abi.encode(address(resolver), callbackFunction, extraData)
);
}
if (bytes4(data) == IMulticallable.multicall.selector) { // multicall
assembly {
mstore(add(data, 4), sub(mload(data), 4))
data := add(data, 4)
}
bytes[] memory calls = abi.decode(data, (bytes[])); // unbundle the requests
for (uint256 i; i < calls.length; i++) {
(bool success, bytes memory ret) = resolver.staticcall(calls[i]); // call them directly
calls[i] = success ? ret : bytes('');
}
return abi.encode(calls); // bundle the results
} else {
(bool success, bytes memory ret) = resolver.staticcall(data); // single request, call it directly
if (!success) assembly { revert(add(ret, 32), mload(ret)) }
return ret;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment