ERC-4834 Hierarchical domains

Final · Names & metadata · created 2022-02-22

A minimal name resolution standard that treats a contract itself as a domain and converts human-readable names into addresses. Each level can attach the access control it wants.

Why it is needed

Ethereum addresses are long hex strings, which are hard for people to read or remember. Schemes such as ENS (ERC-137), which attach names to addresses, are used for this, but the source points to two problems: ENS has a relatively complex structure and no standardized access control. If the way of deciding who can create, change, and delete each name is not fixed by a standard, then even when different levels want to use different management approaches, there is no common interface, so apps and wallets find it hard to handle them consistently. This standard defines a minimal interface of just two functions needed for name resolution and has every domain, from the root and top-level domains (TLDs) to subdomains, implemented by the same contract, so that names can be resolved with a simple iterative algorithm like DNS.

What to implement

In depth

Every level is the same domain contract

In this standard, a domain is a contract that implements the IDomain interface. Subdomains, TLDs, and even the root are all implemented as domains in the same way. This makes name resolution a simple iterative algorithm similar to DNS. The required interface is only two functions, hasDomain and getDomain, and both take the name as a string array (string[]) in right-to-left order. getDomain must revert when hasDomain(name) is false.

Name resolution algorithm

Split a name such as "a.b.c" by the delimiter to make ["a", "b", "c"], and initialize domain to the root and path to an empty list. Take the last element of the array, add it to path, and then call domain.hasDomain(path). If it returns false, resolution fails, and if true, domain is replaced with domain.getDomain(path). Repeat until all the split pieces are gone. Because there is no limit on nesting depth, the source gives an example where the root holds z and z holds y, and so on, so that even a 36-level name is valid. Because the contracts along the resolution path fully control resolution, flexible implementations are possible, such as a domain that returns a different address depending on the time of day.

Optional extension Registerable: registration and changes

It defines creation (createDomain), update (setDomain) and deletion (deleteDomain) of subdomains, along with three events (SubdomainCreate, SubdomainUpdate, SubdomainDelete). Each write function must revert if its corresponding query function (canCreateDomain, canSetDomain, canDeleteDomain) returns false or if the existence condition is not met. canCreateDomain must return false when hasDomain(name) is true, and canSetDomain and canDeleteDomain must return false when hasDomain(name) is false. createDomain is declared payable, so an implementation may charge a registration fee.

Optional extension Enumerable: listing subdomains

subdomainByIndex(uint256 index) returns the subdomain name at the given index, and totalSubdomains() returns the total count. Both functions must revert when the number of subdomains is unknown or infinite. With this extension, external callers can iterate over the subdomains a domain holds.

Optional extension Access Control: permissions on the subdomain side

This extension lets a subdomain decide permissions about itself. canMoveSubdomain returns whether an account can detach this subdomain from its current parent and replace it with another address, and canDeleteSubdomain returns whether an account can remove the link. The parent domain's canSetDomain and canDeleteDomain are designed to call these functions, so a subdomain is not bound only by the parent's access control. The Rationale in the original text also states that these functions are advisory in nature. For example, a domain that has an owner can implement an owner override so that the domain can be recovered if a key is lost.

Why a simple ownable interface was not used

To keep the design as general as possible, the standard does not adopt a simple owner (ownable) interface. If an owner model is needed, it can be implemented that way. This structure allows different governance at each level. The original text gives an example combination: the root domain is governed by a DAO that distributes non-transferable tokens equally, a TLD by a stake-token DAO, domains below it by a single owner, and subdomains by an owner tied to an NFT.

Relationship with ENS

This standard has a similar purpose to ENS (ERC-137) but takes a different approach. Unlike ENS's resolution algorithm, name resolution in this standard is fully controlled by the contracts along the resolution path. The original text explains that this behavior is more intuitive for users. On compatibility, it states that this standard is general enough to support ENS, but ENS is not general enough to support this standard. This standard has reached Final status.

Things to watch out for

Original ERC · ← ERCs