Skip to main content
The ETHRegistrarController is the primary interface for registering and renewing .eth names. It implements a commit-reveal process to prevent frontrunning and supports resolver configuration during registration.

Overview

Key features:
  • Two-step commit-reveal registration process
  • Configurable resolver and records during registration
  • Support for reverse record setup
  • Length-based pricing via price oracles
  • Minimum registration duration of 28 days

Registration Struct

All registrations use the Registration struct defined in IETHRegistrarController.sol:7:
struct Registration {
    string label;           // The name to register (without .eth)
    address owner;          // The address that will own the name
    uint256 duration;       // Registration duration in seconds
    bytes32 secret;         // Secret value for commit-reveal
    address resolver;       // Resolver address (or address(0))
    bytes[] data;           // Multicall data for resolver setup
    uint8 reverseRecord;    // Bitmask for reverse records
    bytes32 referrer;       // Referrer identifier
}

Field Details

label
string
required
The label to register (e.g., “myname” for myname.eth). Must be 3+ characters.
owner
address
required
The address that will own the registered name.
duration
uint256
required
Registration duration in seconds. Minimum is 28 days.
secret
bytes32
required
A secret value to prevent frontrunning. Use a random 32-byte value.
resolver
address
Address of the resolver contract. Use address(0) for no resolver.
data
bytes[]
Multicall data for setting resolver records. Requires non-zero resolver. Empty array [] if no records to set.
reverseRecord
uint8
Bitmask for reverse record setup:
  • 0 = No reverse record
  • 1 = Set Ethereum reverse record (addr.reverse)
  • 2 = Set default reverse record (default.reverse)
  • 3 = Set both reverse records
referrer
bytes32
Optional referrer identifier for analytics/attribution.

Commit-Reveal Process

Step 1: Make Commitment

Create a commitment hash from your registration parameters.
function makeCommitment(
    Registration calldata registration
) public pure returns (bytes32 commitment)
Source: ETHRegistrarController.sol:210

Step 2: Submit Commitment

Submit the commitment on-chain.
function commit(bytes32 commitment) public
Source: ETHRegistrarController.sol:230 Important: Wait for minCommitmentAge (default: 60 seconds) before registering.

Step 3: Register

After waiting, submit the actual registration.
function register(
    Registration calldata registration
) public payable
Source: ETHRegistrarController.sol:247 Requirements:
  • Commitment must be at least minCommitmentAge old
  • Commitment must be younger than maxCommitmentAge
  • msg.value must be >= total price (base + premium)
  • Name must be available and valid
  • If data is provided, resolver must be non-zero
  • If reverseRecord is non-zero, resolver must be non-zero

Core Functions

rentPrice

Calculates the price for a registration or renewal.
function rentPrice(
    string calldata label,
    uint256 duration
) public view returns (IPriceOracle.Price memory price)
label
string
required
The label to check pricing for
duration
uint256
required
Duration in seconds
Returns: A Price struct with:
  • base: Base price in wei
  • premium: Premium price in wei (for expired names)
Source: ETHRegistrarController.sol:179

available

Checks if a name is available for registration.
function available(string calldata label) public view returns (bool)
label
string
required
The label to check
Returns: true if valid and available, false otherwise Source: ETHRegistrarController.sol:199

renew

Renews an existing name.
function renew(
    string calldata label,
    uint256 duration,
    bytes32 referrer
) external payable
label
string
required
The label to renew
duration
uint256
required
Additional duration in seconds
referrer
bytes32
Optional referrer identifier
Note: Anyone can renew any name, not just the owner. Premium is not charged for renewals. Source: ETHRegistrarController.sol:352

valid

Checks if a label is valid for registration.
function valid(string calldata label) public pure returns (bool)
label
string
required
The label to validate
Returns: true if the label is 3+ characters, false otherwise Source: ETHRegistrarController.sol:191

Example Usage

Basic Registration

import { ethers } from 'ethers';
import { ETHRegistrarController } from '@ensdomains/ens-contracts';

const controller = new ethers.Contract(
  controllerAddress,
  ETHRegistrarController.abi,
  signer
);

// Step 1: Create registration parameters
const registration = {
  label: 'myname',
  owner: await signer.getAddress(),
  duration: 31536000, // 1 year in seconds
  secret: ethers.utils.randomBytes(32),
  resolver: ethers.constants.AddressZero,
  data: [],
  reverseRecord: 0,
  referrer: ethers.constants.HashZero
};

// Step 2: Make and submit commitment
const commitment = await controller.makeCommitment(registration);
const commitTx = await controller.commit(commitment);
await commitTx.wait();

// Step 3: Wait for minimum commitment age (60 seconds)
await new Promise(resolve => setTimeout(resolve, 60000));

// Step 4: Get price
const price = await controller.rentPrice(registration.label, registration.duration);
const totalPrice = price.base.add(price.premium);

// Step 5: Register
const registerTx = await controller.register(registration, {
  value: totalPrice
});
await registerTx.wait();

console.log('Registration complete!');

Registration with Resolver and Records

import { ethers } from 'ethers';

// Assume we have controller and resolver contracts initialized

const registration = {
  label: 'myname',
  owner: await signer.getAddress(),
  duration: 31536000,
  secret: ethers.utils.randomBytes(32),
  resolver: resolverAddress,
  data: [
    // Set ETH address
    resolver.interface.encodeFunctionData('setAddr', [
      namehash,
      await signer.getAddress()
    ]),
    // Set text record
    resolver.interface.encodeFunctionData('setText', [
      namehash,
      'com.twitter',
      '@myhandle'
    ])
  ],
  reverseRecord: 3, // Set both Ethereum and default reverse records
  referrer: ethers.constants.HashZero
};

// Commit
const commitment = await controller.makeCommitment(registration);
await (await controller.commit(commitment)).wait();

// Wait 60 seconds...
await new Promise(resolve => setTimeout(resolve, 60000));

// Register
const price = await controller.rentPrice(registration.label, registration.duration);
await controller.register(registration, {
  value: price.base.add(price.premium)
});

Renew a Name

const label = 'myname';
const duration = 31536000; // 1 year

const price = await controller.rentPrice(label, duration);

const tx = await controller.renew(label, duration, ethers.constants.HashZero, {
  value: price.base // No premium for renewals
});
await tx.wait();

Events

NameRegistered

Emitted when a name is successfully registered.
event NameRegistered(
    string label,
    bytes32 indexed labelhash,
    address indexed owner,
    uint256 baseCost,
    uint256 premium,
    uint256 expires,
    bytes32 referrer
);
Source: ETHRegistrarController.sol:116

NameRenewed

Emitted when a name is renewed.
event NameRenewed(
    string label,
    bytes32 indexed labelhash,
    uint256 cost,
    uint256 expires,
    bytes32 referrer
);
Source: ETHRegistrarController.sol:133

Constants

MIN_REGISTRATION_DURATION

Minimum duration for a registration: 28 days (2,419,200 seconds) Source: ETHRegistrarController.sol:33

Reverse Record Bitmasks

uint8 constant REVERSE_RECORD_ETHEREUM_BIT = 1;  // addr.reverse
uint8 constant REVERSE_RECORD_DEFAULT_BIT = 2;   // default.reverse
Source: ETHRegistrarController.sol:27-30

Error Reference

CommitmentNotFound

No commitment found for the provided hash.

CommitmentTooNew

Commitment exists but hasn’t aged past minCommitmentAge.

CommitmentTooOld

Commitment has expired (older than maxCommitmentAge).

NameNotAvailable

The requested name is not available for registration.

DurationTooShort

Registration duration is less than MIN_REGISTRATION_DURATION.

ResolverRequiredWhenDataSupplied

Cannot set resolver data without specifying a resolver address.

ResolverRequiredForReverseRecord

Cannot set reverse record without specifying a resolver address.

InsufficientValue

msg.value is less than the required price.

UnexpiredCommitmentExists

A valid commitment already exists for this hash.

Build docs developers (and LLMs) love