ENS Development Support
Comprehensive toolkit for building applications with Ethereum Name Service (ENS) - the decentralized naming protocol that converts addresses into human-readable names like "vitalik.eth".
Quick Start
Core Concepts
ENS converts complex addresses into memorable names across the entire Web3 ecosystem. Understanding the key components is essential:
Name Resolution Flow:
ENS Name (vitalik.eth) ↓ Registry lookup ENS Registry (finds resolver) ↓ Resolver query Resolver Contract (returns address) ↓ Result Ethereum Address (0xd8dA...)
Key decision points:
- •Register .eth names → ETH Registrar Controller (annual registration)
- •Resolve names to addresses → Universal Resolver (supports all resolution types)
- •Create subdomains → Registry + Resolver (owner can create infinite subdomains)
- •Add profile data → Public Resolver (avatars, URLs, social handles)
- •Manage permissions → Name Wrapper (programmable ownership with fuses)
- •Integrate DNS domains → DNSSEC Oracle (import traditional domains)
- •Support L2/multichain → CCIP Read (ERC-3668 for offchain resolution)
- •Address to name lookup → Reverse Resolver (.addr.reverse)
Common Tasks
1. Resolve ENS name to address:
- •Review basic_resolution.ts for simple name resolution
- •Key points: Universal Resolver usage, normalization, error handling
- •See resolution-guide.md for advanced patterns
2. Register .eth domain:
- •Use registration_example.ts for commit-reveal flow
- •Alternative: Use ENS Manager App at https://ens.app for UI-based registration
- •See registration-guide.md for pricing and flow details
3. Create and manage subdomains:
- •Use subdomain_creation.ts for programmatic subdomain creation
- •Configure permissions with Name Wrapper for granular control
- •See subdomains-guide.md for architecture patterns
4. Set avatar and profile records:
- •Start with profile_records.ts for avatar, URL, social records
- •Supports NFT avatars via EIP-634 format
- •See records-guide.md for all record types
5. Integrate with smart contracts:
- •Use contract_integration.sol for Solidity integration
- •Key pattern: Query resolver for specific record types
- •See contracts-guide.md for gas optimization
6. Enable multichain resolution:
- •Implement ccip_read_example.ts for L2/offchain resolution
- •Test with "test.offchaindemo.eth" (resolves to 0x779981590E7Ccc0CFAe8040Ce7151324747cDb97)
- •See multichain-guide.md for CCIP Read implementation
Core Workflows
Name Resolution
Basic Resolution (viem v2.35.0+):
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
import { normalize } from 'viem/ens';
// 1. Initialize client
const client = createPublicClient({
chain: mainnet,
transport: http()
});
// 2. Resolve name to address
const address = await client.getEnsAddress({
name: normalize('vitalik.eth')
});
// Returns: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
// 3. Reverse resolution (address to name)
const name = await client.getEnsName({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
});
// Returns: vitalik.eth
Advanced Resolution with Universal Resolver:
import { createPublicClient, http, namehash } from 'viem';
import { mainnet } from 'viem/chains';
const client = createPublicClient({
chain: mainnet,
transport: http()
});
// Universal Resolver address (automatically used by viem)
const UNIVERSAL_RESOLVER = '0xeEeEEEeE14D718C2B47D9923Deab1335E144EeEe';
// Resolve multiple record types
const avatar = await client.getEnsAvatar({ name: normalize('vitalik.eth') });
const text = await client.getEnsText({
name: normalize('vitalik.eth'),
key: 'com.twitter'
});
const contentHash = await client.getEnsText({
name: normalize('vitalik.eth'),
key: 'contentHash'
});
With ethers.js:
import { ethers } from 'ethers';
const provider = new ethers.JsonRpcProvider('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY');
// Forward resolution
const address = await provider.resolveName('vitalik.eth');
// Reverse resolution
const name = await provider.lookupAddress('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
// Get resolver for advanced queries
const resolver = await provider.getResolver('vitalik.eth');
const avatar = await resolver.getAvatar();
const twitter = await resolver.getText('com.twitter');
See basic_resolution.ts for complete implementation.
.eth Domain Registration
.eth registration uses a commit-reveal pattern to prevent front-running:
import { createWalletClient, http, namehash } from 'viem';
import { mainnet } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';
const account = privateKeyToAccount('0x...');
const client = createWalletClient({
account,
chain: mainnet,
transport: http()
});
// Contract addresses
const ETH_REGISTRAR_CONTROLLER = '0x59E16fcCd424Cc24e280Be16E11Bcd56fb0CE547';
// 1. Check name availability
const name = 'myname';
const available = await publicClient.readContract({
address: ETH_REGISTRAR_CONTROLLER,
abi: registrarAbi,
functionName: 'available',
args: [name]
});
if (!available) throw new Error('Name not available');
// 2. Make commitment
const commitment = await publicClient.readContract({
address: ETH_REGISTRAR_CONTROLLER,
abi: registrarAbi,
functionName: 'makeCommitment',
args: [name, account.address, duration, secret, resolver, [], false, 0]
});
const commitTx = await client.writeContract({
address: ETH_REGISTRAR_CONTROLLER,
abi: registrarAbi,
functionName: 'commit',
args: [commitment]
});
// 3. Wait minimum 60 seconds (anti-front-running)
await new Promise(resolve => setTimeout(resolve, 60000));
// 4. Register name (requires ETH payment)
const price = await publicClient.readContract({
address: ETH_REGISTRAR_CONTROLLER,
abi: registrarAbi,
functionName: 'rentPrice',
args: [name, duration]
});
const registerTx = await client.writeContract({
address: ETH_REGISTRAR_CONTROLLER,
abi: registrarAbi,
functionName: 'register',
args: [name, account.address, duration, secret, resolver, [], false, 0],
value: price.base + price.premium
});
Pricing (as of ENSv2):
- •5+ characters: $5/year
- •4 characters: $160/year
- •3 characters: $640/year
Grace Period: 90 days after expiration with 21-day declining premium
See registration_example.ts for complete flow.
Subdomain Creation & Management
Creating Subdomains (Domain Owner):
import { createWalletClient, http, namehash } from 'viem';
import { mainnet } from 'viem/chains';
const client = createWalletClient({
account,
chain: mainnet,
transport: http()
});
const ENS_REGISTRY = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e';
const PUBLIC_RESOLVER = '0xF29100983E058B709F3D539b0c765937B804AC15';
// 1. Create subdomain (you must own parent domain)
const parentNode = namehash('mydomain.eth');
const label = 'sub'; // Creates sub.mydomain.eth
const labelHash = keccak256(toBytes(label));
// Set subdomain owner in registry
await client.writeContract({
address: ENS_REGISTRY,
abi: registryAbi,
functionName: 'setSubnodeOwner',
args: [parentNode, labelHash, newOwnerAddress]
});
// 2. Configure resolver for subdomain
const subdomainNode = namehash('sub.mydomain.eth');
await client.writeContract({
address: ENS_REGISTRY,
abi: registryAbi,
functionName: 'setResolver',
args: [subdomainNode, PUBLIC_RESOLVER]
});
// 3. Set address record in resolver
await client.writeContract({
address: PUBLIC_RESOLVER,
abi: resolverAbi,
functionName: 'setAddr',
args: [subdomainNode, targetAddress]
});
Using Name Wrapper for Permission Control:
const NAME_WRAPPER = '0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401';
// Wrap name to enable fuses
await client.writeContract({
address: NAME_WRAPPER,
abi: wrapperAbi,
functionName: 'wrapETH2LD',
args: ['mydomain', account.address, 0, ethers.ZeroAddress]
});
// Create subdomain with custom permissions
const PARENT_CANNOT_CONTROL = 1 << 16; // Parent can't modify
const CANNOT_TRANSFER = 1 << 1; // Name can't be transferred
await client.writeContract({
address: NAME_WRAPPER,
abi: wrapperAbi,
functionName: 'setSubnodeOwner',
args: [
parentNode,
'sub',
newOwner,
PARENT_CANNOT_CONTROL | CANNOT_TRANSFER,
expiry
]
});
See subdomain_creation.ts for production patterns.
Avatar & Profile Records
Setting Profile Records:
import { createWalletClient, http, namehash } from 'viem';
const PUBLIC_RESOLVER = '0xF29100983E058B709F3D539b0c765937B804AC15';
const node = namehash('myname.eth');
// 1. Set avatar (supports multiple formats)
// NFT avatar: eip155:1/erc721:0x... or eip155:1/erc1155:0x.../1
await client.writeContract({
address: PUBLIC_RESOLVER,
abi: resolverAbi,
functionName: 'setText',
args: [node, 'avatar', 'eip155:1/erc721:0xb7F7F6C52F2e2fdb1963Eab30438024864c313F6/2430']
});
// IPFS avatar: ipfs://...
await client.writeContract({
address: PUBLIC_RESOLVER,
abi: resolverAbi,
functionName: 'setText',
args: [node, 'avatar', 'ipfs://QmY...']
});
// 2. Set social records
const records = {
'com.twitter': 'vitalikbuterin',
'com.github': 'vbuterin',
'url': 'https://vitalik.eth.limo',
'email': 'vitalik@ethereum.org',
'description': 'Ethereum co-founder'
};
for (const [key, value] of Object.entries(records)) {
await client.writeContract({
address: PUBLIC_RESOLVER,
abi: resolverAbi,
functionName: 'setText',
args: [node, key, value]
});
}
// 3. Set content hash (for decentralized websites)
await client.writeContract({
address: PUBLIC_RESOLVER,
abi: resolverAbi,
functionName: 'setContenthash',
args: [node, contentHash] // IPFS or Swarm hash
});
// 4. Set multiple coin addresses (multichain)
// Ethereum (coinType: 60)
await client.writeContract({
address: PUBLIC_RESOLVER,
abi: resolverAbi,
functionName: 'setAddr',
args: [node, 60, ethAddressBytes]
});
// Bitcoin (coinType: 0)
await client.writeContract({
address: PUBLIC_RESOLVER,
abi: resolverAbi,
functionName: 'setAddr',
args: [node, 0, btcAddressBytes]
});
See profile_records.ts for all record types.
Smart Contract Integration
Query ENS in Solidity:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IENSRegistry {
function resolver(bytes32 node) external view returns (address);
}
interface IResolver {
function addr(bytes32 node) external view returns (address);
}
contract ENSIntegration {
IENSRegistry public immutable ens;
constructor(address _ens) {
ens = IENSRegistry(_ens);
}
function resolve(bytes32 node) public view returns (address) {
address resolver = ens.resolver(node);
if (resolver == address(0)) return address(0);
return IResolver(resolver).addr(node);
}
function sendToENSName(bytes32 node) external payable {
address recipient = resolve(node);
require(recipient != address(0), "ENS name not found");
(bool success, ) = recipient.call{value: msg.value}("");
require(success, "Transfer failed");
}
}
Using @ensdomains/ens-contracts package:
pragma solidity ^0.8.19;
import "@ensdomains/ens-contracts/contracts/registry/ENS.sol";
import "@ensdomains/ens-contracts/contracts/resolvers/PublicResolver.sol";
contract MyContract {
ENS public ens;
constructor(ENS _ens) {
ens = _ens;
}
function getAddress(bytes32 node) public view returns (address) {
address resolverAddr = ens.resolver(node);
if (resolverAddr == address(0)) return address(0);
PublicResolver resolver = PublicResolver(resolverAddr);
return resolver.addr(node);
}
}
See contract_integration.sol for production template.
Multichain Resolution (CCIP Read)
CCIP Read (ERC-3668) for L2 and Offchain Resolution:
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
const client = createPublicClient({
chain: mainnet,
transport: http(),
// CCIP Read is automatically supported in viem 2.35.0+
});
// Resolve L2/offchain ENS name
const address = await client.getEnsAddress({
name: normalize('test.offchaindemo.eth')
});
// Should resolve to: 0x779981590E7Ccc0CFAe8040Ce7151324747cDb97
// even though data is stored on L2 or offchain
// Query offchain text records
const twitter = await client.getEnsText({
name: normalize('l2name.eth'),
key: 'com.twitter'
});
Implementing Custom CCIP Read Resolver:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IOffchainResolver {
error OffchainLookup(
address sender,
string[] urls,
bytes callData,
bytes4 callbackFunction,
bytes extraData
);
function resolve(bytes calldata name, bytes calldata data)
external
view
returns (bytes memory);
}
contract CCIPReadResolver is IOffchainResolver {
string[] public urls;
constructor(string[] memory _urls) {
urls = _urls;
}
function resolve(bytes calldata name, bytes calldata data)
external
view
returns (bytes memory)
{
revert OffchainLookup(
address(this),
urls,
data,
this.resolveWithProof.selector,
abi.encode(name, data)
);
}
function resolveWithProof(bytes calldata response, bytes calldata extraData)
external
view
returns (bytes memory)
{
// Verify offchain data and return result
// Implementation depends on your L2/offchain storage
}
}
See ccip_read_example.ts for complete implementation.
Critical Security Requirements
Never deploy without:
- •Name Normalization: Always use UTS-46 normalization before processing names
- •Input Validation: Validate ENS names match expected format (no homograph attacks)
- •Address Verification: Display both name AND address in transaction UIs
- •Resolver Verification: Check resolver is trusted before using its data
- •Expiry Checks: Verify name hasn't expired before critical operations
- •Reverse Record Validation: Confirm reverse record matches forward resolution
- •CCIP Read Security: Validate offchain data signatures and sources
- •Private Key Protection: Never expose private keys when setting records
UI Best Practices:
- •Show both "vitalik.eth" AND "0xd8d..." in transaction confirmations
- •Implement debouncing for ENS input fields (300-500ms)
- •Display warning if name will expire soon (<30 days)
- •Check reverse record is set before displaying name in place of address
See security.md for complete checklist.
Architecture Patterns
ENS Protocol Architecture
┌─────────────────────────────────────────────┐
│ Application Layer │
│ (Your dApp, Wallet, Smart Contract) │
└─────────────────┬───────────────────────────┘
│
┌─────────────────▼───────────────────────────┐
│ Universal Resolver (v2) │
│ (Handles all resolution, CCIP Read) │
└─────────────────┬───────────────────────────┘
│
┌───────────┴───────────┐
│ │
┌─────▼─────────┐ ┌────────▼────────┐
│ ENS Registry │ │ Resolvers │
│ (Ownership) │ │ (Data Storage) │
└─────┬─────────┘ └────────┬────────┘
│ │
┌─────▼─────────────────────┬─▼────────┐
│ Registrars │ Records │
│ (.eth, DNS, etc.) │ (Addr, │
│ │ Text, │
│ Name Wrapper │ Content)│
│ (Permissions/Fuses) │ │
└───────────────────────────┴───────────┘
Name States & Wrapped Names
Unwrapped → Wrapped → Emancipated → Locked:
- •Unwrapped: Traditional ENS ownership (mutable, no fuses)
- •Wrapped: Converted to ERC-1155 NFT (fuses can be set)
- •Emancipated: Parent cannot control (PARENT_CANNOT_CONTROL burned)
- •Locked: Name locked permanently (CANNOT_UNWRAP burned)
Fuse Types:
- •Parent-Controlled: Grant "perks" (e.g., CAN_EXTEND_EXPIRY)
- •Owner-Controlled: Restrict "permissions" (e.g., CANNOT_TRANSFER)
See name-wrapper-guide.md for complete fuse reference.
Resolution Flow
// Modern approach with Universal Resolver (automatically handles all cases)
const address = await client.getEnsAddress({ name: normalize('name.eth') });
// Traditional approach (manual registry + resolver lookup)
const registry = getContract({ address: ENS_REGISTRY, abi: registryAbi, client });
const resolverAddress = await registry.read.resolver([namehash('name.eth')]);
const resolver = getContract({ address: resolverAddress, abi: resolverAbi, client });
const address = await resolver.read.addr([namehash('name.eth')]);
Development Setup
Dependencies
For TypeScript/JavaScript:
# viem (recommended for ENSv2) npm install viem # ethers.js (v6+) npm install ethers # wagmi (for React) npm install wagmi viem # ENS contracts (for Solidity integration) npm install @ensdomains/ens-contracts # ENS utilities npm install @ensdomains/ensjs
For Solidity:
# Foundry forge install ensdomains/ens-contracts # Hardhat npm install @ensdomains/ens-contracts
Contract Addresses
Mainnet:
- •ENS Registry:
0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e - •Base Registrar (.eth):
0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85 - •ETH Registrar Controller:
0x59E16fcCd424Cc24e280Be16E11Bcd56fb0CE547 - •Public Resolver:
0xF29100983E058B709F3D539b0c765937B804AC15 - •Universal Resolver:
0xeEeEEEeE14D718C2B47D9923Deab1335E144EeEe - •Name Wrapper:
0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401 - •Reverse Registrar:
0xa58E81fe9b61B5c3fE2AFD33CF304c454AbFc7Cb
Sepolia Testnet:
- •ENS Registry:
0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e - •ETH Registrar Controller:
0xfb3cE5D01e0f33f41DbB39035dB9745962F1f968 - •Public Resolver:
0xE99638b40E4Fff0129D56f03b55b6bbC4BBE49b5
See deployments.md for complete list.
React Integration (wagmi)
import { useEnsAddress, useEnsAvatar, useEnsName } from 'wagmi';
import { normalize } from 'viem/ens';
function ENSProfile({ name }: { name: string }) {
const { data: address } = useEnsAddress({ name: normalize(name) });
const { data: avatar } = useEnsAvatar({ name: normalize(name) });
const { data: ensName } = useEnsName({ address });
return (
<div>
<img src={avatar} alt={name} />
<p>{name} → {address}</p>
<p>Reverse: {ensName}</p>
</div>
);
}
Testing
Library Testing (TypeScript)
import { expect } from 'chai';
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
import { normalize } from 'viem/ens';
describe('ENS Resolution', () => {
const client = createPublicClient({
chain: mainnet,
transport: http()
});
it('should resolve vitalik.eth correctly', async () => {
const address = await client.getEnsAddress({
name: normalize('vitalik.eth')
});
expect(address).to.equal('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
});
it('should handle reverse resolution', async () => {
const name = await client.getEnsName({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
});
expect(name).to.equal('vitalik.eth');
});
});
Smart Contract Testing (Foundry)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "@ensdomains/ens-contracts/contracts/registry/ENS.sol";
import "@ensdomains/ens-contracts/contracts/resolvers/PublicResolver.sol";
contract ENSIntegrationTest is Test {
ENS ens;
PublicResolver resolver;
function setUp() public {
// Fork mainnet
vm.createSelectFork(vm.envString("ETH_RPC_URL"));
ens = ENS(0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e);
resolver = PublicResolver(0xF29100983E058B709F3D539b0c765937B804AC15);
}
function testResolveVitalik() public view {
bytes32 node = 0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835;
address resolverAddr = ens.resolver(node);
assertEq(resolverAddr, address(resolver));
address addr = PublicResolver(resolverAddr).addr(node);
assertEq(addr, 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045);
}
}
Common Pitfalls
- •Missing Normalization: Always normalize names with UTS-46 before hashing
- •Direct Registry Queries: Use Universal Resolver instead of manual registry lookups
- •Hardcoded Resolver: Don't assume Public Resolver - always query from registry
- •Namehash Errors: Use library functions for namehash - manual implementation is error-prone
- •Reverse Record Assumptions: Not all addresses have reverse records set
- •Expiry Ignorance: Check expiry before trusting resolution in critical paths
- •CCIP Read Timeout: Offchain resolution can be slow - implement proper timeout handling
- •Homograph Attacks: Validate input to prevent look-alike character exploitation
- •Missing ENSv2 Support: Update to viem 2.35.0+ or ethers v6+ for Universal Resolver
- •Gas Optimization: Batch resolver queries when fetching multiple records
ENSv2 Migration Checklist
For App Developers:
- •✅ Update viem to v2.35.0+ or ethers to v6+
- •✅ Use Universal Resolver (automatic with updated libraries)
- •✅ Test with "test.offchaindemo.eth" for CCIP Read support
- •✅ Handle CCIP Read timeouts gracefully
- •✅ Display both name and address in UIs
For Resolver Developers:
- •✅ Implement ERC-3668 (CCIP Read) for offchain data
- •✅ Support wildcard resolution if needed
- •✅ Add proper signature verification for offchain responses
- •✅ Test with Universal Resolver
For Subname Operators:
- •✅ Consider wrapping names for permission management
- •✅ Set appropriate fuses for subdomain distribution
- •✅ Document subdomain expiry policies
- •✅ Implement subdomain marketplace if needed
Resources
Official Documentation
- •Main Docs: https://docs.ens.domains/
- •Protocol Overview: https://docs.ens.domains/learn/protocol
- •Deployments: https://docs.ens.domains/learn/deployments
- •FAQ: https://docs.ens.domains/faq
- •LLM Context: https://docs.ens.domains/llms-full.txt
Code Repositories
- •ENS Contracts: https://github.com/ensdomains/ens-contracts
- •ENS App v3: https://github.com/ensdomains/ens-app-v3
- •ENS Docs: https://github.com/ensdomains/docs
- •Main GitHub: https://github.com/ensdomains
Tools & Services
- •ENS Manager: https://ens.app (register and manage names)
- •ENSv2 Info: https://ens.domains/ensv2
- •Main Site: https://ens.domains/
Support
- •Bug Bounty: Immunefi - up to $250K for critical bugs
- •GitHub Issues: https://github.com/ensdomains/ens-contracts/issues
- •Documentation Issues: https://github.com/ensdomains/docs/issues
Bundled Resources
Scripts
- •basic_resolution.ts: Complete name resolution examples
- •registration_example.ts: .eth domain registration flow
- •subdomain_creation.ts: Subdomain creation and management
- •profile_records.ts: Avatar and profile record management
- •ccip_read_example.ts: Multichain/L2 resolution implementation
References
- •resolution-guide.md: Complete resolution patterns
- •registration-guide.md: Registration pricing and process
- •subdomains-guide.md: Subdomain architecture patterns
- •records-guide.md: All record types and formats
- •contracts-guide.md: Smart contract integration patterns
- •multichain-guide.md: CCIP Read and L2 resolution
- •name-wrapper-guide.md: Name Wrapper and fuse reference
- •security.md: Security best practices
- •deployments.md: All contract addresses
Assets
- •contract-integration-template.sol: Production Solidity template
- •resolver-implementation.sol: Custom resolver template
Support Context7 Integration
When the user needs up-to-date documentation or specific implementation details:
- •Use ENS official docs as primary source: https://docs.ens.domains/
- •For smart contract details: @ensdomains/ens-contracts on GitHub
- •For library-specific questions: Use Context7 with viem or ethers.js
- •Combine Context7 results with this skill's security guidelines
Example:
User: "How do I implement wildcard resolution?" → Check ENS docs for EIP-2544 (wildcard resolution) → Use Context7: query-docs with "@ensdomains/ens-contracts" for contract examples → Apply security patterns from security.md
Name Wrapper Fuse Reference
Owner-Controlled Fuses (Restrict Permissions)
- •
CANNOT_UNWRAP(0x01): Prevent unwrapping to traditional ENS - •
CANNOT_BURN_FUSES(0x02): No more fuses can be burned - •
CANNOT_TRANSFER(0x04): Name cannot be transferred - •
CANNOT_SET_RESOLVER(0x08): Resolver cannot be changed - •
CANNOT_SET_TTL(0x10): TTL cannot be modified - •
CANNOT_CREATE_SUBDOMAIN(0x20): Cannot create new subdomains - •
CANNOT_APPROVE(0x40): Cannot approve name transfers
Parent-Controlled Fuses (Grant Perks)
- •
PARENT_CANNOT_CONTROL(0x10000): Parent loses control (emancipation) - •
CAN_EXTEND_EXPIRY(0x40000): Subdomain owner can extend expiry
Common Fuse Patterns
Locked Forever:
const LOCKED = CANNOT_UNWRAP | CANNOT_BURN_FUSES | PARENT_CANNOT_CONTROL;
Transferable but Locked:
const TRANSFERABLE_LOCKED = CANNOT_UNWRAP | CANNOT_BURN_FUSES;
Fully Controlled Subdomain:
const EMANCIPATED = PARENT_CANNOT_CONTROL | CAN_EXTEND_EXPIRY;
DNS Integration
ENS supports importing traditional DNS domains via DNSSEC:
Supported TLDs: .com, .org, .net, .io, .app, and 200+ more
Integration Flow:
- •Add DNSSEC to your DNS domain
- •Create TXT record:
_ens.yourdomain.com→a=0xYourAddress - •Import to ENS via Manager App or contract call
- •Manage DNS domain like native .eth name
Benefits:
- •Use existing domain on ENS
- •Full ENS feature support (records, subdomains, etc.)
- •Bridge Web2 and Web3 identity
See ENS documentation for complete DNSSEC setup guide.