Skip to content

Commit

Permalink
Merge branch 'staging' into feat/universal-resolver-result
Browse files Browse the repository at this point in the history
  • Loading branch information
TateB committed Nov 30, 2023
2 parents 5765963 + e08a9b3 commit 6117475
Show file tree
Hide file tree
Showing 25 changed files with 2,502 additions and 1,358 deletions.
116 changes: 102 additions & 14 deletions contracts/dnsregistrar/OffchainDNSResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import "../dnssec-oracle/RRUtils.sol";
import "../registry/ENSRegistry.sol";
import "../utils/HexUtils.sol";

import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {LowLevelCallUtils} from "../utils/LowLevelCallUtils.sol";

error InvalidOperation();
error OffchainLookup(
address sender,
string[] urls,
Expand All @@ -29,8 +33,9 @@ interface IDNSGateway {
uint16 constant CLASS_INET = 1;
uint16 constant TYPE_TXT = 16;

contract OffchainDNSResolver is IExtendedResolver {
contract OffchainDNSResolver is IExtendedResolver, IERC165 {
using RRUtils for *;
using Address for address;
using BytesUtils for bytes;
using HexUtils for bytes;

Expand All @@ -46,20 +51,23 @@ contract OffchainDNSResolver is IExtendedResolver {
gatewayURL = _gatewayURL;
}

function supportsInterface(
bytes4 interfaceId
) external pure override returns (bool) {
return interfaceId == type(IExtendedResolver).interfaceId;
}

function resolve(
bytes calldata name,
bytes calldata data
) external view returns (bytes memory) {
string[] memory urls = new string[](1);
urls[0] = gatewayURL;

revert OffchainLookup(
address(this),
urls,
abi.encodeCall(IDNSGateway.resolve, (name, TYPE_TXT)),
OffchainDNSResolver.resolveCallback.selector,
abi.encode(name, data)
);
return
callWithOffchainLookupPropagation(
msg.sender,
name,
data,
abi.encodeCall(IExtendedResolver.resolve, (name, data))
);
}

function resolveCallback(
Expand Down Expand Up @@ -106,17 +114,30 @@ contract OffchainDNSResolver is IExtendedResolver {
)
) {
return
IExtendedDNSResolver(dnsresolver).resolve(
callWithOffchainLookupPropagation(
dnsresolver,
name,
query,
context
abi.encodeCall(
IExtendedDNSResolver.resolve,
(name, query, context)
)
);
} else if (
IERC165(dnsresolver).supportsInterface(
IExtendedResolver.resolve.selector
)
) {
return IExtendedResolver(dnsresolver).resolve(name, query);
return
callWithOffchainLookupPropagation(
dnsresolver,
name,
query,
abi.encodeCall(
IExtendedResolver.resolve,
(name, query)
)
);
} else {
(bool ok, bytes memory ret) = address(dnsresolver)
.staticcall(query);
Expand Down Expand Up @@ -223,4 +244,71 @@ contract OffchainDNSResolver is IExtendedResolver {
abi.encodePacked(parentNode, name.keccak(idx, separator - idx))
);
}

function callWithOffchainLookupPropagation(
address target,
bytes memory name,
bytes memory innerdata,
bytes memory data
) internal view returns (bytes memory) {
if (target.isContract()) {
bool result = LowLevelCallUtils.functionStaticCall(
address(target),
data
);
uint256 size = LowLevelCallUtils.returnDataSize();
if (result) {
bytes memory returnData = LowLevelCallUtils.readReturnData(
0,
size
);
return abi.decode(returnData, (bytes));
}
// Failure
if (size >= 4) {
bytes memory errorId = LowLevelCallUtils.readReturnData(0, 4);
if (bytes4(errorId) == OffchainLookup.selector) {
// Offchain lookup. Decode the revert message and create our own that nests it.
bytes memory revertData = LowLevelCallUtils.readReturnData(
4,
size - 4
);
(
address sender,
string[] memory urls,
bytes memory callData,
bytes4 innerCallbackFunction,
bytes memory extraData
) = abi.decode(
revertData,
(address, string[], bytes, bytes4, bytes)
);

if (sender != target) {
revert InvalidOperation();
}

revert OffchainLookup(
address(this),
urls,
callData,
OffchainDNSResolver.resolveCallback.selector,
abi.encode(sender, innerCallbackFunction, extraData)
);
}
}
LowLevelCallUtils.propagateRevert();
} else {
string[] memory urls = new string[](1);
urls[0] = gatewayURL;

revert OffchainLookup(
address(this),
urls,
abi.encodeCall(IDNSGateway.resolve, (name, TYPE_TXT)),
OffchainDNSResolver.resolveCallback.selector,
abi.encode(name, innerdata)
);
}
}
}
6 changes: 4 additions & 2 deletions contracts/dnsregistrar/RecordParser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ library RecordParser {
" "
);
if (terminator == type(uint256).max) {
terminator = input.length;
terminator = len + offset;
nextOffset = terminator;
} else {
nextOffset = terminator + 1;
}

key = input.substring(offset, separator - offset);
value = input.substring(separator + 1, terminator - separator - 1);
nextOffset = terminator + 1;
}
}
37 changes: 37 additions & 0 deletions contracts/dnsregistrar/mocks/DummyNonCCIPAwareResolver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "../OffchainDNSResolver.sol";
import "../../resolvers/profiles/IExtendedResolver.sol";

contract DummyNonCCIPAwareResolver is IExtendedResolver, ERC165 {
OffchainDNSResolver dnsResolver;

constructor(OffchainDNSResolver _dnsResolver) {
dnsResolver = _dnsResolver;
}

function supportsInterface(
bytes4 interfaceId
) public view virtual override returns (bool) {
return
interfaceId == type(IExtendedResolver).interfaceId ||
super.supportsInterface(interfaceId);
}

function resolve(
bytes calldata /* name */,
bytes calldata data
) external view returns (bytes memory) {
string[] memory urls = new string[](1);
urls[0] = "https://example.com/";
revert OffchainLookup(
address(dnsResolver),
urls,
data,
OffchainDNSResolver.resolveCallback.selector,
data
);
}
}
47 changes: 47 additions & 0 deletions contracts/dnsregistrar/mocks/DummyParser.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
pragma solidity ^0.8.4;

import "../../dnssec-oracle/BytesUtils.sol";
import "../RecordParser.sol";

contract DummyParser {
using BytesUtils for bytes;

// parse data in format: name;key1=value1 key2=value2;url
function parseData(
bytes memory data,
uint256 kvCount
)
external
pure
returns (
string memory name,
string[] memory keys,
string[] memory values,
string memory url
)
{
uint256 len = data.length;
// retrieve name
uint256 sep1 = data.find(0, len, ";");
name = string(data.substring(0, sep1));

// retrieve url
uint256 sep2 = data.find(sep1 + 1, len - sep1, ";");
url = string(data.substring(sep2 + 1, len - sep2 - 1));

keys = new string[](kvCount);
values = new string[](kvCount);
// retrieve keys and values
uint256 offset = sep1 + 1;
for (uint256 i; i < kvCount && offset < len; i++) {
(
bytes memory key,
bytes memory val,
uint256 nextOffset
) = RecordParser.readKeyValue(data, offset, sep2 - offset);
keys[i] = string(key);
values[i] = string(val);
offset = nextOffset;
}
}
}
47 changes: 47 additions & 0 deletions contracts/resolvers/profiles/ExtendedDNSResolver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../../resolvers/profiles/IExtendedDNSResolver.sol";
import "../../resolvers/profiles/IAddressResolver.sol";
import "../../resolvers/profiles/IAddrResolver.sol";
import "../../utils/HexUtils.sol";

contract ExtendedDNSResolver is IExtendedDNSResolver, IERC165 {
using HexUtils for *;

uint256 private constant COIN_TYPE_ETH = 60;

error NotImplemented();
error InvalidAddressFormat();

function supportsInterface(
bytes4 interfaceId
) external view virtual override returns (bool) {
return interfaceId == type(IExtendedDNSResolver).interfaceId;
}

function resolve(
bytes calldata /* name */,
bytes calldata data,
bytes calldata context
) external pure override returns (bytes memory) {
bytes4 selector = bytes4(data);
if (
selector == IAddrResolver.addr.selector ||
selector == IAddressResolver.addr.selector
) {
if (selector == IAddressResolver.addr.selector) {
(, uint256 coinType) = abi.decode(data[4:], (bytes32, uint256));
if (coinType != COIN_TYPE_ETH) return abi.encode("");
}
(address record, bool valid) = context.hexToAddress(
2,
context.length
);
if (!valid) revert InvalidAddressFormat();
return abi.encode(record);
}
revert NotImplemented();
}
}
4 changes: 4 additions & 0 deletions contracts/utils/HexUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ library HexUtils {
uint256 idx,
uint256 lastIdx
) internal pure returns (bytes32 r, bool valid) {
uint256 hexLength = lastIdx - idx;
if ((hexLength != 64 && hexLength != 40) || hexLength % 2 == 1) {
revert("Invalid string length");
}
valid = true;
assembly {
// check that the index to read to is not past the end of the string
Expand Down
Loading

0 comments on commit 6117475

Please sign in to comment.