Skip to main content
ENS provides a decentralized naming system that makes blockchain addresses human-readable. This guide covers the essential contracts and patterns for integrating ENS into your application.

Overview

Integrating ENS into your application involves:
  • Resolving ENS names to addresses
  • Setting up reverse resolution
  • Managing resolver records
  • Handling different coin types and chains

Core Contracts

ENS Registry

The ENS registry (ENSRegistry.sol) is the core contract that maintains the ownership and resolver information for all ENS names. Key Functions:
  • owner(bytes32 node) - Returns the owner of a name
  • resolver(bytes32 node) - Returns the resolver for a name
  • setResolver(bytes32 node, address resolver) - Sets the resolver for a name

Public Resolver

The PublicResolver contract implements various resolver profiles:
  • AddrResolver - Address resolution (EIP-137, EIP-2304)
  • TextResolver - Text records (EIP-634)
  • ContentHashResolver - Content hash support (EIP-1577)
  • NameResolver - Reverse resolution (EIP-181)
  • ABIResolver - Contract ABI support (EIP-205)
  • PubkeyResolver - Public key records (EIP-619)
Source: ~/workspace/source/contracts/resolvers/PublicResolver.sol:19-29

Installation

Install the ENS contracts package:
npm install @ensdomains/ens-contracts

Importing Contracts

JavaScript/TypeScript

import {
  ENS,
  ENSRegistry,
  PublicResolver,
  ETHRegistrarController,
  ReverseRegistrar
} from '@ensdomains/ens-contracts'

Solidity

import '@ensdomains/ens-contracts/contracts/registry/ENS.sol';
import '@ensdomains/ens-contracts/contracts/resolvers/PublicResolver.sol';

Basic Integration Pattern

1

Get the ENS Registry

Connect to the ENS registry contract deployed on your network.
import { namehash } from 'viem'

const ENS_REGISTRY_ADDRESS = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e'
const ensRegistry = await viem.getContractAt(
  'ENSRegistry',
  ENS_REGISTRY_ADDRESS
)
2

Resolve the Name

Use namehash to convert the ENS name to a node, then look up its resolver.
const node = namehash('vitalik.eth')
const resolverAddress = await ensRegistry.read.resolver([node])
3

Query the Resolver

Get the address from the resolver contract.
const resolver = await viem.getContractAt(
  'PublicResolver',
  resolverAddress
)
const address = await resolver.read.addr([node])

Multi-Chain Address Resolution

ENS supports addresses for multiple blockchains using coin types (ENSIP-9).
import { namehash } from 'viem'

const node = namehash('example.eth')
const resolver = await viem.getContractAt('PublicResolver', resolverAddress)

// Get Ethereum address (coin type 60)
const ethAddress = await resolver.read.addr([node, 60])

// Get Bitcoin address (coin type 0)
const btcAddress = await resolver.read.addr([node, 0])

// Get Polygon address (coin type 966)
const polygonAddress = await resolver.read.addr([node, 966])
Source: ~/workspace/source/contracts/resolvers/profiles/AddrResolver.sol:47-66

Text Records

Text records store arbitrary key-value data for ENS names.
const node = namehash('example.eth')
const resolver = await viem.getContractAt('PublicResolver', resolverAddress)

// Read text records
const email = await resolver.read.text([node, 'email'])
const url = await resolver.read.text([node, 'url'])
const avatar = await resolver.read.text([node, 'avatar'])
const twitter = await resolver.read.text([node, 'com.twitter'])
Source: ~/workspace/source/contracts/resolvers/profiles/TextResolver.sol:28-33

Common Text Record Keys

  • email - Email address
  • url - Website URL
  • avatar - Avatar image URL or NFT identifier
  • description - Profile description
  • com.twitter - Twitter handle
  • com.github - GitHub username
  • com.discord - Discord username

Setting Records (as Name Owner)

Only the owner of an ENS name (or an authorized operator) can set resolver records.
import { namehash } from 'viem'

const node = namehash('myname.eth')
const resolver = await viem.getContractAt('PublicResolver', resolverAddress)

// Set address
await resolver.write.setAddr([node, ownerAddress])

// Set multi-chain address
await resolver.write.setAddr([node, 60, ethAddressBytes]) // Ethereum

// Set text records
await resolver.write.setText([node, 'email', '[email protected]'])
await resolver.write.setText([node, 'url', 'https://example.com'])

Authorization

The PublicResolver checks authorization before allowing record updates:
function isAuthorised(bytes32 node) internal view returns (bool) {
    address owner = ens.owner(node);
    if (owner == address(nameWrapper)) {
        owner = nameWrapper.ownerOf(uint256(node));
    }
    return
        owner == msg.sender ||
        isApprovedForAll(owner, msg.sender) ||
        isApprovedFor(owner, node, msg.sender);
}
Source: ~/workspace/source/contracts/resolvers/PublicResolver.sol:112-127

Best Practices

Always validate that a resolver is set before attempting to query it. A name without a resolver will return the zero address.
Never hardcode resolver addresses. Always look up the current resolver from the ENS registry, as name owners can change resolvers at any time.

Error Handling

async function resolveENS(name) {
  try {
    const node = namehash(name)
    const resolverAddress = await ensRegistry.read.resolver([node])
    
    if (resolverAddress === zeroAddress) {
      throw new Error('No resolver set for this name')
    }
    
    const resolver = await viem.getContractAt('PublicResolver', resolverAddress)
    const address = await resolver.read.addr([node])
    
    if (address === zeroAddress) {
      throw new Error('No address set for this name')
    }
    
    return address
  } catch (error) {
    console.error('Failed to resolve ENS name:', error)
    throw error
  }
}

Caching Considerations

ENS records can change at any time. Implement appropriate cache invalidation strategies based on your application’s requirements.

Network Deployments

The ENS Registry is deployed at the same address across networks:
  • Mainnet: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e
  • Sepolia: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e

Next Steps

Build docs developers (and LLMs) love