forked from DecentralizedClimateFoundation/DCIPs
127 lines
9.6 KiB
Markdown
127 lines
9.6 KiB
Markdown
---
|
|
eip: 2544
|
|
title: ENS Wildcard Resolution
|
|
description: Adds support for "wildcard" resolution of subdomains in ENS.
|
|
author: Nick Johnson (@arachnid), 0age (@0age)
|
|
discussions-to: https://ethereum-magicians.org/t/eip-2544-ens-wildcard-resolution
|
|
status: Stagnant
|
|
type: Standards Track
|
|
category: ERC
|
|
created: 2020-02-28
|
|
requires: 137
|
|
---
|
|
|
|
## Abstract
|
|
|
|
The Ethereum Name Service Specification (EIP-137) establishes a two-step name resolution process. First, an ENS client performs the namehash algorithm on the name to determine the associated "node", and supplies that node to the ENS Registry contract to determine the resolver. Then, if a resolver has been set on the Registry, the client supplies that same node to the resolver contract, which will return the associated address or other record.
|
|
|
|
As currently specified, this process terminates if a resolver is not set on the ENS Registry for a given node. This EIP changes the name resolution process by adding an additional step if a resolver is not set for a domain. This step strips out the leftmost label from the name, derives the node of the new fragment, and supplies that node to the ENS Registry. If a resolver is located for that node, the client supplies the original, complete node to that resolver contract to derive the relevant records. This step is repeated until a node with a resolver is found.
|
|
|
|
Further, this specification defines a new way for resolvers to resolve names, using a unified `resolve()` method that permits more flexible handling of name resolution.
|
|
|
|
## Motivation
|
|
|
|
Many applications such as wallet providers, exchanges, and dapps have expressed a desire to issue ENS names for their users via custom subdomains on a shared parent domain. However, the cost of doing so is currently prohibitive for large user bases, as a distinct record must be set on the ENS Registry for each subdomain.
|
|
|
|
Furthermore, users cannot immediately utilize these subdomains upon account creation, as the transaction to assign a resolver for the node of the subdomain must first be submitted and mined on-chain. This adds unnecessary friction when onboarding new users, who coincidentally would often benefit greatly from the usability improvements afforded by an ENS name.
|
|
|
|
Enabling wildcard support allows for the design of more advanced resolvers that deterministically generate addresses and other records for unassigned subdomains. The generated addresses could map to counterfactual contract deployment addresses (i.e. `CREATE2` addresses), to designated "fallback" addresses, or other schemes. Additionally, individual resolvers would still be assignable to any given subdomain, which would supersede the wildcard resolution using the parent resolver.
|
|
|
|
Another critical motivation with EIP-2544 is to enable wildcard resolution in a backwards-compatible fashion. It does not require modifying the current ENS Registry contract or any existing resolvers, and continues to support existing ENS records — legacy ENS clients would simply fail to resolve wildcard records.
|
|
|
|
## Specification
|
|
|
|
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
|
|
|
|
Let:
|
|
- `namehash` be the algorithm defined in EIP 137.
|
|
- `dnsencode` be the process for encoding DNS names specified in section 3.1 of RFC1035, with the exception that there is no limit on the total length of the encoded name. The empty string is encoded identically to the name '.', as a single 0-octet.
|
|
- `parent` be a function that removes the first label from a name (eg, `parent('foo.eth') = 'eth'`). `parent('tld')` is defined as the empty string ''.
|
|
- `ens` is the ENS registry contract for the current network.
|
|
|
|
EIP-2544-compliant ENS resolvers MAY implement the following function interface:
|
|
|
|
```
|
|
interface ExtendedResolver {
|
|
function resolve(bytes calldata name, bytes calldata data) external view returns(bytes);
|
|
}
|
|
```
|
|
|
|
If a resolver implements this function, it MUST return true when `supportsInterface()` is called on it with the interface's ID, 0xTBD.
|
|
|
|
ENS clients will call `resolve` with the DNS-encoded name to resolve and the encoded calldata for a resolver function (as specified in EIP-137 and elsewhere); the function MUST either return valid return data for that function, or revert if it is not supported.
|
|
|
|
EIP-2544-compliant ENS clients MUST perform the following procedure when determining the resolver for a given name:
|
|
|
|
1. Set `currentname = name`
|
|
2. Set `resolver = ens.resolver(namehash(currentname))`
|
|
3. If `resolver` is not the zero address, halt and return `resolver`.
|
|
4. If `name` is the empty name ('' or '.'), halt and return null.
|
|
5. Otherwise, set `currentname = parent(currentname)` and go to 2.
|
|
|
|
If the procedure above returns null, name resolution MUST terminate unsuccessfully. Otherwise, EIP-2544-compliant ENS clients MUST perform the following procedure when resolving a record:
|
|
|
|
1. Set `calldata` to the ABI-encoded call data for the resolution function required - for example, the ABI encoding of `addr(namehash(name))` when resolving the `addr` record.
|
|
2. Set `supports2544 = resolver.supportsInterface(0xTBD)`.
|
|
3. If `supports2544` is true, set `result = resolver.resolve(dnsencode(name), calldata)`
|
|
4. Otherwise, set `result` to the result of calling `resolver` with `calldata`.
|
|
5. Return `result` after decoding it using the return data ABI of the corresponding resolution function (eg, for `addr()`, ABI-decode the result of `resolver.resolve()` as an `address`).
|
|
|
|
Note that in all cases the resolution function (`addr()` etc) and the `resolve` function are supplied the original `name`, *not* the `currentname` found in the first stage of resolution.
|
|
|
|
### Pseudocode
|
|
```
|
|
function getResolver(name) {
|
|
for(let currentname = name; currentname !== ''; currentname = parent(currentname)) {
|
|
const node = namehash(currentname);
|
|
const resolver = ens.resolver(node);
|
|
if(resolver != '0x0000000000000000000000000000000000000000') {
|
|
return resolver;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function resolve(name, func, ...args) {
|
|
const resolver = getResolver(name);
|
|
if(resolver === null) {
|
|
return null;
|
|
}
|
|
const supports2544 = resolver.supportsInterface('0xTBD');
|
|
let result;
|
|
if(supports2544) {
|
|
const calldata = resolver[func].encodeFunctionCall(namehash(name), ...args);
|
|
result = resolver.resolve(dnsencode(name), calldata);
|
|
return resolver[func].decodeReturnData(result);
|
|
} else {
|
|
return resolver[func](...args);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Rationale
|
|
|
|
The proposed implementation supports wildcard resolution in a manner that minimizes the impact to existing systems. It also reuses existing algorithms and procedures to the greatest possible extent, thereby easing the burden placed on authors and maintainers of various ENS clients.
|
|
|
|
It also recognizes an existing consensus concerning the desirability of wildcard resolution for ENS, enabling more widespread adoption of the original specification by solving for a key scalability obstacle.
|
|
|
|
While introducing an optional `resolve` function for resolvers, taking the unhashed name and calldata for a resolution function increases implementation complexity, it provides a means for resolvers to obtain plaintext labels and act accordingly, which enables many wildcard-related use-cases that would otherwise not be possible - for example, a wildcard resolver could resolve `id.nifty.eth` to the owner of the NFT with id `id` in some collection. With only namehashes to work with, this is not possible. Resolvers with simpler requirements can continue to simply implement resolution functions directly and omit support for the `resolve` function entirely.
|
|
|
|
The DNS wire format is used for encoding names as it permits quick and gas-efficient hashing of names, as well as other common operations such as fetching or removing individual labels; in contrast, dot-separated names require iterating over every character in the name to find the delimiter.
|
|
|
|
## Backwards Compatibility
|
|
|
|
Existing ENS clients that are compliant with EIP-137 will fail to resolve wildcard records and refuse to interact with them, while those compliant with EIP-2544 will continue to correctly resolve, or reject, existing ENS records. Resolvers wishing to implement the new `resolve` function for non-wildcard use-cases (eg, where the resolver is set directly on the name being resolved) should consider what to return to legacy clients that call the individual resolution functions for maximum compatibility.
|
|
|
|
## Security Considerations
|
|
|
|
While compliant ENS clients will continue to refuse to resolve records without a resolver, there is still the risk that an improperly-configured client will refer to an incorrect resolver, or will not reject interactions with the null address when a resolver cannot be located.
|
|
|
|
Additionally, resolvers supporting completely arbitrary wildcard subdomain resolution will increase the likelihood of funds being sent to unintended recipients as a result of typos. Applications that implement such resolvers should consider making additional name validation available to clients depending on the context, or implementing features that support recoverability of funds.
|
|
|
|
There is also the possibility that some applications might require that no resolver be set for certain subdomains. For this to be problematic, the parent domain would need to successfully resolve the given subdomain node — to the knowledge of the authors, no application currently supports this feature or expects that subdomains should not resolve to a record.
|
|
|
|
## Copyright
|
|
|
|
Copyright and related rights waived via [CC0](../LICENSE.md).
|