ENSIP-19: Multichain Primary Names
Authors: jefflau.eth, taytems.eth, premm.eth, nick.eth, raffy.eth
Created: March 14, 2023
Status: draft
Abstract
This ENSIP standardizes reverse and primary name resolution for all coin types, and defines how this resolution process operates across the multichain Ethereum ecosystem.
Motivation
ENSIP-1 established the resolution of Ethereum addresses by name. ENSIP-9 introduced coin types and assigned the Ethereum address to a coin type. ENSIP-11 defined an algorithm to convert between chains and coin types.
ENSIP-3 established the reverse resolution process for Ethereum addresses. However, the generalization of this process for arbitrary coin types does not exist.
Since EVM-compatible chains have become the primary scaling solution for Ethereum, an Ethereum-wide default name is essential to ensure consistent identity resolution across all chains.
Additionally, because EVM-compatible chains have the same address encoding, chain-agonstic addresses—such as externally owned accounts (EoA) and deterministic deployment proxies—motivate an Ethereum-wide default address.
With the rise of smart contract accounts (SCA) and presence of different address derivation schemes, a modern ENS identity likely has multiple addresses accross the Ethereum ecosystem.
Specification
Primary name resolution is a two-phase procedure that takes addressBytes
and coinType
as input, and returns no name or a verified primary name.
Definitions
addressBytes
— the target address as bytes, according to ENSIP-9 § Address Encoding.[addressAsHex]
— prefix-free lowercase hexadecimal representation ofaddressBytes
.- eg.
0x0000ABcD
→"0000abcd"
- eg.
coinType
— the target coin type, according to ENSIP-9.coinType = 60
corresponds to the mainnet Ethereum address.- L1 testnets (like Sepolia) may also use this
coinType
.
- L1 testnets (like Sepolia) may also use this
coinType
can be derived from a 31-bit EVMchainId
, according to ENSIP-11.chainId = 0
corresponds to the default EVM chain.
[coinTypeAsHex]
— prefix-free lowercase hexadecimal representation ofcoinType
without leading zeros.- equivalent to
BigInt(coinType).toString(16)
in JavaScript. - eg.
4095
→"fff"
- equivalent to
chainFromCoinType(coinType)
- If
coinType = 60
, returns1
. - If
0x8000_0000 ≤ coinType ≤ 0xffff_ffff
, returnscoinType ^ 0x8000_0000
. - Otherwise, returns
0
.Network coinType
chainFromCoinType()
EVM Default 0x8000_0000
0
✓ Ethereum 60
1
✓ Chain(2) 0x8000_0002
2
✓ Bitcoin 0
0
? 0x1_8000_2105
0
- If
resolve(name, data)
— an ENSIP-10 implementation.
Algorithm
Reverse Resolution
- Generate
reverseName
withcoinType
where:coinType
reverseName
60
"[addressAsHex].addr.reverse"
0x8000_0000
"[addressAsHex].default.reverse"
*
"[addressAsHex].[coinTypeAsHex].reverse"
- Compute
reverseNode = namehash(reverseName)
. - Resolve
name = resolve(reverseName, abi.encodeCall(INameResolver.name, (reverseNode)))
. - If
name
is empty, no primary name exists for this address.- Stop and display the address.
name
is the primary name if and only if it resolves to the sameaddressBytes
.
Forward Resolution
- Compute
node = namehash(name)
. - Resolve
resolvedAddress = resolve(name, callData)
where:coinType
callData
60
abi.encodeCall(IAddrResolver.addr, (node))
*
abi.encodeCall(IAddressResolver.addr, (node, coinType))
- If
resolvedAddress != addressBytes
, no primary name exists for this address.- Stop and display the address.
name
is the primary name.
Multichain Ethereum
A new standalone registrar contract will maintain an address
→ name
mapping and grant accounts of the host chain the ability to manage their name
via various trustless mechanisms.
Unlike reverse registrations in ENSIP-3, the new registrar is registry-independent and does not support custom resolvers or records.
Resolving addr(node, coinType)
on a reverse namespace will return the address of the corresponding registrar.
Default Primary Name
A new registrar contract will be deployed on L1 for default names. An ENSIP-10 wildcard resolver registered at "reverse"
will utilize the default registrar. The default resolver will intercept "default.reverse"
and "[coinTypeAsHex].reverse"
for every chainFromCoinType(coinType) > 0
and lookup names when addressAsHex
is a valid EVM address.
Chain-specific Primary Name
New registrars will be deployed per chain, but only those that post state to L1 (such as rollups) may have a corresponding ENSIP-10 wildcard resolver at "[coinTypeAsHex].reverse"
.
Each resolver will trustlessly verify registrar lookups on the corresponding chain when addressAsHex
is a valid EVM address. If no name is assocated with the address, the resolver will return the default name from the default registrar.
Example
The resolver for
chainId = 2
is registered at"80000002.reverse"
.The primary name of
0xb8c2C29ee19D8307cb7255e1Cd9CbDE883A267d5
on this chain corresponds to resolving thename()
of"b8c2c29ee19d8307cb7255e1cd9cbde883a267d5.80000002.reverse"
.If this chain was not a rollup, the reverse name would be intercepted by the default resolver, and the primary name becomes the default name.
Default Address
Similar to ENSIP-9 § Backwards Compatibility which states:
the value returned by
addr(node)
from ENSIP-1 should always match the value returnedaddr(node, 60)
If chainFromCoinType(coinType) > 0
, the value returned by addr(node, coinType)
, when no address is stored for coinType
, should always match the value returned by addr(node, 0x8000_0000)
.
Backwards Compatibility
This specification requires no modification to ENSIP-10 resolution.
Unlike the new registrar defined above, the ENSIP-3 registrar assigned a resolver to "[addressAsHex].addr.reverse"
. To clear this registration, the reverse resolver must be replaced with a default-aware resolver or the resolver must be unset. An unaware resolver with an unset name will not fallback to the default name.
Most resolvers do not implement the default address logic and will need redeployed. Alternatively, the same address can be set for all relevant coin types to replicate the default behavior.
Deprecating Reverse Name Avatars
ENSIP-12 defined avatars for reverse names, which allowed accounts to have avatars without an ENS name. Adoption of this is virtually non-existent, and ENS names are more accessible than ever before (free), which effectively removes the need for it entirely.
The reverse resolvers defined in this specification do not support text()
.
Deprecating Mainnet as Default
ENS has not been explicit about how to use the mainnet address record addr()
and it is often used as a default when a chain address is not present. Additionally, mainnet primary names have historically been used on other chains as there was no alternative.
Clients must remove all logic related to default address and name handling.
Example
User A on chain C wants to transfer assets to user B, who operates a SCA on L1.
- User A enters the mainnet address of user B.
- The application verifies and displays the mainnet primary name of user B.
- User A confidently executes the transfer on chain C.
Due to the specifics of SCA creation, user B likely has no ability to claim the matching counterfactual address on chain C, and the assets are unrecoverable.
Copyright
Copyright and related rights waived via CC0.
Annex: Supported Chains
Mainnet
Network | chainId | reverseNamespace |
---|---|---|
Default | 0 | "default.reverse" |
Ethereum | 1 | "addr.reverse" |
Optimism | 10 | "8000000a.reverse" |
Base | 8453 | "80002105.reverse" |
Arbitrum | 42161 | "8000a4b1.reverse" |
Linea | 59144 | "8000e708.reverse" |
Scroll | 534352 | "80082750.reverse" |
Sepolia
Network | chainId | reverseNamespace |
---|---|---|
Default | 0 | "default.reverse" |
Ethereum | 1 | "addr.reverse" |
Linea | 59141 | "8000e705.reverse" |
Base | 84532 | "80014a34.reverse" |
Arbitrum | 421614 | "80066eee.reverse" |
Scroll | 534351 | "8008274f.reverse" |
Optimism | 11155420 | "80aa37dc.reverse" |