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:
A user enters the domain name, longdogechallenge.com
, in their browser’s address bar
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)
The browser is given the IP address for the requested domain name and asks the server behind that IP address for content
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.
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
.
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.
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.
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 🔥
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.
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:
Define a web3.js contract instance with the ownerOf
ABI input
Convert the name
to a tokenId
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:
First we want to define a contract instance for the ENS resolver with the addr
method. The current contract address is 0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41
We then leverage the namehash
algorithm to convert the given name
to a sha3 node
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:
Again, start by defining a new contract instance for the ENS reverse resolver with the getNames
method. The current contract address is 0x3671aE578E63FdF66ad4F3E12CC0c0d71Ac7510C
Ask the contract for the name that corresponds to our given address
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;
}
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.