The Ethereum Name Service (ENS)

You can design the best smart contract in the world, but if you don’t provide a good interface for users, they won’t be able to access it.

On the traditional internet, the Domain Name System (DNS) allows us to use human-readable names in the browser while resolving those names to IP addresses or other identifiers behind the scenes. On the Ethereum blockchain, the Ethereum Naming System (ENS) solves the same problem, but in a decentralized manner.

For example, the Ethereum Foundation donation address is 0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359; in a wallet that supports ENS, it’s simply ethereum.eth.

ENS is more than a smart contract; it’s a fundamental DApp itself, offering a decentralized name service. Furthermore, ENS is supported by a number of DApps for registration, management, and auctions of registered names. ENS demonstrates how DApps can work together: it’s DApp built to serve other DApps, supported by an ecosystem of DApps, embedded in other DApps, and so on.

In this section we will look at how ENS works. We’ll demonstrate how you can set up your own name and link it to a wallet or Ethereum address, how you can embed ENS in another DApp, and how you can use ENS to name your DApp resources to make them easier to use.

History of Ethereum Name Services

Name registration was the first noncurrency application of blockchains, pioneered by Namecoin. The Ethereum White Paper gave a two-line Namecoin-like registration system as one of its example applications.

Early releases of Geth and the C++ Ethereum client had a built-in namereg contract (not used any more), and many proposals and ERCs for name services were made, but it was only when Nick Johnson started working for the Ethereum Foundation in 2016 and took the project under his wing that serious work on a registrar started.

ENS was launched on Star Wars Day, May 4, 2017 (after a failed attempt to launch it on Pi Day, March 15).

The ENS Specification

ENS is specified mainly in three Ethereum Improvement Proposals: EIP-137, which specifies the basic functions of ENS; EIP-162, which describes the auction system for the .eth root; and EIP-181, which specifies reverse resolution of addresses.

ENS follows a “sandwich” design philosophy: a very simple layer on the bottom, followed by layers of more complex but replaceable code, with a very simple top layer that keeps all the funds in separate accounts.

Bottom Layer: Name Owners and Resolvers

The ENS operates on “nodes” instead of human-readable names: a human-readable name is converted to a node using the “Namehash” algorithm.

The base layer of ENS is a cleverly simple contract (less than 50 lines of code) defined by ERC137 that allows only nodes’ owners to set information about their names and to create subnodes (the ENS equivalent of DNS subdomains).

The only functions on the base layer are those that enable a node owner to set information about their own node (specifically the resolver, time to live, or transferring the ownership) and to create owners of new subnodes.

The Namehash algorithm

Namehash is a recursive algorithm that can convert any name into a hash that identifies the name.

“Recursive” means that we solve the problem by solving a subproblem that is a smaller problem of the same type, and then use the solution to the subproblem to solve the original problem.

Namehash recursively hashes components of the name, producing a unique, fixed-length string (or “node”) for any valid input domain. For example, the Namehash node of subdomain.example.eth is keccak('<example.eth>' node) + keccak('<subdomain>'). The subproblem we must solve is to compute the node for example.eth, which is keccak('<.eth>' node) + keccak('<example>'). To begin, we must compute the node for eth, which is keccak(<root node>) + keccak('<eth>').

The root node is what we call the “base case” of our recursion, and we obviously can’t define it recursively, or the algorithm will never terminate! The root node is defined as 0x0000000000000000000000000000000000000000000000000000000000000000 (32 zero bytes).

Putting this all together, the node of subdomain.example.eth is therefore keccak(keccak(keccak(0x0...0 + keccak('eth')) + keccak('example')) + keccak('subdomain')).

Generalizing, we can define the Namehash function as follows (the base case for the root node, or empty name, followed by the recursive step):

  1. namehash([]) = 0x0000000000000000000000000000000000000000000000000000000000000000
  2. namehash([label, ...]) = keccak256(namehash(...) + keccak256(label))

In Python this becomes:

  1. def namehash(name):
  2. if name == '':
  3. return '\0' * 32
  4. else:
  5. label, _, remainder = name.partition('.')
  6. return sha3(namehash(remainder) + sha3(label))

Thus, mastering-ethereum.eth will be processed as follows:

  1. namehash('mastering-ethereum.eth')
  2. sha3(namehash('eth') + sha3('mastering-ethereum'))
  3. sha3(sha3(namehash('') + sha3('eth')) + sha3('mastering-ethereum'))
  4. sha3(sha3(('\0' * 32) + sha3('eth')) + sha3('mastering-ethereum'))

Of course, subdomains can themselves have subdomains: there could be a sub.subdomain.example.eth after subdomain.example.eth, then a sub.sub.subdomain.example.eth, and so on. To avoid expensive recomputation, since Namehash depends only on the name itself, the node for a given name can be precomputed and inserted into a contract, removing the need for string manipulation and permitting immediate lookup of ENS records regardless of the number of components in the raw name.

How to choose a valid name

Names consist of a series of dot-separated labels. Although upper- and lowercase letters are allowed, all labels should follow a UTS #46 normalization process that case-folds labels before hashing them, so names with different case but identical spelling will end up with the same Namehash.

You could use labels and domains of any length, but for the sake of compatibility with legacy DNS, the following rules are recommended:

  • Labels should be no more than 64 characters each.

  • Complete ENS names should be no more than 255 characters.

  • Labels should not start or end with hyphens, or start with digits.

Root node ownership

One of the results of this hierarchical system is that it relies on the owners of the root node, who are able to create top-level domains (TLDs).

While the eventual goal is to adopt a decentralized decision-making process for new TLDs, at the time of writing the root node is controlled by a 4-of-7 multisig, held by people in different countries (built as a reflection of the 7 keyholders of the DNS system). As a result, a majority of at least 4 of the 7 keyholders is required to effect any change.

Currently the purpose and goal of these keyholders is to work in consensus with the community to:

  • Migrate and upgrade the temporary ownership of the .eth TLD to a more permanent contract once the system is evaluated.

  • Allow adding new TLDs, if the community agrees they are needed.

  • Migrate the ownership of the root multisig to a more decentralized contract, when such a system is agreed upon, tested, and implemented.

  • Serve as a last-resort way to deal with any bugs or vulnerabilities in the top-level registries.

Resolvers

The basic ENS contract can’t add metadata to names; that is the job of so-called “resolver contracts.” These are user-created contracts that can answer questions about the name, such as what Swarm address is associated with the app, what address receives payments to the app (in ether or tokens), or what the hash of the app is (to verify its integrity).

Middle Layer: The .eth Nodes

At the time of writing, the only top-level domain that is uniquely registrable in a smart contract is .eth.

Note

There’s work underway on enabling traditional DNS domain owners to claim ENS ownership. While in theory this could work for .com, the only domain that this has been implemented for so far is .xyz, and only on the Ropsten testnet.

.eth domains are distributed via an auction system. There is no reserved list or priority, and the only way to acquire a name is to use the system. The auction system is a complex piece of code (over 500 lines); most of the early development efforts (and bugs!) in ENS were in this part of the system. However, it’s also replaceable and upgradeable, without risk to the funds—more on that later.

Vickrey auctions

Names are distributed via a modified Vickrey auction. In a traditional Vickrey auction, every bidder submits a sealed bid, and all of them are revealed simultaneously, at which point the highest bidder wins the auction but only pays the second-highest bid. Therefore bidders are incentivized not to bid less than the true value of the name to them, since bidding their true value increases the chance they will win but does not affect the price they will eventually pay.

On a blockchain, some changes are required:

  • To ensure bidders don’t submit bids they have no intention of paying, they must lock up a value equal to or higher than their bid beforehand, to guarantee the bid is valid.

  • Because you can’t hide secrets on a blockchain, bidders must execute at least two transactions (a commit–reveal process), in order to hide the original value and name they bid on.

  • Since you can’t reveal all bids simultaneously in a decentralized system, bidders must reveal their own bids themselves; if they don’t, they forfeit their locked-up funds. Without this forfeit, one could make many bids and choose to reveal only one or two, turning a sealed-bid auction into a traditional increasing price auction.

Therefore, the auction is a four-step process:

  1. Start the auction. This is required to broadcast the intent to register a name. This creates all auction deadlines. The names are hashed, so that only those who have the name in their dictionary will know which auction was opened. This allows some privacy, which is useful if you are creating a new project and don’t want to share details about it. You can open multiple dummy auctions at the same time, so if someone is following you they cannot simply bid on all auctions you open.

  2. Make a sealed bid. You must do this before the bidding deadline, by tying a given amount of ether to the hash of a secret message (containing, among other things, the hash of the name, the actual amount of the bid, and a salt). You can lock up more ether than you are actually bidding in order to mask your true valuation.

  3. Reveal the bid. During the reveal period, you must make a transaction that reveals the bid, which will then calculate the highest bid and the second-highest bid and send ether back to unsuccessful bidders. Every time the bid is revealed the current winner is recalculated; therefore, the last one to be set before the revealing deadline expires becomes the overall winner.

  4. Clean up after. If you are the winner, you can finalize the auction in order to get back the difference between your bid and the second-highest bid. If you forgot to reveal you can make a late reveal and recover a little of your bid.

Top Layer: The Deeds

The top layer of ENS is yet another super-simple contract with a single purpose: to hold the funds.

When you win a name, the funds are not actually sent anywhere, but are just locked up for the period you want to hold the name (at least a year). This works like a guaranteed buyback: if the owner does not want the name any more they can sell it back to the system and recover their ether (so the cost of holding the name is the opportunity cost of doing something with a return greater than zero).

Of course, having a single contract hold millions of dollars in ether has proven to be very risky, so instead ENS creates a deed contract for each new name. The deed contract is very simple (about 50 lines of code), and it only allows the funds to be transferred back to a single account (the deed owner) and to be called by a single entity (the registrar contract). This approach drastically reduces the attack surface where bugs can put the funds at risk.

Registering a Name

Registering a name in ENS is a four-step process, as we saw in Vickrey auctions. First we place a bid for any available name, then we reveal our bid after 48 hours to secure the name. ENS timeline for registration is a diagram showing the timeline of registration.

Let’s register our first name!

We will use one of several available user-friendly interfaces to search for available names, place a bid on the name ethereumbook.eth, reveal the bid, and secure the name.

There are a number of web-based interfaces to ENS that allow us to interact with the ENS DApp. For this example, we will use the MyCrypto interface, in conjunction with MetaMask as our wallet.

ens flow

Figure 5. ENS timeline for registration

First, we need to make sure the name we want is available. While writing this book, we really wanted to register the name mastering.eth, but alas, Searching for ENS names on MyCrypto.com revealed it was already taken! Because ENS registrations only last one year, it might become possible to secure that name in the future. In the meantime, let’s search for ethereumbook.eth (Searching for ENS names on MyCrypto.com).

Searching for ENS names on MyCrypto.com

Figure 6. Searching for ENS names on MyCrypto.com

Great! The name is available. In order to register it, we need to move forward with Starting an auction for an ENS name. Let’s unlock MetaMask and start an auction for ethereumbook.eth.

Starting an auction for an ENS name

Figure 7. Starting an auction for an ENS name

Let’s make our bid. In order to do that we need to follow the steps in Placing a bid for an ENS name.

Placing a bid for an ENS name

Figure 8. Placing a bid for an ENS name

Warning

As mentioned in Vickrey auctions, you must reveal your bid within 48 hours after the auction is complete, or you lose the funds in your bid. Did we forget to do this and lose 0.01 ETH ourselves? You bet we did.

Take a screenshot, save your secret phrase (as a backup for your bid), and add a reminder in your calendar for the reveal date and time, so you don’t forget and lose your funds.

Finally, we confirm the transaction by clicking the big green submit button shown in MetaMask transaction containing your bid.

MetaMask transaction containing your bid

Figure 9. MetaMask transaction containing your bid

If all goes well, after submitting a transaction in this way you can return and reveal the bid in 48 hours, and the name you requested will be registered to your Ethereum address.

Managing Your ENS Name

Once you have registered an ENS name, you can manage it using another user-friendly interface: ENS Manager.

Once there, enter the name you want to manage in the search box (see The ENS Manager web interface). You need to have your Ethereum wallet (e.g., MetaMask) unlocked, so that the ENS Manager DApp can manage the name on your behalf.

The ENS Manager web interface

Figure 10. The ENS Manager web interface

From this interface, we can create subdomains, set a resolver contract (more on that later), and connect each name to the appropriate resource, such as the Swarm address of a DApp frontend.

Creating an ENS subdomain

First, let’s create a subdomain for our example Auction DApp (see Adding the subdomain auction.ethereumbook.eth). We will name the subdomain auction, so the fully qualified name will be auction.ethereumbook.eth.

Adding the subdomain auction.ethereumbook.eth

Figure 11. Adding the subdomain auction.ethereumbook.eth

Once we’ve created the subdomain, we can enter auction.ethereumbook.eth in the search box and manage it, just as we managed the domain ethereumbook.eth previously.

ENS Resolvers

In ENS, resolving a name is a two-step process:

  1. The ENS registry is called with the name to resolve after hashing it. If the record exists, the registry returns the address of its resolver.

  2. The resolver is called, using the method appropriate to the resource being requested. The resolver returns the desired result.

This two-step process has several benefits. Separating the functionality of resolvers from the naming system itself gives us a lot more flexibility. The owners of names can use custom resolvers to resolve any type or resource, extending the functionality of ENS. For example, if in the future you wanted to link a geolocation resource (longitude/lattitude) to an ENS name, you could create a new resolver that answers a geolocation query. Who knows what applications might be useful in the future? With custom resolvers, the only limitation is your imagination.

For convenience, there is a default public resolver that can resolve a variety of resources, including the address (for wallets or contracts) and content (a Swarm hash for DApps or contract source code).

Since we want to link our Auction DApp to a Swarm hash, we can use the public resolver, which supports content resolution, as shown in Setting the default public resolver for auction.ethereumbook.eth; we don’t need to code or deploy a custom resolver.

Set the default public resolver for auction.ethereumbook.eth

Figure 12. Setting the default public resolver for auction.ethereumbook.eth

Resolving a Name to a Swarm Hash (Content)

Once the resolver for auction.ethereumbook.eth is set to be the public resolver, we can set it to return the Swarm hash as the content of our name (see Setting the ‘content’ to return for auction.ethereumbook.eth).

Set the 'content' return for auction.ethereumbook.eth

Figure 13. Setting the ‘content’ to return for auction.ethereumbook.eth

After waiting a short time for our transaction to be confirmed, we should be able to resolve the name correctly. Before setting a name, our Auction DApp could be found on a Swarm gateway by its hash:

or by searching in a DApp browser or Swarm gateway for the Swarm URL:

  • bzz://ab164cf37dc10647e43a233486cdeffa8334b026e32a480dd9cbd020c12d4581

Now that we have attached it to a name, it is much easier:

We can also find it by searching for “auction.ethereumbook.eth” in any ENS-compatible wallet or DApp browser (e.g., Mist).