# EtherNames (.ether) > Ownerless, immutable naming protocol on Ethereum mainnet (chain id 1). ERC-721 > names under the .ether TLD with ENS-style records (addr, text, contenthash, > primary name). No owner, no admin keys, no API keys, no accounts. Registration > fees are paid in ETH and burned (locked in the contract forever; there is no > withdraw and no privileged role). Contracts are a minimally-adapted fork of the > audited wei-names base (Cantina, Plainshift, Zellic); every changed line is > published on the audit trail. Verify the contract address AND chainid == 1 > before signing; the same address on another chain is not this contract. Critical rules for programmatic use (each prevents a real failure): - Registration is commit-reveal: commit(makeCommitment(label, owner, secret)), wait until the reveal block timestamp is >= the commit block timestamp + 60 (commitment stays valid 24h from the commit; both boundaries inclusive), then reveal from the SAME account you committed for. reveal() binds msg.sender and mints to msg.sender; the owner argument of makeCommitment must match whoever reveals. - The secret must be 32 cryptographically random bytes, unique per commitment, never derived from the label/time/address. The commitment is a salted hash; a guessable secret lets an observer reconstruct it, learn the label, and race your reveal. Persist the secret to durable storage BEFORE broadcasting commit. - A reverted reveal leaves the commitment live: retry the SAME reveal with the SAME secret. Only restarting from commit() while the old commitment is still live needs a fresh secret (re-sending the identical commitment reverts AlreadyCommitted). Before any retry, check ownerOf/isAvailable: a front-runner may have already registered the name to you. - revealFor(label, owner, secret) lets any sender register directly to `owner` (payer pays and gets the refund; the mint goes to the committed owner). The owner is FINAL: a typoed owner mints the name and burns the fee to the wrong address with no recovery (no admin). A contract owner must implement onERC721Received or the transaction reverts. Checksum-validate the recipient and simulate before broadcasting. - Every mint runs an onERC721Received check: any contract receiving a name (a reveal sender, a revealFor owner, or a subdomain `to`) must implement it. - Send fee + premium as value; excess is refunded to msg.sender in the same transaction. A contract sender must accept ETH (receive()) or pay the exact amount, or the refund reverts the whole call. - Names freeze the moment they expire: resolve() returns address(0), record writes and transfers revert during the whole 90-day grace; only renew() works. Check liveness with resolve(tokenId) != 0, never isExpired or inGracePeriod (those always return false for subdomains). - renew(tokenId) is permissionless (anyone can pay for any top-level name) and extends 365 days from current expiry; prepay multiple years via repeated calls. renew refunds excess to msg.sender, so in a batch send each call exactly its fee (inside a multicall msg.sender is the multicall contract). - Token ids are REUSED: after a lapse past grace, re-registration re-mints the same tokenId to the new owner and wipes all records. Cache the epoch from records(tokenId) and treat a changed epoch as a different name. ERC-6551 token-bound accounts follow the name: a lapsed name's TBA (and its assets) belongs to the next registrant, so do not use one as a treasury without automated renewal. - Fees are tiered by UTF-8 BYTE length of the label: 0.05 / 0.05 / 0.005 / 0.005 / 0.0005 ETH for 1 / 2 / 3 / 4 / 5+ bytes. Post-grace premium starts near 100 ETH, decays linearly to 0 over 21 days. A name still in grace quotes premium 0 while unregisterable, then jumps to ~100 ETH at the first registrable second; budget getPremium as of the reveal block. - Normalization: lowercase ASCII labels as-is; apply ENSIP-15 normalization only to NON-ASCII labels (ENSIP-15 remaps/rejects ASCII punctuation the contract accepts, e.g. apostrophe and interior underscore). The contract exposes isAsciiLabel(). - Availability/quote lookups leak the label to whoever runs the RPC; use a node you trust for valuable names. The commit is a salted hash and leaks nothing. - Subdomains: registerSubdomainFor(label, parentId, to) is one transaction, no commit-reveal, free under a parent you own. The SubdomainRegistrar sells subdomains with ERC-20 or ETH pricing and on-chain price discovery via config(parentId); approve EXACTLY the quoted price (never unlimited) or send exactly that ETH, since the controller can change the price at any time. A parent owner can always reclaim a subdomain: buying one is trust in the parent. ## Docs - [AI agents & integrators](https://ethernames.com/docs/agents): the page this file summarizes. - [Contracts reference](https://ethernames.com/docs/contracts): addresses, constants, full function and event signatures. - [Registration](https://ethernames.com/docs/registration): commit-reveal explained, secrets, resuming a pending registration. - [Pricing](https://ethernames.com/docs/pricing): fee tiers, grace period, premium auction. - [Records & resolution](https://ethernames.com/docs/records): addr, text, contenthash, avatars, primary names. - [Subdomains](https://ethernames.com/docs/subdomains): depth limits, epochs. - [Selling subdomains](https://ethernames.com/docs/selling-subdomains): the SubdomainRegistrar, escrow vs flash mode, safety properties. - [Audit trail](https://ethernames.com/audit): audits and the full line-by-line diff against the audited base.