This repository contains a single contract, ChainResolver.sol.
This contract serves as the on-chain single source of truth for chain data discovery.
It is the implementation of the specifications outlined in ERC-7828, allowing for the resolution of an ERC-7930 Interoperable Address from an Interoperable Name of the form example.eth@optimism#1234.
It is fully compliant with ENS standards and best practices. ENSIP-10: Wildcard Resolution is utilised as the entry point for resolution of data.
The contract implements the Ownable ownership model by proxy of Open Zeppelin's OwnableUpgradeable module.
Only the owner of the contract can register chain data. The resolver will be owned by a multisig with the following signers:
- Josh Rudolf (EF)
- Thomas Clowes (Unruggable)
- OxOrca (Wonderland)
The ERC-7930 chain identifier is set for each chain by this owner. It is immutable once set.
During initialization, administrative control of additional data stored under the chain specific namespace is handed off to the chain operator. This allows for chain operators to set standard ENS data - addresses, a content hash, and text records.
-
The
ChainResolveris to be deployed behind an [ERC-1967] proxy to allow for it to be upgraded if neccesary. This path is secured by the multisig, with ultimate control falling to the ENS DAO who will be the underlying owner of theon.ethname. -
Under the hood, data is associated with the labelhash - the
keccak256hash of the chain label. The resolver is tied to a namespace defined on initialization. The namespace for ERC-7828 ison.eth. -
When originally designed there was discussion on appropriate namespace. The
ChainResolverwas designed to be agnostic to the underlying namespace. Given that some ENS event specifications emit the namehash (which is an algorithm using unidirectional hashing mechanisms -keccak256) we mapnodeToLabelhash. SeemigrateParentNamehash. -
There is an alias system to allow for commonly understood aliases to point to the same chain data. e.g,
arb1.on.ethwill point to the same underlying data asarbitrum.on.eth. -
There is an in-built discovery mechanism.
chainCount()exposes the number of chains in the registry, whilegetChainAtIndex(uint256)allows clients to iterate through them. This is provided as a utility - usage of this registry requires no external dependencies. -
Forward Resolution requires the resolution of the
interoperable-addressdata record (ENSIP-24) for the chain in question e.g.base.<namespace>.eth. The data returned is the ERC-7930 Interoperable Address. -
Reverse Resolution requires the resolution of a text record (ENSIP-5) on the
reverse.<namespace>.ethnode. The key to use is the ERC-7930 Interoperable Address you want to reverse, prefixed withchain-name:. For example,"chain-name:00010001010a00". The data returned is the human readable chain label.
The storage architecture within this contract has:
- all data records stored under one property,
dataRecords - all text records stored under one property,
textRecords
For contract simplicity, the immutability of the interoperable-address data key is handled in the publicly exposed setter, setData. This function does not allow the setting of this key.This function has the onlyChainOwner modifier.
The internal function _setData is called from the _register function to set this immutable key on registration. It has the onlyOwner modifier - only the multisig can register chains.
Similarly, the immutability of the chain-name: prefixed text keys are set on the reverse node (reverse.<namespace>.eth) as part of the registration flow. Ownership of the reverse node can not be set.
Checkout this repository, and install dependencies.
forge install foundry-rs/forge-std@v1.10.0
forge install OpenZeppelin/openzeppelin-contracts@v5.4.0
forge install OpenZeppelin/openzeppelin-contracts-upgradeable@v5.5.0
forge install ensdomains/ens-contracts@v1.6.0
git submodule add -b v4.9.3 https://github.com/OpenZeppelin/openzeppelin-contracts lib/openzeppelin-contracts-v4
bun installThe following interactive scripts are provided to allow for the deployment, initialization, and upgrading of the ChainResolver.
bun run deploy/DeployChainResolver.ts --chain=sepoliaThis command deploys the ChainResolver behind an ERC1967Proxy.
The script deploys the contract as an EOA, and transfers ownership to a predefined address (the multisig).
bun run deploy/RegisterChains.ts --chain=sepoliaThis command registers chains.
bun run deploy/DoUpgrade.ts --chain=sepoliaThis command deploys a new ChainResolver and upgrades the proxy referenced implementation.
This is for demonstration purposes. In practice, once ownership of the proxy has been transferred to the multsig all upgrades will need to be executed through it.
forge test -vvbun run test/ChainResolver.blocksmith.ts