Overview
The Ethereum Name Service (ENS) is an open, extensible naming system built on the Ethereum blockchain. As the most widely used naming protocol on Ethereum, ENS simplifies complex Ethereum addresses into human-readable names like vitalik.eth.
This guide assumes readers have intermediate Solidity programming knowledge. If you can understand ERC-20 contract implementations, you'll find this content accessible. For beginners, we recommend first studying this Foundry tutorial on ERC-20 contracts.
Core Components
ENS operates through three primary components:
- Registry - The central smart contract that serves as the starting point for ENS queries
- Resolvers - Contracts that execute actual domain resolution
- Registrar - Handles domain registration and NFT minting
Registry Structure
The Registry contract maintains:
- Domain owner (
owner) - Domain resolver (
resolver) - Time-to-live cache (
TTL)
Domain owners can delegate modification rights to operators via:
struct Record {
address owner;
address resolver;
uint64 ttl;
}
mapping(bytes32 => Record) records;
mapping(address => mapping(address => bool)) operators;Resolvers
Resolver contracts implement ENS standards to support various record types including:
- Ethereum addresses
- EVM-compatible chain addresses
- Content hash values
👉 Learn more about ENS resolution standards
Domain Resolution Process
Namehash Calculation
ENS uses namehash to represent domains in contracts. This recursive hash method preserves domain hierarchy:
- Name Normalization: Converts domains to ASCII using UTS46 encoding (case-insensitive)
- Hierarchical Hashing: Processes labels from right to left
Python implementation (simplified):
from Crypto.Hash import keccak
def namehash(name: str):
labels = name.split(".")[::-1]
node = "0" * 64
for label in labels:
label_hash = keccak.new(digest_bits=256).update(label.encode()).hexdigest()
node += label_hash
node = keccak.new(digest_bits=256).update(bytes.fromhex(node)).hexdigest()
return nodePro tip: Use cast namehash foo.eth with Foundry for quick hashingResolution Workflow
- Query
Registry.resolver()to get resolver address - Call resolver's
addr()function for address resolution:
function addr(bytes32 node) public view returns (address payable) {
bytes memory a = addr(node, 60); // 60 = ETH coinType
return a.length == 0 ? payable(0) : bytesToAddress(a);
}Multi-chain resolution follows ENSIP-9 and SLIP-0044 standards.
Domain Registration
Registration Process
The .eth Registrar contract (BaseRegistrarImplementation.sol) handles registrations:
function _register(
uint256 id, // label hash
address owner,
uint256 duration,
bool updateRegistry
) internal {
require(available(id));
expiries[id] = block.timestamp + duration;
if (_exists(id)) _burn(id);
_mint(owner, id);
if (updateRegistry) {
ens.setSubnodeOwner(baseNode, bytes32(id), owner);
}
}Key points:
- Only active controllers can call registration functions
- NFT tokenID =
keccak256(label) - Metadata URL format:
https://metadata.ens.domains/mainnet/[contract]/[tokenId]
👉 View current ENS controllers
ENS Name Wrapper
The Name Wrapper system introduces advanced permission management through ERC1155 NFTs and fuse mechanisms:
Fuse Types
| Owner-Controlled Fuses | Bit | Function |
|---|---|---|
| CANNOT_UNWRAP | 1 | Prevent unwrapping |
| CANNOT_BURN_FUSES | 2 | Prevent further fuse burns |
| CANNOT_TRANSFER | 4 | Prevent NFT transfers |
| Parent-Controlled Fuses | Bit | Function |
|---|---|---|
| PARENT_CANNOT_CONTROL | 65536 | Relinquish parent control |
| CAN_EXTEND_EXPIRY | 262144 | Allow expiry extension |
Domain States
- Wrapped: Parent maintains control
- Emancipated: Parent control removed (automatic for .eth domains)
- Locked: Permanent wrapper state with full subdomain control
FAQ
How do I check a domain's expiration?
Query expiries[id] in the Registrar contract where id = keccak256(label).
Can I transfer a subdomain without root domain permission?
Only if the root domain has burned PARENT_CANNOT_CONTROL and the subdomain hasn't burned CANNOT_TRANSFER.
What's the difference between ENS NFT and DNS?
ENS provides blockchain-native resolution with smart contract integration, while DNS is the traditional web system.
How do I resolve multi-chain addresses?
Use the addr(node, coinType) function with appropriate coinType values from SLIP-0044.
Can I recover expired domains?
Yes, within the 90-day grace period after expiration.