Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

edit: EVM-chain reverse resolution #13

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 70 additions & 56 deletions ensips/19.md
Original file line number Diff line number Diff line change
@@ -1,107 +1,121 @@
---
description: Specifies reverse resolution in a cross-chain context
description: Specifies a reverse resolution mechanism for EVM-chains.
contributors:
- jefflau.eth
- taytems.eth
- premm.eth
- nick.eth
ensip:
status: draft
created: 2023-03-14
---

# ENSIP-19: EVM-chain Reverse Resolution

Specifies a reverse resolution mechanism for EVM-chains.

## Abstract

This ENSIP specifies a way for reverse resolution to be used on other EVM chains. This allows setting primary names on L2s, as well as resolving any other records set on this specific reverse record, such as the avatar.
ENSIP-3 establishes 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

Reverse resolution has been in use since ENS's inception, however at the time Ethereum had no concrete scaling plans. In the past 5 years, we've seen layer 2s and sidechains become more prevalent and we first allowed support for these with ENSIP-9 (formerly EIP-2304) to allow addresses from other chains to be stored on ENS. To complete support for other EVM chains, reverse resolution needs to be expanded to allow reverse resolution to also exist.
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](https://docs.ens.domains/ensip/9), which allowed arbitrary chain addresses to be resolved within ENS. Furthermore, [ENSIP-11](https://docs.ens.domains/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

* Reverse registrars will be setup on each EVM-chain, with a corresponding registry
* Reverse registrar will only allow setting the name and text record without resolver customisability.
- Reverse Registries will be setup on each EVM-chain, with combined registry/registrar/resolver functionality.
- Registries will only allow setting the name, without resolver customisability.
This is to allow a consistent storage slot that can be checked on L1.
* User can now claim their reverse on this chain and set it to their ENS name
* Their ENS name will need to set their record for the same EVM-cointype as the network, which is specified in [ENSIP-11](https://docs.ens.domains/ensip/11).
* A dapp can then detect the chainID that a user is on, convert that into coinType in hexadecimal and resolve their primary ens name by resolving the name record at [userAddress].[coinTypeAsHex].reverse. This will be resolved via a CCIP-read gateway and look up the reverse record on the corresponding EVM-chain. Depending on if the chain is an L2 that has state roots on L1 or sidechain, verification can be done with trusted signatures or trustlessly on Ethereum mainnet.
* Dapps will then resolve this name via ENS on L1 to check if the forward resolution matches. This forward resolution can be on L1, or the user can set up a CCIP-read resolver and records for each network and put those addresses wherever they want (such as on another L2)
* Once matched, the dapp can then also resolve any text records on the primary ENS name, such as avatar.
* Discovery of the reverse registrar on each chain will be done by looking up the `addr()` of [coinTypeAsHex].reverse.
* coinType in all instances will be the hex representation to reduce the length of the name
- A Reverse Resolver will be deployed on L1 for each corresponding EVM-chain Reverse Registry.
- A Reverse Registry will be deployed as the resolver for `default.reverse`. Each Reverse Resolver will internally fallback to this default namespace in the case that the chain-specific data is `null`.
- Users will have the ability to set the `name()` record
- The corresponding ENS name will need to have its record set for the chain's EVM cointype (see [ENSIP-11](https://docs.ens.domains/ensip/11)) to match the user's address.
- EOA Users will also have the ability to set a default `name()` record value (i.e. fallback), used if no value for a specified coin type was available.
- Clients will be able to resolve a primary ENS name for any given chain ID by resolving the `name()` record for `[userAddress].[coinTypeAsHex].reverse`. Based on this result, clients will then need to resolve the `addr()` record with the corresponding chain ID for the resulting ENS name to verify the resolution result.
- Discovery of the Reverse Registry on each chain will be done by resolving `addr()` for `[coinTypeAsHex].reverse`.
- coinType in all instances will be the hex representation to reduce the length of the name

### Deployment and discovery of EVM Reverse Resolvers

A valid EVM Reverse Resolver on Ethereum is defined as an offchain resolver that:

1. resolves wildcard names in the format `[address].[coinTypeAsHex].reverse` for the `name()` method.
1. ERC-3668 should be used to fetch and validate data from the Reverse Registry on the EVM-chain.
2. In the case that the resolved data is `null`, resolution should fallback to the resolver of `default.reverse`, where a default name can be resolved.
2. resolves `addr([coinTypeAsHex].reverse, [coinType])` to the Reverse Registry address on the EVM-chain.

### Deployment and discovery of EVM Reverse registrars
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.

When a new EVM reverse registrar is deployed, it will need to be setup by the owner of the `reverse` node, to setup a subdomain [coinTypeAsHex].reverse. It must then be setup with an Offchain resolver that has an onchain L1 address record that return the contract address of the reverse registrar for that chain. The Offchain resolver will also support wildcard of all the address subdomains with the format [address].[coinTypeAsHex].reverse. Additionally there must be a new EVM gateway setup to handle the CCIP-read revert errors that will go to the corresponding network to gather the chain-specific reverse record and verify this data on L1.
### Client resolution process

### Resolving Primary ENS Names by a dapp
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.

Below is a step-by-step resolution process of ENS reverse resolution. A dapp must adhere to these rules to be compliant with the reverse resolution process. This reverse resolution process adds on to ENSIP-3's original reverse resolution process and will act as a replacement for applications that support Primary ENS names on multiple chains.
Let:

#### Glossary of terms
- `[address]` be the lowercase hexadecimal representation of an Ethereum address with prefix `0x` removed.

* `[address]` is the lowercase hexadecimal representation of an Ethereum address with prefix `0x` removed.
- `coinType` be the value derived using [ENSIP-11](https://docs.ens.domains/ensip/11) by ORing the chainId with `0x80000000`.

* `coinType` for chain ids is derived using [ENSIP-11](https://docs.ens.domains/ensip/11) by ORing the chainId with `0x80000000`
- `coinTypeAsHex` be the lowercase hexadecimal representation of `coinType`.

* `coinTypeAsHex` is the cointype converted to hexadecimal.
- `encodeCall` be a generic method for ABI-encoding a function call.

* Registry refers to the ENS registry on Ethereum L1
- `ensip10` be a an implementation of [ENSIP-10](https://docs.ens.domains/ensip/10), where the `resolve` function takes an input of `name, callData`.

* Resolver refers to the resolver of the Reverse node whether on L1 or another chain
- L1 be Ethereum mainnet or testnet equivalent.

* Primary Name is the common name use for the reverse node's record `name`
- Registry be the ENS registry on Ethereum L1.

#### Primary Name Resolution process
- Resolver be the resolver of the Reverse node whether on L1 or another chain.

1) Let `chainId` be the chain ID of the DApp's currently connected chain.
2) If `chainId` is 1, set `reverseName = "[address].addr.reverse" and `coinType = 60` and go to step 5.
3) Otherwise, set `coinType` using ENSIP-11: `coinType = 0x80000000 | chainId`.
4) Set `reverseName = '[address].[coinTypeAsHex].reverse'`
5) Set `node = namehash(reverseName)`.
6) Fetch the resolver for the reverse name: `resolver = registry.resolver(node)`
7) Fetch the primary name from the reverse record's resolver: `name = resolver.name(node)`
8) If the primary name is not the empty string, go to step 11.
9) If `name` is an empty string, and `coinType` is not 0, set `reverseName = '[address].default.reverse'` and `coinType = 0` and go to step 5.
10) Otherwise, no primary name exists for this account on this chain; halt and display the address instead.
11) If the dapp finds an ENS name, it MUST then check the forward resolution. This can be done by using the resolution processs in [ENSIP-10](https://docs.ens.domains/ensip/10). When constructing the ENSIP-10 `resolve()` calldata, encode a call to `addr(bytes32 node, uint256 coinType)`. Set `resolvedAddress` to the result of calling `resolve` on the resolver with this calldata.
12) If `resolvedAddress == address`, the dapp considers the Primary Name valid, and can now show this instead of the address within the application.
13) If `resolvedAddress != address` the dapp considers the Primary Name invalid and MUST show the address instead.

Note: The dapp MUST NOT use the reverse record set for Ethereum mainnet ([address].addr.reverse) even if the Primary ENS name has not been set on the target chain, and must treat this identically to an address with no primary name set.
- Primary Name be the forward-validated reference to the `name` record of a reverse node.

### Resolving an avatar by a dapp on another EVM chain
1. Let `chainId` be the chain ID of the client.
2. If `chainId` is an L1 chain ID, set `reverseName = "[address].addr.reverse"` and `coinType = 60` and go to step 5.
3. Otherwise, set `coinType` using ENSIP-11: `coinType = 0x80000000 | chainId`.
4. Set `reverseName = '[address].[coinTypeAsHex].reverse'`
5. Set `reverseNode = namehash(reverseName)`.
6. Fetch the `name` from the resolver: `name = ensip10.resolve(reverseName, encodeCall('name', [reverseNode]))`
7. If `name` is empty, no primary name exists for this account on this chain; halt and display the address instead.
8. Otherwise, a primary name may exist, but forward resolution MUST be checked for it to become one (i.e. a valid primary name).
9. Set `node = namehash(name)`
10. Fetch the forward-resolved address from the resolver: `resolvedAddress = ensip10.resolve(reverseName, encodeCall('addr', [node, coinType]))`
11. If `resolvedAddress == address`, `name` is now considered a valid Primary Name, and can be used within an application.
12. If `resolvedAddress != address`, there is no primary name, and thus the address MUST be used in place of one.

ENSIP-12 was concieved before the ENS L2 reverse resolution specification and therefore should be updated to reflect the current state of ENS primary name resolution. This means that all avatar records are able to be updated on a per-chain basis by updating the avatar record on their reverse node.
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.

To determine the avatar URI for a specific EVM chain address, the client can follow the resolution process above until step 6) And then do the following
### Examples of valid EVM-chain reverse names

1. Perform [Ethereum address avatar text record resolution](https://docs.ens.domains/ensip/12#ethereum-address) on the reverse node.
2. If none is found, proceed to step 7) in the [Primary name resolution process](#primary-name-resolution-process) above, if no primary name is found, consider the avatar resolution a failure.
3. Perform [ENS name avatar text record resolution](https://docs.ens.domains/ensip/12#ens-name) on the ENS name.
- Arbitrum: 0f32b753afc8abad9ca6fe589f707755f4df2353.8000a4b1.reverse
- Optimism:
0f32b753afc8abad9ca6fe589f707755f4df2353.8000000a.reverse
- Base: 0f32b753afc8abad9ca6fe589f707755f4df2353.80002105.reverse
- Polygon ZKEVM: 0f32b753afc8abad9ca6fe589f707755f4df2353.8000044d.reverse
- ZKSync Era: 0f32b753afc8abad9ca6fe589f707755f4df2353.80000144.reverse

### Examples of valid L2 reverse resolution
### Deprecating avatars on reverse nodes

* Arbitrum: 0f32b753afc8abad9ca6fe589f707755f4df2353.8000A4B1.reverse
* Optimism:
0f32b753afc8abad9ca6fe589f707755f4df2353.8000000A.reverse
* Base: 0f32b753afc8abad9ca6fe589f707755f4df2353.80002105.reverse
* Polygon ZKEVM: 0f32b753afc8abad9ca6fe589f707755f4df2353.8000044D.reverse
* ZKSync Era: 0f32b753afc8abad9ca6fe589f707755f4df2353.80000144.reverse
[ENSIP-12](https://docs.ens.domains/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 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.
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:

Dapp 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.
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 has an `addr(node, 60)` that is a smart contract wallet. The smart contract wallet 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.
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 seem 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.
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

Expand Down
Loading