The ETH Registrar is a special registrar. It allows for trustless on-chain name registration and is in charge of the ".eth" TLD.
.com.xyz.nl.net.org.shop.photos.pizza.cash.money.news.info.gold.domains.social.de.city.lol.rip.company.es.network.me.us.id.fr.space.ninja.tools.wtf.capital.finance.vision.limo.link.uk.world.dev.day.fyi.cooland any other DNSSEC-compatible domain...
The ETH Registrar is split into two contracts. The BaseRegistrar and the ETHRegistrarController.The BaseRegistrar is responsible for name ownership, transfers, etc (ownership related),while the Controller is responsible for registration & renewal (pricing related).This separation is done to reduce the attack surface of the registrar, and provides users with the guarantees of continued ownership of a name so long as the registrar is in place.
Controllers
The ETHRegistrarController is the main controller for the ETH Registrar, and provides a straightforward registration and renewal mechanism.
Pricing Structure
The ETH Registrar charges a fee for registration.This fee is paid in ETH and is set to prevent spamming the registrar.Any protocol fees are sent to the ENS Treasury.
Pricing Oracle
Initially, a single pricing oracle was deployed, the StablePriceOracle.This contract has owner-set prices for each name length (1, 2, 3, 4, 5 or more).Users do not have to interact with this oracle directly, as the controller provides functionality to determine the pricing for a registration or renewal.
3, 4, and 5 Letter Names
The ETH Registrar has special pricing for 3, 4, and 5 (and more) letter names. At the time of writing, a 5+
letter .eth
will cost you 5 USD
per year.A 4
letter 160 USD
per year, and a 3
letter 640 USD
per year.This pricing structure is done to promote market diversity as there are an exponentially less amount of names the shorter they become.The minimum length of a name is 3 characters.
Name Length | Price (USD) |
---|---|
5+ | 5 |
4 | 160 |
3 | 640 |
Premium & Auctions
In addition to length-based pricing the ETH Registrar also has a premium pricing structure.90 days after a name expires (aka after the grace period), the name will go into a Temporary Premium Auction.The Auction is a 21 day dutch auction, meaning that the price starts high (~100 Million USD) and exponentially decrease till it hits 0 or a bid goes through.
This is done to prevent sniping of names, and ensures the name goes to the highest bidder fairly.
You can read more about the temporary premium in this article.
Where does the money go?
Upon registration funds are sent to the ETHRegistrarController. The controller then sends the funds to the ENS Treasury (anyone can call the withdraw
method to trigger this).Income from the ETH Registrar is used to fund the development of ENS, its ecosystem, and other public goods.
Read more about our spending in Article III of the Constitution.
In the early days of ENS, the ERC721 standard did not exist.The original ETH Registrar formed the pre-cursor to the ERC721 standard.As we witnessed the ERC721 being standardized support for it was added to the ETH Registrar.
Today, users can interact with the ETH Registrar to transfer their name just like with any other ERC721 token.
Registering a Name
To register a name you can use the ENS Manager App, ENS Fairy, your favourite mobile wallet (if supported), or any other frontend you like.If you would like to register a name through a smart contract, or your own interface, you can use the following functions.
For the process of .eth
name registration the ETH Registrar uses a two transaction commit reveal process.
Commit
Wait
Reveal
Commit Reveal
The ETHRegistrarController implements a commit reveal scheme to prevent frontrunning.The way it works is that during the registration process we first call the commit
function with an opaque bit of data (the commitmenthash
).Wait a few blocks and then call the register
function.
The commit
function takes a commitment hash, which can be generated using the makeCommitment
function. The commitment hash is opaque and revealed during the register
function.
The commit reveal process ensures no eavesdropping third-party is able to register your name before you can.
ETHRegistrarController.makeCommitment(name string, owner address, duration uint256, secret bytes32, resolver address, data bytes[], reverseRecord bool, ownerControlledFuses uint16)// For examplemakeCommitment( "myname", // "myname.eth" but only the label 0x1234..., // The address you want to own the name 31536000, // 1 year (in seconds) 0x1234..., // A secret that you have generated (32 bytes) 0x1234..., // The address of the resolver you want to use [], false, // Set as primary name? 0);
Once you have calculated the commitment hash you can call the commit
function.
ETHRegistrarController.commit(commitment bytes32)
Note this does require an on-chain transaction.After having committed it is recommended to wait at least the MIN_COMMITMENT_AGE
(~60 seconds) before registering.
Registering
Once you have committed you can register your name.Registration takes in the same parameters as the makeCommitment
function, but this time is in the form of a transaction.
Before initiating registration ensure that:
available(name)
== trueduration
>=MIN_REGISTRATION_DURATION
commitments[commitment]
is between 1 min and 24 hrs oldmsg.value
>=rentPrice(name, duration)
+5-10% (slippage)
Because the rent price may vary over time, callers are recommended to send slightly more than the value returned by rentPrice
, a premium of 5-10% will likely be sufficient.Any excess funds sent during registration are automatically returned to the caller.
ETHRegistrarController.register(name string, owner address, duration uint256, secret bytes32, resolver address, data bytes[], reverseRecord bool, ownerControlledFuses uint16)// For exampleregister( "myname", // "myname.eth" but only the label 0x1234..., // The address you want to own the name 31536000, // 1 year (in seconds) 0x1234..., // A secret that you have generated (32 bytes) 0x1234..., // The address of the resolver you want to use [], false, // Set as primary name? 0);
If you would like to try registering a name live on a testnet you can use the live demo below.
Register a name
ETHRegistrarController.renew()
Any user can renew a domain, not just the owner. This means that if you want to ensure a name doesn't expire you can renew it for someone.
By allowing renewal for any arbitrary amount of time users can ensure their name will not expire.As per the separation between registry and controller, even with upgraded controller your name will still be yours.
Renew a name
Other features
ETHRegistrarController.MIN_COMMITMENT_AGE uintETHRegistrarController.MAX_COMMITMENT_AGE uintETHRegistrarController.MIN_REGISTRATION_DURATION uint// Get Commitment TimestampETHRegistrarController.commitments mapping(bytes32=>uint)// Get Rent PriceETHRegistrarController.rentPrice(string name, uint duration) view returns (uint)// Check Name ValidityETHRegistrarController.valid(string name) view returns (bool)// Check Name Availability// Returns true if the name is both valid and available for registration by this controller.ETHRegistrarController.available(string name) view returns (bool)// Calculate Commitment HashETHRegistrarController.makeCommitment(string name, address owner, uint256 duration, bytes32 secret, address resolver, bytes[] data, bool reverseRecord, uint16 ownerControlledFuses) view returns (bytes32)// Get Name Expiry (unix timestamp at which registration expires)BaseRegistrar.nameExpires(uint256 label) view returns (uint)// Check Name Availability (less specific, use ETHRegistrarController.available instead)BaseRegistrar.available(uint256 label) view returns (bool)// Get Transfer Period End (unix timestamp at which transfer period (from legacy registrar) ends)BaseRegistrar.transferPeriodEnds uint// Get Controller StatusBaseRegistrar.controllers mapping(address=>bool)// Check Token ApprovalBaseRegistrar.getApproved(uint256 tokenId) view returns (address operator)// Check All Tokens ApprovalBaseRegistrar.isApprovedForAll(address owner, address operator) view returns (bool)// Get Token OwnerBaseRegistrar.ownerOf(uint256 tokenId) view returns (address)// Get Token URIBaseRegistrar.tokenURI(uint256 tokenId) view returns (string)
Writable
// Transfer a NameBaseRegistrar.transferFrom(address from, address to, uint256 tokenId)BaseRegistrar.safeTransferFrom(address from, address to, uint256 tokenId)BaseRegistrar.safeTransferFrom(address from, address to, uint256 tokenId, bytes _data)// Approve OperatorBaseRegistrar.approve(address to, uint256 tokenId)// Set Approval For AllBaseRegistrar.setApprovalForAll(address operator, bool approved)// Reclaim ENS RecordBaseRegistrar.reclaim(uint256 label)
Events
// BaseRegistrarevent Transfer(address indexed from, address indexed to, uint256 indexed tokenId);event NameMigrated(uint256 indexed hash, address indexed owner, uint expires);event NameRegistered(uint256 indexed hash, address indexed owner, uint expires);event NameRenewed(uint256 indexed hash, uint expires);// Controllerevent NameRegistered(string name, bytes32 indexed label, address indexed owner, uint cost, uint expires);event NameRenewed(string name, bytes32 indexed label, uint cost, uint expires);