Skip to main content

Overview

The UniversalResolverV2 contract extends the ENS Universal Resolver functionality to support the ENS v2 multi-registry architecture. It provides methods to find resolvers, registries, and canonical names across the hierarchical registry structure. Contract Address: Deploy-specific (immutable ROOT_REGISTRY) Inherits: AbstractUniversalResolver

Constructor

constructor(
    IRegistry root,
    IGatewayProvider batchGatewayProvider
)
Initializes the UniversalResolverV2 with a root registry and gateway provider.
root
IRegistry
required
The root registry contract that anchors the registry hierarchy
batchGatewayProvider
IGatewayProvider
required
Gateway provider for batch CCIP-Read operations

Read Functions

findCanonicalName

function findCanonicalName(IRegistry registry) external view returns (bytes memory)
Constructs the canonical DNS-encoded name for a given registry by traversing up the registry hierarchy.
registry
IRegistry
required
The registry contract to construct a name for
return
bytes
The DNS-encoded canonical name, or empty bytes if the registry is not canonical
Example:
// Get canonical name for a registry
IRegistry ethRegistry = rootRegistry.getSubregistry("eth");
bytes memory name = resolver.findCanonicalName(ethRegistry);
// Returns DNS-encoded "eth" (0x03657468 + 0x00)

findCanonicalRegistry

function findCanonicalRegistry(bytes calldata name) external view returns (IRegistry)
Finds the canonical registry for a DNS-encoded name. Returns the registry only if it is the canonical registry for that exact name.
name
bytes
required
The DNS-encoded name to look up (e.g., “vitalik.eth” as DNS-encoded bytes)
return
IRegistry
The canonical registry contract, or null (address(0)) if not found or not canonical
Example:
// Find the canonical registry for "eth"
bytes memory ethName = hex"036574680000"; // DNS-encoded "eth"
IRegistry ethRegistry = resolver.findCanonicalRegistry(ethName);

if (address(ethRegistry) != address(0)) {
    // Registry found and is canonical
}

findRegistries

function findRegistries(bytes calldata name) external view returns (IRegistry[] memory)
Finds all registries in the ancestry of a name, from most specific to root.
name
bytes
required
The DNS-encoded name to traverse
return
IRegistry[]
Array of registries in label-order, from the name to the root. Null entries indicate missing registries.
Behavior Examples:
  • findRegistries("") returns [<root>]
  • findRegistries("eth") returns [<eth>, <root>]
  • findRegistries("vitalik.eth") returns [<vitalik>, <eth>, <root>]
  • findRegistries("sub.vitalik.eth") returns [null, <vitalik>, <eth>, <root>] if “sub” doesn’t exist
Example:
// Get all registries for a name
bytes memory name = dnsEncode("vitalik.eth");
IRegistry[] memory registries = resolver.findRegistries(name);

for (uint i = 0; i < registries.length; i++) {
    if (address(registries[i]) != address(0)) {
        // Process each registry in the hierarchy
    }
}

findResolver

function findResolver(
    bytes memory name
) public view returns (
    address resolver,
    bytes32 node,
    uint256 offset
)
Finds the resolver address for a given name by traversing the registry hierarchy.
name
bytes
required
The DNS-encoded name to resolve
resolver
address
The resolver contract address, or address(0) if not found
node
bytes32
The namehash of the name
offset
uint256
The offset into the name where the resolver was found
Example:
// Find resolver for a name
bytes memory name = dnsEncode("vitalik.eth");
(address resolverAddr, bytes32 node, uint256 offset) = universalResolver.findResolver(name);

if (resolverAddr != address(0)) {
    // Use the resolver
    IResolver resolver = IResolver(resolverAddr);
    address ethAddr = resolver.addr(node);
}

Public State Variables

ROOT_REGISTRY

IRegistry public immutable ROOT_REGISTRY
The root registry that anchors the entire ENS v2 registry hierarchy. This is set during contract construction and cannot be changed.

Integration Example

// Complete workflow: resolve a name to an Ethereum address
contract ENSClient {
    UniversalResolverV2 public universalResolver;
    
    function resolveAddress(string memory ensName) public view returns (address) {
        // 1. DNS-encode the name
        bytes memory dnsName = dnsEncode(ensName);
        
        // 2. Find the resolver
        (address resolverAddr, bytes32 node,) = universalResolver.findResolver(dnsName);
        require(resolverAddr != address(0), "No resolver found");
        
        // 3. Query the resolver for the address
        IAddrResolver resolver = IAddrResolver(resolverAddr);
        return resolver.addr(node);
    }
    
    function dnsEncode(string memory name) internal pure returns (bytes memory) {
        // DNS encoding implementation
        // e.g., "vitalik.eth" -> 0x0776697461 6c696b036574680000
    }
}
  • IRegistry: Registry interface for ENS v2 hierarchical registries
  • AbstractUniversalResolver: Base universal resolver implementation
  • LibRegistry: Library providing registry traversal utilities
  • IGatewayProvider: Gateway provider for CCIP-Read operations

Build docs developers (and LLMs) love