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

Add metadata #22

Merged
merged 11 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion crosschain-resolver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ On L1
// On L1
await ENS.setResolver(l1lresolver)
const l2resolverAddress = await DelegatableResolverFactory.predictAddress(OWNER_ADDRESS)
await L1Resolver.setTarget(node, l2resolverAddress)
await L1Resolver.setTarget(encodedname, l2resolverAddress)
// On L2
const l2resolverAddress = await DelegatableResolverFactory.predictAddress(OWNER_ADDRESS)
await DelegatableResolverFactory.create(OWNER_ADDRESS)
Expand Down
18 changes: 18 additions & 0 deletions crosschain-resolver/contracts/IMetadataResolver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IMetadataResolver {
/**
* @notice Get metadata about the CCIP Resolver
* @dev This function provides metadata about the CCIP Resolver, including its name, coin type, GraphQL URL, storage type, and encoded information.
* @param name The domain name in format (dnsEncoded)
* @return name The name of the resolver ("CCIP RESOLVER")
makoto marked this conversation as resolved.
Show resolved Hide resolved
* @return coinType Resolvers coin type (60 for Ethereum)
makoto marked this conversation as resolved.
Show resolved Hide resolved
* @return graphqlUrl The GraphQL URL used by the resolver
* @return storageType Storage Type (0 for EVM)
makoto marked this conversation as resolved.
Show resolved Hide resolved
* @return storageLocation The storage identifier. For EVM chains, this is the address of the resolver contract.
* @return context can be l2 resolver contract address for evm chain but can be any l2 storage identifier for non evm chain
makoto marked this conversation as resolved.
Show resolved Hide resolved
*
*/
function metadata(bytes calldata name) external view returns (string memory, uint256, string memory, uint8, bytes memory, bytes memory);
makoto marked this conversation as resolved.
Show resolved Hide resolved
}
92 changes: 80 additions & 12 deletions crosschain-resolver/contracts/L1Resolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import {ITextResolver} from "@ensdomains/ens-contracts/contracts/resolvers/profi
import {IContentHashResolver} from "@ensdomains/ens-contracts/contracts/resolvers/profiles/IContentHashResolver.sol";
import "@ensdomains/ens-contracts/contracts/resolvers/profiles/IExtendedResolver.sol";
import {ITargetResolver} from './ITargetResolver.sol';
import {IMetadataResolver} from './IMetadataResolver.sol';
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

contract L1Resolver is EVMFetchTarget, ITargetResolver, IExtendedResolver, ERC165 {
contract L1Resolver is EVMFetchTarget, ITargetResolver, IMetadataResolver, IExtendedResolver, ERC165 {
using EVMFetcher for EVMFetcher.EVMFetchRequest;
using BytesUtils for bytes;
IEVMVerifier public immutable verifier;
Expand All @@ -27,9 +28,20 @@ contract L1Resolver is EVMFetchTarget, ITargetResolver, IExtendedResolver, ERC16
uint256 constant VERSIONABLE_ADDRESSES_SLOT = 2;
uint256 constant VERSIONABLE_HASHES_SLOT = 3;
uint256 constant VERSIONABLE_TEXTS_SLOT = 10;
string public graphqlUrl;
string public resolverName;
uint256 public l2ResolverCoinType;

event TargetSet(bytes32 indexed node, address target);

event TargetSet(bytes name, bytes32 indexed node, address target);
makoto marked this conversation as resolved.
Show resolved Hide resolved
event MetadataChanged(
makoto marked this conversation as resolved.
Show resolved Hide resolved
bytes name,
string resolverName,
uint256 coinType,
string graphqlUrl,
uint8 storageType,
bytes storageLocation,
bytes context
);
function isAuthorised(bytes32 node) internal view returns (bool) {
// TODO: Add support for
// trustedETHController
Expand All @@ -43,32 +55,58 @@ contract L1Resolver is EVMFetchTarget, ITargetResolver, IExtendedResolver, ERC16
return owner == msg.sender;
}

modifier authorised(bytes32 node) {
require(isAuthorised(node));
_;
}

/**
* @param _verifier The chain verifier address
* @param _ens The ENS registry address
* @param _nameWrapper The ENS name wrapper address
* @param _graphqlUrl The offchain/l2 graphql endpoint url
* @param _resolverName The name of the resolver, eg: "OP Resolver"
* @param _l2ResolverCoinType The chainId at which the resolver resolves data from. 0 if storageLocation is offChain
*/
constructor(
IEVMVerifier _verifier,
ENS _ens,
INameWrapper _nameWrapper
INameWrapper _nameWrapper,
string memory _graphqlUrl,
string memory _resolverName,
uint256 _l2ResolverCoinType
){
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;
graphqlUrl = _graphqlUrl;
resolverName = _resolverName;
l2ResolverCoinType = _l2ResolverCoinType;
}

/**
* Set target address to verify aagainst
* @param node The ENS node to query.
* @param name The encoded name to query.
* @param target The L2 resolver address to verify against.
*/
function setTarget(bytes32 node, address target) public authorised(node){
function setTarget(bytes calldata name, address target) public {
(bytes32 node,) = getTarget(name);
require(isAuthorised(node));
targets[node] = target;
emit TargetSet(node, target);
emit TargetSet(name, node, target);
(
,,,
uint8 storageType,
bytes memory storageLocation,
bytes memory context
) = metadata(name);
emit MetadataChanged(
name,
resolverName,
l2ResolverCoinType,
graphqlUrl,
storageType,
storageLocation,
context
);
}

/**
Expand Down Expand Up @@ -218,12 +256,42 @@ contract L1Resolver is EVMFetchTarget, ITargetResolver, IExtendedResolver, ERC16
return abi.encode(values[1]);
}

/**
* @notice Get metadata about the L1 Resolver
* @dev This function provides metadata about the L1 Resolver, including its name, coin type, GraphQL URL, storage type, and encoded information.
* @param name The domain name in format (dnsEncoded)
* @return name The name of the resolver ("CCIP RESOLVER")
* @return coinType Resolvers coin type (60 for Ethereum)
* @return graphqlUrl The GraphQL URL used by the resolver
* @return storageType Storage Type (0 for EVM)
* @return storageLocation The storage identifier. For EVM chains, this is the address of the resolver contract.
* @return context can be l2 resolver contract address for evm chain but can be any l2 storage identifier for non-evm chain
*/
function metadata(
bytes calldata name
) public view returns (string memory, uint256, string memory, uint8, bytes memory, bytes memory) {
(, address target) = getTarget(name);

return (
resolverName,
l2ResolverCoinType,
graphqlUrl,
uint8(0), // storage Type 0 => EVM
abi.encodePacked(address(target)), // storage location => l2 resolver address
abi.encodePacked(address(target)) // context => l2 resolver address
);
}
function id() public pure returns(bytes4){
makoto marked this conversation as resolved.
Show resolved Hide resolved
return type(IMetadataResolver).interfaceId;
}

function supportsInterface(
bytes4 interfaceId
) public override view returns (bool) {
return
interfaceId == type(IExtendedResolver).interfaceId ||
interfaceId == type(ITargetResolver).interfaceId ||
interfaceId == type(IMetadataResolver).interfaceId ||
super.supportsInterface(interfaceId);
}
}
15 changes: 12 additions & 3 deletions crosschain-resolver/deploy_l1/10_l1resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import {DeployFunction} from 'hardhat-deploy/types';

import {convertEVMChainIdToCoinType} from '@ensdomains/address-encoder'

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const {deployments, getNamedAccounts} = hre;
Expand All @@ -11,13 +11,22 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const VERIFIER_ADDRESS = process.env.VERIFIER_ADDRESS
const ENS_ADDRESS = process.env.ENS_ADDRESS
const WRAPPER_ADDRESS = process.env.WRAPPER_ADDRESS
const L2_GRAPHQL_URL = process.env.L2_GRAPHQL_URL
const L2_RESOLVER_NAME = process.env.L2_RESOLVER_NAME
const L2_CHAIN_ID = process.env.L2_CHAIN_ID

if(!VERIFIER_ADDRESS) throw ('Set $VERIFIER_ADDRESS')
if(!ENS_ADDRESS) throw ('Set $ENS_ADDRESS')
if(!WRAPPER_ADDRESS) throw ('Set $WRAPPER_ADDRESS')
console.log({VERIFIER_ADDRESS,ENS_ADDRESS, WRAPPER_ADDRESS})
if(!L2_GRAPHQL_URL) throw ('Set $L2_GRAPHQL_URL')
if(!L2_RESOLVER_NAME) throw ('Set $L2_RESOLVER_NAME')
if(!L2_CHAIN_ID) throw ('Set $L2_CHAIN_ID')

const L2_COINTYPE = convertEVMChainIdToCoinType(parseInt(L2_CHAIN_ID))
console.log({VERIFIER_ADDRESS,ENS_ADDRESS, WRAPPER_ADDRESS,L2_GRAPHQL_URL,L2_RESOLVER_NAME,L2_COINTYPE})
await deploy('L1Resolver', {
from: deployer,
args: [VERIFIER_ADDRESS,ENS_ADDRESS,WRAPPER_ADDRESS],
args: [VERIFIER_ADDRESS,ENS_ADDRESS,WRAPPER_ADDRESS,L2_GRAPHQL_URL,L2_RESOLVER_NAME,L2_COINTYPE],
log: true,
});
};
Expand Down
1 change: 1 addition & 0 deletions crosschain-resolver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"typescript": "^5.2.2"
},
"dependencies": {
"@ensdomains/address-encoder": "^0.2.22",
"@ensdomains/ens-contracts": "ensdomains/ens-contracts#feature/crosschain-resolver-with-reverse-registrar",
"@ensdomains/evm-verifier": "^0.1.0",
"@eth-optimism/contracts": "^0.6.0"
Expand Down
10 changes: 6 additions & 4 deletions crosschain-resolver/scripts/setupl1.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import hre from 'hardhat';
import packet from 'dns-packet';
const ethers = hre.ethers;
const abi = [
"function predictAddress(address) view returns (address)"
]
const encodeName = (name) => '0x' + packet.name.encode(name).toString('hex')

export const main = async () => {
const [signer] = await hre.ethers.getSigners();
Expand All @@ -13,8 +15,8 @@ export const main = async () => {
const L1_RESOLVER_ADDRESS = process.env.L1_RESOLVER_ADDRESS;
const ENS_NAME = process.env.ENS_NAME;
const ETH_ADDRESS = signer.address
const node = ethers.namehash(ENS_NAME);
console.log({L2_RESOLVER_FACTORY_ADDRESS, L1_RESOLVER_ADDRESS, ENS_NAME, node, ETH_ADDRESS})
const encodedname = encodeName(ENS_NAME);
console.log({L2_RESOLVER_FACTORY_ADDRESS, L1_RESOLVER_ADDRESS, ENS_NAME, encodedname, ETH_ADDRESS})


if (!process.env.L2_RESOLVER_FACTORY_ADDRESS || !process.env.L1_PROVIDER_URL || !process.env.L2_PROVIDER_URL || !process.env.ENS_NAME)
Expand All @@ -23,7 +25,7 @@ export const main = async () => {
const provider = new ethers.JsonRpcProvider(L1_PROVIDER_URL);
const currentResolver = await provider.getResolver(ENS_NAME)
if(currentResolver.address !== L1_RESOLVER_ADDRESS){
console.log({ENS_NAME, node, CURRENT_RESOLVER_ADDRESS:currentResolver.address, L1_RESOLVER_ADDRESS})
console.log({ENS_NAME, CURRENT_RESOLVER_ADDRESS:currentResolver.address, L1_RESOLVER_ADDRESS})
throw(`Set the resolver of the parent name to ${L1_RESOLVER_ADDRESS}`)
}else{
console.log(`The resolver of ${ENS_NAME} is set to ${L1_RESOLVER_ADDRESS}`)
Expand All @@ -35,7 +37,7 @@ export const main = async () => {
const l2resolverAddress = await l2Factory.predictAddress(ETH_ADDRESS)
console.log({l2resolverAddress})
const l1resolver = (await ethers.getContractFactory('L1Resolver', signer)).attach(L1_RESOLVER_ADDRESS);
const tx2 = await l1resolver.setTarget(node, l2resolverAddress)
const tx2 = await l1resolver.setTarget(encodedname, l2resolverAddress)

console.log(`Setting l2 resolver ${l2resolverAddress} as a target`, (await tx2.wait()).hash)
console.log(`Set export L2_RESOLVER_ADDRESS=${l2resolverAddress}`)
Expand Down
Loading
Loading