Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix cross chain resolver compatibility with resolver interface and ENS UI #37

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion arb-gateway/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
},
"dependencies": {
"@chainlink/ccip-read-server": "^0.2.1",
"@ensdomains/evm-gateway": "^0.1.0",
"@ensdomains/evm-gateway": "workspace:*",
"@ethereumjs/block": "^5.0.0",
"@nomicfoundation/ethereumjs-block": "^5.0.2",
"commander": "^11.0.0",
Expand Down
10 changes: 5 additions & 5 deletions arb-verifier/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox": "^3.0.0",
"@nomicfoundation/hardhat-verify": "^1.0.0",
"@typechain/ethers-v6": "^0.4.0",
"@typechain/hardhat": "^8.0.0",
"@typechain/ethers-v6": "^0.5.1",
"@typechain/hardhat": "^9.0.0",
"@types/chai": "^4.2.0",
"@types/express": "^4.17.18",
"@types/mocha": ">=9.1.0",
Expand All @@ -26,19 +26,19 @@
"express": "^4.18.2",
"ganache": "^7.9.1",
"hardhat": "^2.16.0",
"hardhat-deploy": "^0.11.43",
"hardhat-deploy": "^0.12.2",
"hardhat-deploy-ethers": "^0.4.1",
"hardhat-gas-reporter": "^1.0.8",
"solidity-bytes-utils": "^0.8.0",
"solidity-coverage": "^0.8.1",
"supertest": "^6.3.3",
"ts-node": "^10.9.1",
"typechain": "^8.2.0",
"typechain": "^8.3.2",
"typescript": "^5.2.2"
},
"dependencies": {
"@arbitrum/nitro-contracts": "^1.1.0",
"@ensdomains/evm-verifier": "^0.1.0",
"@ensdomains/evm-verifier": "workspace:*",
"dotenv": "^16.3.1"
}
}
Binary file modified bun.lockb
Binary file not shown.
234 changes: 161 additions & 73 deletions crosschain-resolver/contracts/L1Resolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,23 @@ pragma solidity ^0.8.17;
import {EVMFetcher} from '@ensdomains/evm-verifier/contracts/EVMFetcher.sol';
import {EVMFetchTarget} from '@ensdomains/evm-verifier/contracts/EVMFetchTarget.sol';
import {IEVMVerifier} from '@ensdomains/evm-verifier/contracts/IEVMVerifier.sol';
import "@ensdomains/ens-contracts/contracts/registry/ENS.sol";
import {INameWrapper} from "@ensdomains/ens-contracts/contracts/wrapper/INameWrapper.sol";
import {BytesUtils} from "@ensdomains/ens-contracts/contracts/dnssec-oracle/BytesUtils.sol";
import {IAddrResolver} from "@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddrResolver.sol";
import {IAddressResolver} from "@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddressResolver.sol";
import {ITextResolver} from "@ensdomains/ens-contracts/contracts/resolvers/profiles/ITextResolver.sol";
import {IContentHashResolver} from "@ensdomains/ens-contracts/contracts/resolvers/profiles/IContentHashResolver.sol";
import '@ensdomains/ens-contracts/contracts/registry/ENS.sol';
import {INameWrapper} from '@ensdomains/ens-contracts/contracts/wrapper/INameWrapper.sol';
import {BytesUtils} from '@ensdomains/ens-contracts/contracts/dnssec-oracle/BytesUtils.sol';
import {IAddrResolver} from '@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddrResolver.sol';
import {IAddressResolver} from '@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddressResolver.sol';
import {ITextResolver} from '@ensdomains/ens-contracts/contracts/resolvers/profiles/ITextResolver.sol';
import {IContentHashResolver} from '@ensdomains/ens-contracts/contracts/resolvers/profiles/IContentHashResolver.sol';
import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';


contract L1Resolver is EVMFetchTarget {
contract L1Resolver is
EVMFetchTarget,
IAddrResolver,
IAddressResolver,
ITextResolver,
IContentHashResolver,
IERC165
{
using EVMFetcher for EVMFetcher.EVMFetchRequest;
using BytesUtils for bytes;
IEVMVerifier immutable verifier;
Expand All @@ -36,7 +43,7 @@ contract L1Resolver is EVMFetchTarget {
// isApprovedFor
address owner = ens.owner(node);
if (owner == address(nameWrapper)) {
owner = nameWrapper.ownerOf(uint256(node));
owner = nameWrapper.ownerOf(uint256(node));
}
return owner == msg.sender;
}
Expand All @@ -46,27 +53,29 @@ contract L1Resolver is EVMFetchTarget {
_;
}

constructor(
IEVMVerifier _verifier,
ENS _ens,
INameWrapper _nameWrapper
){
require(address(_nameWrapper) != address(0), "Name Wrapper address must be set");
require(address(_verifier) != address(0), "Verifier address must be set");
require(address(_ens) != address(0), "Registry address must be set");
verifier = _verifier;
ens = _ens;
nameWrapper = _nameWrapper;
constructor(IEVMVerifier _verifier, ENS _ens, INameWrapper _nameWrapper) {
require(
address(_nameWrapper) != address(0),
'Name Wrapper address must be set'
);
require(
address(_verifier) != address(0),
'Verifier address must be set'
);
require(address(_ens) != address(0), 'Registry address must be set');
verifier = _verifier;
ens = _ens;
nameWrapper = _nameWrapper;
}

/**
* Set target address to verify aagainst
* @param node The ENS node to query.
* @param target The L2 resolver address to verify against.
*/
function setTarget(bytes32 node, address target) public authorised(node){
targets[node] = target;
emit TargetSet(node, target);
function setTarget(bytes32 node, address target) public authorised(node) {
targets[node] = target;
emit TargetSet(node, target);
}

/**
Expand All @@ -84,91 +93,108 @@ contract L1Resolver is EVMFetchTarget {
node = bytes32(0);
if (len > 0) {
bytes32 label = name.keccak(offset + 1, len);
(node, target) = getTarget(
name,
offset + len + 1
);
(node, target) = getTarget(name, offset + len + 1);
node = keccak256(abi.encodePacked(node, label));
if(targets[node] != address(0)){
return (
node,
targets[node]
);
if (targets[node] != address(0)) {
return (node, targets[node]);
}
} else {
return (
bytes32(0),
address(0)
);
return (bytes32(0), address(0));
}
return (node, target);
}

/**
/**
* @dev Resolve and verify a record stored in l2 target address. It supports subname by fetching target recursively to the nearlest parent.
* @param name DNS encoded ENS name to query
* @param data The actual calldata
* @return result result of the call
*/
function resolve(bytes calldata name, bytes calldata data) external view returns (bytes memory result) {
function resolve(
bytes calldata name,
bytes calldata data
) external view returns (bytes memory result) {
(, address target) = getTarget(name, 0);
bytes4 selector = bytes4(data);

if (selector == IAddrResolver.addr.selector) {
(bytes32 node) = abi.decode(data[4:], (bytes32));
bytes32 node = abi.decode(data[4:], (bytes32));
return _addr(node, target);
}
if (selector == IAddressResolver.addr.selector) {
(bytes32 node, uint256 cointype) = abi.decode(data[4:], (bytes32, uint256));
(bytes32 node, uint256 cointype) = abi.decode(
data[4:],
(bytes32, uint256)
);
return _addr(node, cointype, target);
}
if (selector == ITextResolver.text.selector) {
(bytes32 node, string memory key) = abi.decode(data[4:], (bytes32, string));
(bytes32 node, string memory key) = abi.decode(
data[4:],
(bytes32, string)
);
return bytes(_text(node, key, target));
}
if (selector == IContentHashResolver.contenthash.selector) {
(bytes32 node) = abi.decode(data[4:], (bytes32));
bytes32 node = abi.decode(data[4:], (bytes32));
return _contenthash(node, target);
}
}

function _addr(bytes32 node, address target) private view returns (bytes memory) {
EVMFetcher.newFetchRequest(verifier, target)
function _addr(
bytes32 node,
address target
) private view returns (bytes memory) {
EVMFetcher
.newFetchRequest(verifier, target)
.getStatic(RECORD_VERSIONS_SLOT)
.element(node)
.element(node)
.getDynamic(VERSIONABLE_ADDRESSES_SLOT)
.ref(0)
.element(node)
.element(COIN_TYPE_ETH)
.fetch(this.addrCallback.selector, ''); // recordVersions
.ref(0)
.element(node)
.element(COIN_TYPE_ETH)
.fetch(this.addrCallback.selector, msg.data[0:4]); // recordVersions
}

function addrCallback(
bytes[] memory values,
bytes memory
bytes memory sig
) public pure returns (bytes memory) {
return abi.encode(address(bytes20(values[1])));
address result = address(bytes20(values[1]));
if (keccak256(sig) != keccak256(hex"9061b923")) {
// Return address instead of bytes
assembly {
let freemem := mload(0x40)
mstore(freemem, result)
return(freemem, 0x20)
}
}
return abi.encode(result);
}

function _addr(
bytes32 node,
uint256 coinType,
address target
) private view returns (bytes memory) {
EVMFetcher.newFetchRequest(verifier, target)
EVMFetcher
.newFetchRequest(verifier, target)
.getStatic(RECORD_VERSIONS_SLOT)
.element(node)
.element(node)
.getDynamic(VERSIONABLE_ADDRESSES_SLOT)
.ref(0)
.element(node)
.element(coinType)
.fetch(this.addrCoinTypeCallback.selector, '');
.ref(0)
.element(node)
.element(coinType)
.fetch(this.addrCoinTypeCallback.selector, msg.data[0:4]);
}

function addrCoinTypeCallback(
bytes[] memory values,
bytes memory
bytes memory sig
) public pure returns (bytes memory) {
if (keccak256(sig) != keccak256(hex"9061b923")) {
return values[1];
}
return abi.encode(values[1]);
}

Expand All @@ -177,38 +203,100 @@ contract L1Resolver is EVMFetchTarget {
string memory key,
address target
) private view returns (bytes memory) {
EVMFetcher.newFetchRequest(verifier, target)
EVMFetcher
.newFetchRequest(verifier, target)
.getStatic(RECORD_VERSIONS_SLOT)
.element(node)
.element(node)
.getDynamic(VERSIONABLE_TEXTS_SLOT)
.ref(0)
.element(node)
.element(key)
.fetch(this.textCallback.selector, '');
.ref(0)
.element(node)
.element(key)
.fetch(this.textCallback.selector, msg.data[0:4]);
}

function textCallback(
bytes[] memory values,
bytes memory
bytes memory sig
) public pure returns (bytes memory) {
if (keccak256(sig) != keccak256(hex"9061b923")) {
return bytes(string(values[1]));
}
return abi.encode(string(values[1]));
}

function _contenthash(bytes32 node, address target) private view returns (bytes memory) {
EVMFetcher.newFetchRequest(verifier, target)
function _contenthash(
bytes32 node,
address target
) private view returns (bytes memory) {
EVMFetcher
.newFetchRequest(verifier, target)
.getStatic(RECORD_VERSIONS_SLOT)
.element(node)
.element(node)
.getDynamic(VERSIONABLE_HASHES_SLOT)
.ref(0)
.element(node)
.fetch(this.contenthashCallback.selector, '');
.ref(0)
.element(node)
.fetch(this.contenthashCallback.selector, msg.data[0:4]);
}

function contenthashCallback(
bytes[] memory values,
bytes memory
bytes memory sig
) public pure returns (bytes memory) {
if (keccak256(sig) != keccak256(hex"9061b923")) {
return values[1];
}
return abi.encode(values[1]);
}

/**
* Returns the address associated with an ENS node.
* @param node The ENS node to query.
* @return The associated address.
*/
function addr(
bytes32 node
) public view virtual override returns (address payable) {
_addr(node, targets[node]);
}

function addr(
bytes32 node,
uint256 coinType
) public view virtual override returns (bytes memory) {
_addr(node, coinType, targets[node]);
}

/**
* Returns the text data associated with an ENS node and key.
* @param node The ENS node to query.
* @param key The text data key to query.
* @return The associated text data.
*/
function text(
bytes32 node,
string calldata key
) external view virtual override returns (string memory) {
_text(node, key, targets[node]);
}

/**
* Returns the contenthash associated with an ENS node.
* @param node The ENS node to query.
* @return The associated contenthash.
*/
function contenthash(
bytes32 node
) external view virtual override returns (bytes memory) {
_contenthash(node, targets[node]);
}

function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
return
interfaceID == type(IAddrResolver).interfaceId ||
interfaceID == type(IAddressResolver).interfaceId ||
interfaceID == type(ITextResolver).interfaceId ||
interfaceID == type(IContentHashResolver).interfaceId;
}
}
Loading