This ERC proposes to derive chain identifiers as a digest of their chain name (and other information) and to use ENS to map chain names to identifiers in place of the centralized list on GitHub. A solution to support existing chain identifiers that were not derived following this ERC is also proposed.
The mapping between chain names and identifiers, such as Mainnet -> 0x1
, is currently maintained in a centralized list.
However this solution has two main shortcomings:
- It does not scale with the growing number of L2s.
- The list maintainers are a single point of failure.
Desired properties: - the ability to register new chain names and identifiers in a censorship-resistant way - the ability to resolve chain names and identifiers in a trustless way - maintain a unique mapping between names and identifiers
An important property of the centralized list is that it keeps a one-to-one correspondence between names and identifiers.
Without this property, an attacker could register a fresh name pointing to an existing identifier. For example my-testnet
could point to mainnet 0x1
. A user could be tricked into signing a transaction for the innocent looking my-testnet
while actually signing a transaction for mainnet, a transaction that the attacker can then replay.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Current chain identifiers are usually chosen arbitrarily to be short. While these identifiers are convenient on a small scale, as their number increases it is more desirable to draw them from a larger space.
We propose to extend the size of identifiers to 32 bytes and to derive them using a cryptographic hash function. The input to the function MUST contain the chain name and MAY contain additional information.
An example for a L2:
chain_id = Keccak-256(CHAIN_NAME, SETTLEMENT_CHAIN_ID, VERSION, DEPLOYER_CONTRACT_ADDRESS, SALT)
where:
- SETTLEMENT_CHAIN_ID
is the id of the L1 where the L2 settles, it could be Mainnet or a testnet.
- VERSION
is to separate the domain of the hash function with an arbitrary string
- DEPLOYER_CONTRACT_ADDRESS
is the address of the L2 on the L1
Any ENS name can resolve to a chain identifier as specified in ERC-2304. The name should resolve to a record containing not only the chain identifier, but also all the optional information necessary to verify the identifier.
For example the chain name rollup
can be converted to a chain identifier on Mainnet by resolving:
rollup.eth -> {version : uint, bridge : address, chain_id : chain_id}
and then verified using:
chain_id == hash("rollup", 0x1, version, bridge)
TBD
Existing identifiers, that were not derived using the scheme above, can be supported using a reverse mapping from chain identifiers to chain names, so that one can check for uniqueness.
For example the chain name legacy-rollup.eth
can be resolved to the chain identifier 0x123
.
Then 0x123
can be resolved in the chainid.reverse
domain to a chain_name
.
If chain_name == legacy-rollup
then the mapping is valid.
In order to bootstrap the handling of legacy chain identifiers, we imagine the EF populating the chainid.reverse
domain, a temporary l2.eth
for names and then handing them over.
l2.eth
and chainid.reverse
using Ethereum lists.rollup.eth
and points it to their `chain_id.rollup.l2.eth
and chain_id.chainid.reverse
chain_id.chainid.reverse
to return rollup.eth
Domain spoofing can lead to replay attacks as described above and can be eliminated by deriving new identifiers using a hash function and by checking the reverse mapping for legacy identifiers.
Domain squatting, the practice of ammassing a large number of domains in the hope to selling them later to legitimate users, is a possibility but with an increasing number of L2 registrations we can expect the same problem to appear in the centralized Github list.
Copyright and related rights waived via CC0.