- jefflau.eth
- taytems.eth
- premm.eth
- nick.eth
ENSIP-19: EVM-chain Reverse Resolution
Specifies a reverse resolution mechanism for EVM-chains.
Abstract
ENSIP-3 established a reverse resolution namespace, which allows the resolution from an address to a name. This ENSIP extends the initial namespace and creates one for each EVM-chain. These namespaces are utilised in a formally defined resolution process for a "primary name".
Motivation
Over years of development within the Ethereum ecosystem, EVM compatible sidechains and layer 2 chains (EVM-chains) have become the primary scaling solution. Support for these EVM-chains was initially added in ENSIP-9, which allowed arbitrary chain addresses to be resolved within ENS. Furthermore, ENSIP-11 more specifically recognised chains that inherit the same address encoding type as Ethereum.
However, the current implementation of reverse resolution assumes that any consumer (either a generic contract or an end-user) will have the same address across every EVM-chain. This has been falling further and further out of line with reality as smart contract accounts (SCAs) have continued to become more popular. While on most chains there is some way to deploy to the same address with enough forethought, some have a different address derivation scheme (i.e. ZKSync Era) which makes this impossible.
Given the constraints of the ecosystem, it is critical that reverse resolution be resolved via a namespace for each chain, rather than each Ethereum address.
Specification
Overview
This specification creates a chain-specific reverse resolution system with the following components:
-
Chain-Specific Reverse Registrars
- Each EVM-chain will have its own Reverse Registrar contract deployed
- These Registrars maintain a simple
address => name
mapping for users on that chain - They handle all authorization for name setting on their respective chains
- They operate independently of the ENS Registry on L1
- They replace functionality traditionally found in the ENS Registry or a Resolver because:
- They will not have access to the ENS registry (not deployed on Ethereum)
- They do not require resolver functionality outside of the
name
record - They require an easily derived storage slot on a consistent address to access data from L1
-
L1 Reverse Resolvers
- For each EVM-chain, a corresponding Reverse Resolver will be deployed on Ethereum (L1)
- These are accessible at
[coinTypeAsHex].reverse
and[userAddress].[coinTypeAsHex].reverse
- They use ENSIP-10 to fetch name data from the chain-specific Reverse Registrars
-
Fallback Mechanism
- A default Reverse Registrar will be deployed on Ethereum (L1) as the resolver for
default.reverse
- Chain-specific Reverse Resolvers will fallback to this default when no chain-specific name is set
- Users can set a default name as a fallback (not recommended for smart contract accounts)
- A default Reverse Registrar will be deployed on Ethereum (L1) as the resolver for
-
Name Resolution Process
- Users can set their reverse record (
name()
) on any EVM-chain - Clients can resolve a primary ENS name by querying
[userAddress].[coinTypeAsHex].reverse
- For a valid resolution, the user must also set the appropriate
addr()
record on their ENS name - This completes the two-way verification between address and name
- Users can set their reverse record (
-
Discovering Reverse Registrars
- Applications can discover the Reverse Registrar address on any EVM-chain by resolving
addr()
for[coinTypeAsHex].reverse
- The coinType is represented in hexadecimal format to keep names shorter
- Applications can discover the Reverse Registrar address on any EVM-chain by resolving
Deployment and discovery of EVM Reverse Resolvers
A valid EVM Reverse Resolver on Ethereum is defined as an offchain resolver that:
- resolves wildcard names in the format
[address].[coinTypeAsHex].reverse
for thename()
method.- ERC-3668 should be used to fetch and validate data from the Reverse Registrar on the EVM-chain.
- In the case that the resolved data is
null
, resolution should fallback to the resolver ofdefault.reverse
, where a default name can be resolved.
- resolves
addr([coinTypeAsHex].reverse, [coinType])
to the Reverse Registrar address on the EVM-chain.
For a valid EVM Reverse Resolver to be discoverable, and therefore a successful deployment, the resolver for the node [coinTypeAsHex].reverse
must point to it.
Client resolution process
Below is a step-by-step resolution process of ENS reverse resolution. Clients must adhere to these rules to be compliant with the reverse resolution process. This reverse resolution process serves to clarify and formalise a resolution process for the namespace defined in ENSIP-3, as well as the newly created ones part of this specification.
Let:
-
[address]
be the lowercase hexadecimal representation of an Ethereum address with prefix0x
removed. -
coinType
be the value derived using ENSIP-11 by ORing the chainId with0x80000000
. -
coinTypeAsHex
be the lowercase hexadecimal representation ofcoinType
, equivalent toBigInt(coinType).toString(16)
in JavaScript. -
encodeCall
be a generic method for ABI-encoding a function call. -
ensip10
be a an implementation of ENSIP-10, where theresolve
function takes an input ofname, callData
. -
L1 be Ethereum mainnet or testnet equivalent.
-
Registry be the ENS registry on Ethereum L1.
-
Resolver be the resolver of the Reverse node whether on L1 or another chain.
-
Primary Name be the forward-validated reference to the
name
record of a reverse node.
- Let
chainId
be the chain ID of the client. - If
chainId
is an L1 chain ID (including Ethereum testnets), setreverseName = "[address].addr.reverse"
andcoinType = 60
and go to step 5. - Otherwise, set
coinType
using ENSIP-11:coinType = 0x80000000 | chainId
. - Set
reverseName = '[address].[coinTypeAsHex].reverse'
- Set
reverseNode = namehash(reverseName)
. - Fetch the
name
from the resolver:name = ensip10.resolve(reverseName, encodeCall('name', [reverseNode]))
- If
name
is empty, no primary name exists for this account on this chain; halt and display the address instead. - Otherwise, a primary name may exist, but forward resolution MUST be checked for it to become one (i.e. a valid primary name).
- Set
node = namehash(name)
- Fetch the forward-resolved address from the resolver:
- If
coinType == 60
, with:resolvedAddress = ensip10.resolve(reverseName, encodeCall('addr', [node]))
- Otherwise, with:
resolvedAddress = ensip10.resolve(reverseName, encodeCall('addr', [node, coinType]))
- If
- If
resolvedAddress == address
,name
is now considered a valid Primary Name, and can be used within an application. - If
resolvedAddress != address
, there is no primary name, and thus the address MUST be used in place of one.
Note: A client MUST NOT fallback to using an L1 chainId for this process. If the result is empty it should be treated as such, and therefore be identical to an address with no primary name set.
Examples of valid EVM-chain reverse names
- Arbitrum: b8c2c29ee19d8307cb7255e1cd9cbde883a267d5.8000a4b1.reverse
- Optimism: b8c2c29ee19d8307cb7255e1cd9cbde883a267d5.8000000a.reverse
- Base: b8c2c29ee19d8307cb7255e1cd9cbde883a267d5.80002105.reverse
- Polygon ZKEVM: b8c2c29ee19d8307cb7255e1cd9cbde883a267d5.8000044d.reverse
- ZKSync Era: b8c2c29ee19d8307cb7255e1cd9cbde883a267d5.80000144.reverse
Deprecating avatars on reverse nodes
ENSIP-12 defined a way to store avatars on reverse nodes, which allowed accounts to have avatars without using 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. Given those factors, it should be considered deprecated, and support is not required for it within new EVM Reverse Resolvers.
Deprecating use of mainnet primary ENS name on other chains
ENS has not been explicit about how to use the mainnet addr()
record and it is often used as a backup to a user not having an EVM address record set. The mainnet reverse record has also historically been used on other EVM-chains due to no alternative on that specific chain. There are a few reasons why it would undesirable to encourage use of mainnet primary name and/or addr(node, 60)
record as a backup for it not being set on another EVM-chain.
An example of why this could be confusing:
Application is on Arbitrum and uses mainnet primary ENS name. It resolves the ENS name's mainnet address and uses that to verify the reverse record is correct. It also uses the mainnet address to allow in-app transfers.
Mainnet primary ENS name that resolves addr(node, 60)
to a smart contract account. The smart contract account is only on Ethereum and the user is unable to use CREATE2
to deploy the same smart contract wallet on Arbitrum. User 2 sees this Primary ENS name and wants to send funds to User 1. User 2 resolves the addr()
of the ENS name and sends the funds to an address that doesn't exist on Arbitrum and User 1 has no way to access the counterfactual address on that chain.
If we mandated that the address cannot use addr(node, 60)
, but only the address of the chain in question, it would be possible to use mainnet as a backup. However the fact remains that you would still need to claim and set your Primary ENS name on mainnet, and the possibility for confusion seems to outweigh the benefits of using mainnet (high gas) as a catch-all back up for other L2 EVM-chains (low gas). Additionally this would only be useful for EVM-compatible chains and would not benefit non-EVM L2s that have a different address format.
Copyright
Copyright and related rights waived via CC0.