Skip to content
Open
Show file tree
Hide file tree
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
110 changes: 59 additions & 51 deletions ensips/11.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
---

Check failure on line 1 in ensips/11.md

View workflow job for this annotation

GitHub Actions / install

Unable to load file
description: Introduces coinType for EVM compatible chains (amending ENSIP9).
contributors:
- matoken.eth
- Teddy (@0xteddybear)
- Joxes (@0xJoxess)
- Skeletor Spaceman (@skeletor-spaceman)
- Racu (@0xRacoon)
- TiTi (@0xtiti)
- Gori (@0xGorilla)
- Ardy (@0xArdy)
- Onizuka (@onizuka-wl)
ensip:
status: draft
created: 2022-01-13
requires: ERC-7930, CAIP-350
---

# ENSIP-11: EVM compatible Chain Address Resolution
Expand All @@ -13,70 +22,36 @@

## Abstract

This ENSIP extends [ENSIP 9 (multichain address resolution)](./9), dedicates a range of coin types for EVM compatible chains, and specifies a way to derive EVM chain IDs to the designated coin types.

The dedicated range uses over 0x80000000 (2147483648) which is reserved under ENSIP 9 so there will be no possibility of coin type collision with other non EVM coin types to be added in future. However, some of coin types previously allocated to EVM chain ids will be deprecated.
This ENSIP extends [ENSIP 9 (multichain address resolution)](./9), deprecating separate addresses and coin types in favor of [ERC-7930] Interoperable Addresses.

## Motivation

The existing ENSIP 9 relies on the existence of coin types on [SLIP44](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) which was designed to define address encoding type for deterministic wallets. As the majority of EVM compatible chains inherit the same encoding type as Ethereum, it is redundant to keep requesting the addition of EVM compatible chains into SLIP 44. This specification standardises a way to derive coinType based on [Chain ID](https://chainlist.org).
The existing ENSIP 9 relies on the existence of coin types on [SLIP44](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) which was designed to define address encoding type for deterministic wallets. As the majority of EVM compatible chains inherit the same encoding type as Ethereum, it is redundant to keep requesting the addition of EVM compatible chains into SLIP 44. This specification integrates ENS with Interoperable Addresses as defined in [ERC-7930], which are a single payload including both the address and the chain on which that address belongs.

## Specification

This specification amends ENSIP 9 to specify that coin types with the most-significant bit set are to be treated as EVM chain IDs. The MSB is reserved in SLIP44 for other purposes relating to HD wallet key derivation, so no coin types exist in this range.

To compute the new coin type for EVM chains, bitwise-OR the chain ID with `0x80000000`: `0x80000000 | chainId`.

```typescript
export const convertEVMChainIdToCoinType = (chainId: number) =>{
return (0x80000000 | chainId) >>> 0
}
```

And to reverse the operation, bitwise-AND the coinType with `0x7fffffff`: `0x7fffffff & coinType`.
This specification amends ENSIP 9 to allow resolvers to use a `bytes` parameter, which should be an Interoperable Address containing only a chain specification, and returns an Interoperable Address containing only an address
<!-- TODO: it could be a complete Interoperable Address, costing a bit more gas -->

```typescript
export const convertCoinTypeToEVMChainId = (coinType: number) =>{
return (0x7fffffff & coinType) >> 0
}
```solidity
function addr(bytes32 node, bytes memory chain) external view returns (bytes memory address_)
```

### Implementation

An implementation of this interface is provided in the [ensdomains/address-encoder](https://github.com/ensdomains/address-encoder/) repository.
Where:
- `bytes32 node` is the namehash of the name to be resolved, as defined in ENSIP-1.
- `bytes memory chain` is a v1-compatible Interoperable Addresses describing the chain on which the address returned will live. Its `address` field must be empty.
- `bytes memory address_` is a v1-compatible Interoperable Addresses describing the resulting address. Its `ChainReference` field must be empty.

### Example

To compute the new coin type for EVM chains, call `convertEVMChainIdToCoinType(chainId)`
To query the address of `vitalik.eth` on OP Mainnet

```javascript
const encoder = require('@ensdomains/address-encoder')
> encoder.convertEVMChainIdToCoinType(61)
2147483709
> encoder.convertCoinTypeToEVMChainId(2147483709)
61
```
- `node`: `namehash(vitalik.eth) == 0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835`
- `chain`: `0x00010000010A` (version 1, chain namespace `0000 == eip155`, `ChainReferenceLength == 1`, `ChainReference == 10`)

You can also use existing functions formatsByName and formatsByCoinType to derive these chain IDs

```javascript
> encoder.formatsByName['XDAI']
{
coinType: 2147483748,
decoder: [Function (anonymous)],
encoder: [Function (anonymous)],
name: 'XDAI'
}
> encoder.formatsByCoinType[2147483748]
{
coinType: 2147483748,
decoder: [Function (anonymous)],
encoder: [Function (anonymous)],
name: 'XDAI'
}
```
### Backwards Compatibility

### Exceptions
#### Exceptions

The following EVM chains are the exception to this standard.

Expand All @@ -85,9 +60,9 @@

They will continue using coinType defined at SLIP44

### Backwards Compatibility
#### ENSIP-9

The following EVM compatible cointypes existed before introducing this new standard.
The following EVM compatible cointypes existed before introducing any versions of this standard.

* NRG
* POA
Expand All @@ -104,6 +79,39 @@

When you display them for backward compatibility purposes, append `_LEGACY` to the cointype and make them read only.

If defined, the CAIP-350 profile of a chain's address serialization scheme takes precedence over the one defined in ENSIP-9

#### Previous versions of this same standard
Resolution of pre-existing `uint256 coinType`s can be supported since there's a clear bijectivity with chains as defined in ERC-7930.

`type(uint32).max / 2 < coinType <= type(uint32).max`
: remove up to three bytes, starting from the most significative, if they are zero and produce an `eip155` Interoperable Address with that as the chain reference.

`coinType > type(uint32).max`
: Error case, not supported by previous versions of ENSIP-11 or ENSIP-9.

`0 coinType <= type(uint32).max / 2`
: use an internal lookup table to convert existing supported `coinType`s to the appropiate Interoperable Address
<!-- alternative: proceed with legacy ENSIP-9 resolution -->

<!-- TODO: define precedence of writing and reading legacy cointypes vs those defined in this standard. Ideally:
- if ENSIP-9 is already defined, that value should be read
- it's an error to define a non-zero ENSIP-9 style name
- if ENSIP-9 is already defined, it's an error to write an equivalent ENSIP-11
-->

## Rationale
- Backwards-compatibility of this standard can easily be defined in code, needing no manual migrations by users.
- Using an arbitrary-length `bytes` allows for future compatibility with chainids longer than 32 bits (e.g. in the case the output from a hash function is used, as proposed by ERC-7785) and with chains on CASA namespaces other than `eip155`.
- Leaning on CAIP-350 and ERC-7930 for the serialization details of every chain's addresses allows this standard to stay lean and don't define all the possible chain formats it may possibly support.

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).

<!-- TODO: link to spec permalink once it's an official draft -->
[ERC-7930]: https://github.com/ethereum/ERCs/pull/1002
<!-- TODO: link to spec permalink once it's an official draft -->
[CAIP-350]: https://github.com/ChainAgnostic/CAIPs/blob/892cbe8525028469f31dc4b1eb201fe5419194bb/CAIPs/caip-350.md
[ENSIP-9]: ./9
[ENSIP-1]: ./1
54 changes: 34 additions & 20 deletions ensips/19.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@
description: Specifies reverse resolution in a cross-chain context
contributors:
- jefflau.eth
- Teddy (@0xteddybear)
- Joxes (@0xJoxess)
- Skeletor Spaceman (@skeletor-spaceman)
- Racu (@0xRacoon)
- TiTi (@0xtiti)
- Gori (@0xGorilla)
- Ardy (@0xArdy)
- Onizuka (@onizuka-wl)
ensip:
status: draft
created: 2023-03-14
requires: CAIP-350, ERC-7930
---

# ENSIP-19: EVM-chain Reverse Resolution
Expand All @@ -15,38 +24,36 @@ This ENSIP specifies a way for reverse resolution to be used on other EVM chains

## 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.
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 cross-chain reverse resolution to also exist.

## 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 registrar will only allow setting the name and text record without resolver customizability.
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)
* Their ENS name will need to set their record for the appropiate network, the format for which is specified in [CAIP-350].
* A dapp can then detect the chainID that a user is on, convert that into an unambiguous chain specification via [CAIP-350] and resolve their primary ENS name by resolving the name record at `<userAddress>.<chainSpec>.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 a sidechain or a L2 that has state roots on L1, verification can be done with trusted signatures or trustlessly on Ethereum mainnet, respectively.
* 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
* Discovery of the reverse registrar on each chain will be done by looking up the `addr()` of `<chainSpec>.reverse`.
* `<chainSpec>` in all instances will be the `chain` part of an [ERC-7930]'s Interoperable Name.

### Deployment and discovery of EVM Reverse registrars

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.
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 `<chainSpec>.reverse`. It must then be setup with an offchain resolver that has an onchain L1 address record returning 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>.<chainSpec>.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.

### Resolving Primary ENS Names by a dapp

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.

#### Glossary of terms

* `[address]` is the lowercase hexadecimal representation of an Ethereum address with prefix `0x` removed.
* `<address>` is the `address` part of an Interoperable Name as defined by [CAIP-350].

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

* `coinTypeAsHex` is the cointype converted to hexadecimal.
* `<chainSpec>` is the `chain` part of an Interoperable Name as defined by [CAIP-350].

* Registry refers to the ENS registry on Ethereum L1

Expand All @@ -57,24 +64,25 @@ Below is a step-by-step resolution process of ENS reverse resolution. A dapp mus
#### Primary Name Resolution process

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'`
2) If `chainId` is 1, set `reverseName = "<address>.addr.reverse"` and `coinType = 60` and go to step 5.
3) Otherwise, set `chainSpec` as an Interoperable Name's `chain` attribute, as described in [CAIP-350]
4) Set `reverseName = '<address>.<chainSpec>.reverse`, expressing `<address>` in the format described by [CAIP-350].
5) Set `node = namehash(reverseName)`.
6) Fetch the resolver for the reverse name: `resolver = registry.resolver(node)`
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.
9) If `name` is an empty string, and `coinType` is not 0, set `reverseName = '<address>.default.reverse'` 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.
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, bytes chain)`, with `chain` being an Interoperable Address containing the description of `chainid` and no address. 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.
> ![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.

### Resolving an avatar by a dapp on another EVM chain

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.
ENSIP-12 was conceived 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.

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

Expand All @@ -93,6 +101,7 @@ To determine the avatar URI for a specific EVM chain address, the client can fol

### Deprecating use of mainnet primary ENS name on other chains

<!-- TODO: not sure what to do about this section, I believe it should stay as-is, but I might also be missing a similar consideration on ENSIP-11 -->
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.

An example of why this could be confusing:
Expand All @@ -106,3 +115,8 @@ If we mandated that the address cannot use `addr(node, 60)`, but only the addres
## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).

<!-- TODO: link to spec permalink once it's an official draft -->
[ERC-7930]: https://github.com/ethereum/ERCs/pull/1002
<!-- TODO: link to spec permalink once it's an official draft -->
[CAIP-350]: https://github.com/ChainAgnostic/CAIPs/pull/350
Loading