Overview
When working with ENS from a technical side, you'll almost certainly encounter one of these long decimal or hexadecimal numbers that represent different pieces of an ENS name:
Namehash | A hash value that uniquely identifies a single ENS name. |
Labelhash | A hash value that identifies only a single part or "label" of an ENS name. |
Token ID | This is a unique identifier for an ENS NFT. |
For example, take the name ens.eth
.
The namehash of ens.eth
is:
Decimal |
|
Hexadecimal |
|
The labelhash of ens.eth
is:
Decimal |
|
Hexadecimal |
|
For an unwrapped .eth 2LD (second-level domain), the token ID for the ERC-721 NFT is the same as the labelhash for the second-level part of the domain.
Looking at ens.eth
, the top-level part is eth
and the second-level part is ens
, which is also usually referred to as the label.
So the token ID for the NFT is the same as the labelhash listed above. It's the same number, just represented either in decimal or hexadecimal form. For NFT token IDs, in many cases you'll work with the decimal form.
For example, you will see that token ID in the URL of public explorers or marketplaces:
Etherscan | https://etherscan.io/nft/0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85/ |
OpenSea | https://opensea.io/assets/ethereum/0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85/ |
Those URLs can vary, but they usually contain the NFT contract address (hexadecimal) and the NFT token ID (usually in decimal form). For the ERC-721 NFTs that represent .eth 2LDs, the contract address is 0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85
.
Generating a Labelhash
The labelhash is just the Keccak-256 output for the label.
For a .eth 2LD, the label you're usually going to be concerned with is the first one that appears (in other words the lowest level of the name).
So for ens.eth
, the label you care about is going to be ens
. Take that value ens
and plug it into the Keccak-256 function, and the output is the labelhash.
Here's an example using Node.js:
'0x' + require('js-sha3').keccak_256('ens')
If you don't have a local Node.js environment, you can try it out yourself here: https://npm.runkit.com/js-sha3
Enter the above code, and it'll spit out the labelhash in hexadecimal format:
To get the labelhash in decimal format, use this code:
require('big-integer')(require('js-sha3').keccak_256('ens'), 16).toString()
Generating a Namehash
The namehash is a custom algorithm that uses the labelhash for each label in the name. The specification is here: https://eips.ethereum.org/EIPS/eip-137#namehash-algorithm
It's a recursive algorithm that works its way down until you hit the root domain. For ens.eth
, the algorithm works like so:
|
|
|
That last line is a special case: The namehash for an empty string (representing the root domain) is 32 null bytes.
If you plug everything in above, you'll end up with the final namehash value:
namehash('')
=0x0000000000000000000000000000000000000000000000000000000000000000
labelhash('eth')
=keccak256('eth')
=0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0
namehash('eth')
=keccak256(namehash('') + labelhash('eth'))
=keccak256(0x00000000000000000000000000000000000000000000000000000000000000004f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0)
=0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae
labelhash('ens')
=keccak256('ens')
=0x5cee339e13375638553bdf5a6e36ba80fb9f6a4f0783680884d92b558aa471da
namehash('ens.eth')
=keccak256(namehash('eth') + labelhash('ens'))
=keccak256(0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae5cee339e13375638553bdf5a6e36ba80fb9f6a4f0783680884d92b558aa471da)
=0x4e34d3a81dc3a20f71bbdf2160492ddaa17ee7e5523757d47153379c13cb46df
Luckily, you do not need to go through all those steps every time, as there are libraries that have this function built-in.
For Node.js, you can use this code:
require("@ensdomains/eth-ens-namehash").hash('ens.eth')
If you don't have a local Node.js environment, you can try it out yourself here: https://npm.runkit.com/%40ensdomains%2Feth-ens-namehash
Enter the above code, and it'll spit out the namehash in hexadecimal format:
To get the namehash in decimal format, use this code:
var hexNamehash = require("@ensdomains/eth-ens-namehash").hash('ens.eth')
require('big-integer')(hexNamehash.substr(2), 16).toString()
NFT Token IDs
There are two separate official NFT contracts for ENS:
The ERC-721 NFTs for .eth 2LDs (second-level domains, like
ens.eth
)The ERC-1155 NFTs for wrapped names (could be any .eth or DNS name, subdomains included)
For .eth 2LDs, the ERC-721 NFT token ID is the labelhash for the first (or lowest) label in the domain. So for ens.eth
, the token ID is the labelhash for ens
:
Decimal |
|
Hexadecimal |
|
For names wrapped in the Name Wrapper, the ERC-1155 NFT token ID is the namehash for the entire name. So for ens.eth
, the wrapped token ID would be the namehash for ens.eth
:
Decimal |
|
Hexadecimal |
|