Skip to content

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 of addressBytes.
    • eg. 0x0000ABcD"0000abcd"
  • 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.
    • coinType can be derived from a 31-bit EVM chainId, according to ENSIP-11.
      • chainId = 0 corresponds to the default EVM chain.
  • [coinTypeAsHex] — prefix-free lowercase hexadecimal representation of coinType without leading zeros.
    • equivalent to BigInt(coinType).toString(16) in JavaScript.
    • eg. 4095"fff"
  • chainFromCoinType(coinType)
    • If coinType = 60, returns 1.
    • If 0x8000_0000 ≤ coinType ≤ 0xffff_ffff, returns coinType ^ 0x8000_0000.
    • Otherwise, returns 0.
      NetworkcoinTypechainFromCoinType()EVM
      Default0x8000_00000
      Ethereum601
      Chain(2)0x8000_00022
      Bitcoin00
      ?0x1_8000_21050
  • resolve(name, data) — an ENSIP-10 implementation.

Algorithm

Reverse Resolution

  1. Generate reverseName with coinType where:
    coinTypereverseName
    60"[addressAsHex].addr.reverse"
    0x8000_0000"[addressAsHex].default.reverse"
    *"[addressAsHex].[coinTypeAsHex].reverse"
  2. Compute reverseNode = namehash(reverseName).
  3. Resolve name = resolve(reverseName, abi.encodeCall(INameResolver.name, (reverseNode))).
  4. If name is empty, no primary name exists for this address.
    • Stop and display the address.
  5. name is the primary name if and only if it resolves to the same addressBytes.

Forward Resolution

  1. Compute node = namehash(name).
  2. Resolve resolvedAddress = resolve(name, callData) where:
    coinTypecallData
    60abi.encodeCall(IAddrResolver.addr, (node))
    *abi.encodeCall(IAddressResolver.addr, (node, coinType))
  3. If resolvedAddress != addressBytes, no primary name exists for this address.
    • Stop and display the address.
  4. name is the primary name.

Multichain Ethereum

A new standalone registrar contract will maintain an addressname 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 the name() 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 returned addr(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.

  1. User A enters the mainnet address of user B.
  2. The application verifies and displays the mainnet primary name of user B.
  3. 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

NetworkchainIdreverseNamespace
Default0"default.reverse"
Ethereum1"addr.reverse"
Optimism10"8000000a.reverse"
Base8453"80002105.reverse"
Arbitrum42161"8000a4b1.reverse"
Linea59144"8000e708.reverse"
Scroll534352"80082750.reverse"

Sepolia

NetworkchainIdreverseNamespace
Default0"default.reverse"
Ethereum1"addr.reverse"
Linea59141"8000e705.reverse"
Base84532"80014a34.reverse"
Arbitrum421614"80066eee.reverse"
Scroll534351"8008274f.reverse"
Optimism11155420"80aa37dc.reverse"