Skip to main content
The BaseRegistrarImplementation contract owns the .eth TLD in the ENS registry and manages .eth name ownership as ERC-721 tokens.

Overview

This contract provides the foundational ownership layer for .eth names:
  • Names are represented as ERC-721 NFTs (tokenId = keccak256(label))
  • Only authorized controllers can register and renew names
  • Name owners have full control over their registrations
  • Includes a 90-day grace period after expiration

Key Concepts

Controllers

Controllers are authorized addresses that can register and renew names. The registrar owner manages controllers:
function addController(address controller) external onlyOwner
function removeController(address controller) external onlyOwner
Controllers can:
  • Register new names
  • Extend the expiry of existing names
Controllers cannot:
  • Reduce expiration times
  • Change ownership of existing names
  • Transfer names they don’t own

Grace Period

The grace period is a 90-day window after expiration:
uint256 public constant GRACE_PERIOD = 90 days;
During the grace period:
  • ownerOf() returns the owner (name is not considered expired)
  • available() returns false (name cannot be registered by others)
  • The owner can renew the name
  • After the grace period ends, the name becomes available for registration

Core Functions

register

Registers a new name (controller only).
function register(
    uint256 id,
    address owner,
    uint256 duration
) external override returns (uint256)
id
uint256
required
The token ID (keccak256 of the label)
owner
address
required
The address that should own the registration
duration
uint256
required
Duration in seconds for the registration
Returns: The expiry timestamp Source: BaseRegistrarImplementation.sol:110

renew

Renews an existing name (controller only).
function renew(
    uint256 id,
    uint256 duration
) external override returns (uint256)
id
uint256
required
The token ID of the name to renew
duration
uint256
required
Additional duration in seconds to add
Returns: The new expiry timestamp Source: BaseRegistrarImplementation.sol:157

available

Checks if a name is available for registration.
function available(uint256 id) public view override returns (bool)
id
uint256
required
The token ID to check
Returns: true if available, false if registered or in grace period Source: BaseRegistrarImplementation.sol:101

nameExpires

Returns the expiration timestamp of a name.
function nameExpires(uint256 id) external view override returns (uint256)
id
uint256
required
The token ID to query
Returns: The expiration timestamp (UNIX timestamp in seconds) Source: BaseRegistrarImplementation.sol:96

reclaim

Reclaims ownership of a name in the ENS registry.
function reclaim(uint256 id, address owner) external override
id
uint256
required
The token ID of the name to reclaim
owner
address
required
The address to set as owner in the registry
Use this function if you own a name in the registrar but lost ownership in the ENS registry (e.g., by transferring it away). Source: BaseRegistrarImplementation.sol:172

ownerOf

Returns the owner of a name (ERC-721 standard).
function ownerOf(uint256 tokenId) public view override returns (address)
tokenId
uint256
required
The token ID to query
Returns: The owner address Reverts: If the name has expired (past grace period) Source: BaseRegistrarImplementation.sol:71

Example Usage

Check Name Availability

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

const baseRegistrar = new ethers.Contract(
  baseRegistrarAddress,
  BaseRegistrarImplementation.abi,
  provider
);

const label = 'myname';
const tokenId = ethers.utils.id(label);

const isAvailable = await baseRegistrar.available(tokenId);
if (isAvailable) {
  console.log('Name is available!');
} else {
  const expires = await baseRegistrar.nameExpires(tokenId);
  console.log(`Name expires at: ${new Date(expires * 1000)}`);
}

Reclaim Registry Ownership

const label = 'myname';
const tokenId = ethers.utils.id(label);

// Reclaim ownership in the ENS registry
const tx = await baseRegistrar.reclaim(tokenId, myAddress);
await tx.wait();

Events

NameRegistered

Emitted when a name is registered.
event NameRegistered(uint256 indexed id, address indexed owner, uint256 expires);

NameRenewed

Emitted when a name is renewed.
event NameRenewed(uint256 indexed id, uint256 expires);

ControllerAdded

Emitted when a controller is added.
event ControllerAdded(address indexed controller);

ControllerRemoved

Emitted when a controller is removed.
event ControllerRemoved(address indexed controller);

Integration Notes

Token ID Calculation

The token ID for a name is always:
const tokenId = ethers.utils.id(label); // keccak256 of the label

ERC-721 Compatibility

As an ERC-721 contract, names can be:
  • Transferred using transferFrom() or safeTransferFrom()
  • Approved for transfer using approve() or setApprovalForAll()
  • Queried for ownership using ownerOf() and balanceOf()

Grace Period Consideration

When checking expiration, remember that ownerOf() will revert after the grace period ends, but the stored expiry timestamp is when the registration period ends, not when the grace period ends.

Build docs developers (and LLMs) love