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
The label to register (e.g., “myname” for myname.eth). Must be 3+ characters.
The address that will own the registered name.
Registration duration in seconds. Minimum is 28 days.
A secret value to prevent frontrunning. Use a random 32-byte value.
Address of the resolver contract. Use address(0) for no resolver.
Multicall data for setting resolver records. Requires non-zero resolver. Empty array [] if no records to set.
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
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)
The label to check pricing for
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)
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
Additional duration in seconds
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)
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.