Home

ENS: A Practical Guide

So you’ve made it to this site and this particular blog post. Great! But do you know how you actually got here?

(For those wanting to dive in, feel free to scroll past this to “The DIY Section” below)

The internet today (web2) works, and more importantly gained adoption, in part thanks to the magical world of the Domain Name System (DNS for short). At the highest level, DNS effectively allows users of web2 to say “I want to visit longdogechallenge.com” and reliably be taken to the content (website) that lives there. Let’s break down how that works a bit:

  1. A user enters the domain name, longdogechallenge.com, in their browser’s address bar

  2. A DNS lookup occurs to resolve that domain name to a server’s IP address (an Internet Protocol address is a way to uniquely identify every device on the internet)

  3. The browser is given the IP address for the requested domain name and asks the server behind that IP address for content

  4. The server returns the content and the browser renders that to the end user (aka the resulting website)

(The above is admittedly a major simplification of DNS, and for those wishing to dive deeper, Cloudflare has a great technical write up)

For our purposes though, the general idea is that users of web2 can use DNS to get content behind an IP address while only knowing a domain name. This abstraction is enormously powerful. For starters, IP addresses are not easy to remember - the “common” IPv4 format looks something like 192.168.1.1 and the newer IPv6 format, 2001:0db8:85a3:0000:0000:8a2e:0370:7334, certainly isn’t any easier. IP addresses are designed for uniquely identifying the billions of internet devices and facilitating communication between them; not with humans. And of equal importance, because humans are accessing content via domain names, the server providing that content can be swapped out simply by changing which IP address a domain name points to.

Okay, but what does this have to do with web3?

Allowing mere humans to remember just google.com instead of 142.250.113.102 was a massive accessibility win for web2. The Ethereum Name System, ENS, provides a similar system for the Ethereum ecosystem. And while Ethereum is of course not equivalent to all of web3, it does represent a large portion of the current web3 user base in some capacity (even if you aren’t directly using Ethereum, many protocols and services are built atop the same basic technologies - more on that another time).

ENS, in short, allows a web3 user to say “I want to send funds to alice.eth” without actually knowing the wallet address behind alice.eth.

The DIY Section

Alright, we’ve covered what ENS is and why you should have one. Now let’s dig into how to acquire and use ENS; for both web3 users and developers.

For Users

Go buy an ENS! Seriously, go right now and buy one if you haven’t already. Some steps to get you started:

Setup your wallet

If you haven’t already, make sure you have a web3 wallet. MetaMask is a great place to get started if you haven’t already joined web3.

From there, make sure you have “some” Ethereum in your wallet. A quarter (0.25) ETH should be plenty to get started (unless you’re trying to get a highly prized ENS). If you don’t have any ETH yet, look towards exchanges like Coinbase to get you started.

Buy an ENS

Visit a site like https://app.ens.domains to look up names you’re interested in. There’s no wrong answer here - it’s a lot like choosing an email or a Twitter handle. If your name is available, then great! Follow the registration process (yes, this will involve 2 transactions) and secure your shiny new ENS.

If the name you like is already registered, then you have a few options for purchasing it on the “secondary markets”. ENS, at least in part, is officially a standard NFT collection. That means you can use your favorite NFT marketplaces to trade registered ENS items. Some options in no particular order:

Tie your ENS to your wallet address

This is the important piece. Now that you own your ENS, you need to make sure that it’s setup to point to your wallet address. There are two different pieces to this. Go back to https://app.ens.domains/ once again and click “My Account” in the upper right-hand corner and then do the following:

Define the ENS => wallet address lookup -- Select the ENS you just purchased and set the “Record” for “ETH” address to your wallet address. During this step, feel free to set as many of the other text records you see there as you want - this is all part of your new web3 profile.

Setting ENS records

Define the wallet address => ENS reverse lookup -- Go back to your “My Account” page and you’ll have an option to select your “Primary ENS Name”. Submit the corresponding transaction to make it permanent 🔥

Setting a Primary ENS Name

NOTE: Both of the above steps will also require submitting Ethereum transactions and paying a small amount of ETH in “gas”. This is to pay the network to store the new data you just added.

And just like that, you’ll now have an official, named identity in web3 🎉 A simple way you can try it out is by looking up your name or wallet address on Etherscan and seeing that the two are linked in the results.

BONUS: Add an NFT as your avatar

Thanks to the wonderful world of web3, you can also link pieces of decentralized data together. Specifically in this case, you can say that the photo for your shiny new ENS name should be another NFT that you own. For instance, the avatar field for runninyeti.eth is set to `eip155:1/erc1155:0x495f947276749ce646f68ac8c248420045cb7b5e/87433597745683365960201176492736871205018189775129059226749288698845216112641` which points to this lovely image:

For a good overview of how to do this, check out this post by the ENS team.

For Developers

Also go buy an ENS! For yourself, for your project, whatever it might be, just start participating. See the “For Users” section above and follow along.

Now that that’s done, here’s some how-to’s for adding ENS functionality to your projects. We’re going to focus on using web3.js since it’s usable on both frontend and backend codebases, but these same principles can be used with any language.

We’re also going to focus on some of the low-hanging fruit based on what is available to the developer community today, but we encourage everyone to go far beyond this (e.g. “ENS Profiles” or deploying ENS on a private chain). There are also existing packages to obfuscate working with ENS (mainly JavaScript based, like ensjs), but for this post we’ll be looking at how we can do it ourselves and handle all data directly.

Look up the current owner of an ENS

tl;dr - ask the NFT contract for ENS who the current owner is

We’ll start with an easy one. To grab the address of the current owner of a given ENS name:

  1. Define a web3.js contract instance with the ownerOf ABI input

  2. Convert the name to a tokenId

  3. Ask the contract who owns that tokenId

async function getOwnerAddressForENSName(name) {
  // do a basic null check
  if (!name) {
    return null;
  }

  // define a new contract instance for ENS NFTs
  const nftContract = new web3.eth.Contract(
    [
      {
        inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }],
        name: 'ownerOf',
        outputs: [{ internalType: 'address', name: '', type: 'address' }],
        stateMutability: 'view',
        type: 'function',
      },
    ],
    ENS_NFT_ADDRESS
  );

  // convert the name to a tokenId
  const tokenId = new BigNumber(Web3.utils.sha3(name.replace(/\.eth$/, ''))).toString();

  // ask the contract for the current owner and return the result
  return nftContract.methods
    .ownerOf(tokenId)
    .call()
    .catch(() => null);
}

Swap ENS names for wallet addresses

tl;dr - ask the ENS resolver for the address of a given ENS name

Let’s kick things up a notch. In order to get the resolved address for a given ENS name, we’ll need a few things:

  1. First we want to define a contract instance for the ENS resolver with the addr method. The current contract address is 0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41

  2. We then leverage the namehash algorithm to convert the given name to a sha3 node

  3. Ask the contract for the current addr value of the given node

async function getAddressFromENSName(name) {
  // some basic validity checks
  // @NOTE: non .eth names are valid, but may require a different resolver contract address
  if (!name || !name.endsWith('.eth')) {
    return null;
  }

  // define a new contract instance for our ENS resolver
  const resolverContract = new web3.eth.Contract(
    [
      {
        constant: true,
        inputs: [{ internalType: 'bytes32', name: 'node', type: 'bytes32' }],
        name: 'addr',
        outputs: [{ internalType: 'address', name: '', type: 'address' }],
        payable: false,
        stateMutability: 'view',
        type: 'function',
      },
    ],
    ENS_RESOLVER_ADDRESS
  );

  // convert our name to a node hash
  const node = namehash(name);

  // ask the contract for the current address and return the result
  return resolverContract.methods
    .addr(node)
    .call()
    .catch(() => null);
}

Swap wallet addresses for ENS names

tl;dr - ask the ENS reverse resolver for the ENS name of a given address; double check against the name => address method above

A final example here, getting the ENS name for a given wallet address is almost identical to the other two methods above:

  1. Again, start by defining a new contract instance for the ENS reverse resolver with the getNames method. The current contract address is 0x3671aE578E63FdF66ad4F3E12CC0c0d71Ac7510C

  2. Ask the contract for the name that corresponds to our given address

  3. Double check that the name => address mapping matches. While this step isn’t necessary, it’s best practice to ensure no one is manipulating the reverse resolver - more info from ENS here

async function getENSNameFromAddress(address) {
  // some basic validity checks
  if (!address || address.length !== 42) {
    return null;
  }

  // make sure our address is the checksum version
  address = Web3.utils.toChecksumAddress(address);

  // define a new contract instance for our ENS reverse resolver
  const reverseResolverContract = new web3.eth.Contract(
    [
      {
        inputs: [{ internalType: 'address[]', name: 'addresses', type: 'address[]' }],
        name: 'getNames',
        outputs: [{ internalType: 'string[]', name: 'r', type: 'string[]' }],
        stateMutability: 'view',
        type: 'function',
      },
    ],
    ENS_REVERSE_RESOLVER_ADDRESS
  );

  // ask the contract for the name that maps from the address
  // @NOTE: you can pass multiple addresses in a single call with this method
  const [name] = await reverseResolverContract.methods
    .getNames([address])
    .call()
    .catch(() => []);

  // @NOTE: ideally we double check that the reverse resolver is correct
  //        this can be done by comparing against the name => address mapping
  if (address !== (await getAddressFromENSName(name))) {
    return null;
  }

  return name;
}

Wrapping up

There you have it, that’s a quick run down on working with ENS! Both as a web3 user and as a developer in the space. For deeper dives, definitely check out the official ENS documentation and feel free to explore the code from this post on Github. And please reach out if you find this post interesting or just want to chat more about ENS, indexing, and Data 3.0.