# docs.ens.domains llms.txt > The Ethereum Name Service (ENS) is a distributed, open, and extensible naming system based on the Ethereum blockchain. ENS maps human-readable names like 'alice.eth' to machine-readable identifiers such as Ethereum addresses, other cryptocurrency addresses, content hashes, metadata, and more. > Updated at: 22:35 05/28/25 # Reverse Registrar [Registrar responsible for Primary Names] Reverse resolution in ENS - the process of mapping from an Ethereum address (eg, 0x1234...) to an ENS name - is handled using a special namespace, .addr.reverse. A special-purpose registrar controls this namespace and allocates subdomains to any caller based on their address. The reverse registrar is specified in EIP 181. For example, the account `0x314159265dd8dbb310642f98f50c066173c1259b` can claim `314159265dd8dbb310642f98f50c066173c1259b.addr.reverse`. After doing so, it can configure a resolver and expose metadata, such as a canonical ENS name for this address. The reverse registrar provides functions to `claim` a reverse record, as well as a convenience function (`setName`) to configure the record as it's most commonly used, as a way of specifying a canonical name for an address. ## Lookup Primary Name If you are interested in [querying the primary name for an address](/web/reverse) you can checkout the web section. ## Set Primary Name ```solidity function setName(string memory name) public returns (bytes32) ``` Configures the caller's reverse ENS record to point to the provided `name`. This convenience function streamlines the process of setting up a reverse record for the common case where a user only wants to configure a reverse name and nothing else. It performs the following steps: 1. Sets the reverse record for the caller to be owned by the ReverseRegistrar. 2. Sets the reverse record for the caller to have `defaultResolver` as its resolver. 3. Sets the `name()` field in the `defaultResolver` for the caller's reverse record to `name`. In short, after calling this, a user has a fully configured reverse record claiming the provided name as that account's canonical name. Users wanting more flexibility will need to use `claim` or `claimWithResolver` and configure records manually on their chosen resolver contract. ## Multichain Considerations The current infrastructure for primary names across multiple chains is being worked on. ## Other Functions ### Claim Address ```solidity function claim(address owner) public returns (bytes32); ``` Claims the caller's address in the reverse registrar, assigning ownership of the reverse record to `owner`. Equivalent to calling `claimWithResolver(owner, 0)`. ```solidity function claimWithResolver(address owner, address resolver) public returns (bytes32) ``` Claims the caller's address in the reverse registrar, assigning `ownership` of the reverse record to owner. If `resolver` is nonzero, also updates the record's resolver. After calling this function: - The reverse record for the caller (1234....addr.reverse) is owned by `owner`. - If `resolver` is nonzero, the reverse record for the caller has its resolver set to `resolver`; otherwise it is left unchanged. ### Get Default Resolver ```solidity Resolver public defaultResolver; ``` Returns the address of the resolver contract that the `ReverseRegistrar` uses for `setName`. --- # DNS Registrar In [DNS on ENS](/learn/dns) we learned how ENS aims to extend the functionality of the DNS. On this page we will explore the implementation of DNSSEC, the DNSRegistrar, and the building blocks for gasless DNSSEC. :::note Not all top level domains support DNSSEC, and some might have custom ENS implementations. Please refer to the [TLD List](/dns/tlds) for TLD-specific information. ::: ## DNSSEC DNSSEC (Domain Name System Security Extensions) is an added layer of security on top of DNS that allows for cryptographic verification of records. It establishes a chain of trust from the root key (which is signed by ICANN) down to each key. All ENS-enabled DNS names are required to use DNSSEC, and the [DNSSECOracle](https://github.com/ensdomains/ens-contracts/tree/master/contracts/dnssec-oracle) is responsible for verifying the signatures. ### Claiming a Name Onchain Since 2021, it has been possible to [import a DNS name](/learn/dns#importing-a-dns-name) and use that as an ENS name. This process involves enabling DNSSEC, setting a specific TXT record, and submitting a proof to the [DNSRegistrar](https://github.com/ensdomains/ens-contracts/tree/master/contracts/dnsregistrar) smart contract. Expect your `TXT` record to look something like this: ``` TXT @ _ens a=<eth-address> ``` You can learn more about [how to import a DNS name](/learn/dns#importing-a-dns-name) in the DNS section, or see how to [programmatically complete these steps](#programming-dnssec-proofs). There is no ENS protocol fee to import a DNS name, but it requires a large amount of gas (up to a few million) to submit the proof onchain. Continue reading to learn how this has been mitigated. ## Offchain Verification (Gasless) [EP 5.1](/dao/proposals/5.1) introduced a new DNSSECOracle and DNSRegistrar which makes it possible to perform DNSSEC verification at query time, enabling truly free usage of DNS names in ENS. We call this "gasless DNSSEC". It works by enabling [wildcard resolution](/ensip/10) at the DNS TLD level. During the [name resolution process](/resolution), if a name doesn't already exist onchain but has been configured for usage in ENS, the DNSSEC proof will be fetched offchain via [CCIP Read](https://eips.ethereum.org/EIPS/eip-3668) and then verified onchain with the same DNSSECOracle mentioned above. ### Import a DNS name gaslessly To configure a DNS name for usage in ENS, simply add a `TXT` record with the following format: ``` TXT @ ENS1 <resolver-address> ``` The `resolver-address` implementation is customizable just like any other ENS resolver. To get started quickly, a special ExtendedDNSResolver has been deployed which allows users to specify an ETH address that the name should resolve to within the same `TXT` record. To use this setup, simply add a record with the following format: ``` TXT @ ENS1 <extended-resolver-address> <eth-address> TXT @ ENS1 0x238A8F792dFA6033814B18618aD4100654aeef01 0x225f137127d9067788314bc7fcc1f36746a3c3B5 ``` ## Other ### TLD Ownership You can lookup the `owner` of any TLD by calling the `Registry.owner(bytes32 node)` function. If at least one domain has been imported for this TLD (via the onchain method), the owner will be either the `DNSRegistrar` or a smart contract controlled by the respective registry operator. If a TLD has not yet been activated, the `owner` will return `0x0` and it may require one user to import a name onchain to activate the TLD. See the [supported TLD list](/dns/tlds) for more info. ### Programming DNSSEC Proofs To help you interact with DNSSEC data and the DNSRegistrar, we provide a few libraries. - [DNSProvejs](https://github.com/ensdomains/dnsprovejs) = A library for querying and validating DNSSEC data from DNS - [ENSjs](https://github.com/ensdomains/ensjs) = A library for interacting with ENS smart contracts #### Retrieving a proof ```ts import { addEnsContracts } from '@ensdomains/ensjs' import { getDnsImportData } from '@ensdomains/ensjs/dns' import { createPublicClient, http } from 'viem' import { mainnet } from 'viem/chains' const client = createPublicClient({ chain: addEnsContracts(mainnet), transport: http(), }) const dnsImportData = await getDnsImportData(client, { name: 'example.com', }) ``` #### Submitting the proof to the DNSRegistrar ```ts import { addEnsContracts } from '@ensdomains/ensjs' import { getDnsImportData, importDnsName } from '@ensdomains/ensjs/dns' import { createPublicClient, createWalletClient, custom, http } from 'viem' import { mainnet } from 'viem/chains' const mainnetWithEns = addEnsContracts(mainnet) const client = createPublicClient({ chain: mainnetWithEns, transport: http(), }) const wallet = createWalletClient({ chain: mainnetWithEns, transport: custom(window.ethereum), }) const dnsImportData = await getDnsImportData(client, { name: 'example.com', }) await importDnsName(wallet, { name: 'example.com', dnsImportData, }) ``` ## Other functions ```ts // Get the list of suffixes DNSRegistrar.suffixes // Get Oracle DNSRegistrar.oracle ``` ```ts DNSRegistrar.claim(bytes name, bytes proof) DNSRegistrar.proveAndClaim(bytes name, tuple[] input, bytes proof) DNSRegistrar.proveAndClaimWithResolver(bytes name, tuple[] input, bytes proof, address resolver, address addr) ``` --- import { FiBookOpen, FiClock, FiHash } from 'react-icons/fi' import { Card } from '../../components/ui/Card' # ETH Registrar [Smart contracts responsible for the ".eth" TLD] The ETH Registrar is a special registrar. It allows for trustless on-chain name registration and is in charge of the ".eth" TLD. ## BaseRegistrar vs Controller The ETH Registrar is split into two contracts. The [BaseRegistrar](https://github.com/ensdomains/ens-contracts/blob/staging/contracts/ethregistrar/BaseRegistrarImplementation.sol) and the [ETHRegistrarController](https://github.com/ensdomains/ens-contracts/blob/staging/contracts/ethregistrar/ETHRegistrarController.sol). 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](https://github.com/ensdomains/ens-contracts/blob/staging/contracts/ethregistrar/ETHRegistrarController.sol) 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](https://github.com/ensdomains/ens-contracts/blob/master/contracts/ethregistrar/StablePriceOracle.sol). 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](https://support.ens.domains/en/articles/7900612-temporary-premium). ### 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](/dao/constitution#iii-income-funds-ens-and-other-public-goods). ## ERC721 and NFTs 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 Registering a name is a trustless process that takes place onchain (more on this below). Some open source frontends for registering names are the [ENS Manager App](https://app.ens.domains/), [ENS Fairy](https://ensfairy.xyz/), Rainbow Wallet. The process of registering a `.eth` name uses a commit-reveal process.
Commit
Wait
Reveal
### Commit-Reveal The ETHRegistrarController, the highest level contract that users register names through, implements a commit reveal scheme to prevent frontrunning registrations. We first call the `commit` function with an opaque bit of data (the `commitmenthash`), wait 60 seconds, 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 is to prevent a malicious actor from seeing your `register` transaction in the public mempool and frontrunning it. ```solidity ETHRegistrarController.makeCommitment( name string, owner address, duration uint256, secret bytes32, resolver address, data bytes[], reverseRecord bool, ownerControlledFuses uint16 ) // For example makeCommitment( "myname", // "myname.eth" but only the label 0x1234..., // The address you want to own the name 31536000, // 1 year (in seconds) 0x1234..., // A randomly generated 32 byte secret you create 0x1234..., // The address of the resolver you want to use [0x8b95dd71...], // Encoded function calls you want to pass to the resolver, like `setAddr()` false, // Whether or not to set the new name as your primary name 0 // The NameWrapper fuses you want to set ); ``` Once you have calculated the commitment hash, submit the `commit` transaction. ```solidity ETHRegistrarController.commit(commitment bytes32) ``` After having committed, it is required to wait at least the `MIN_COMMITMENT_AGE` (60 seconds) before making the subsequent `register` transaction. ### Registering Once you have made the onchain commitment and waited 60 seconds, you can register your name. Registration takes in the same parameters as the `makeCommitment` function above. Before initiating registration, ensure that: - `available(label)` == `true`, where `label` is "name" in "name.eth" - `duration` >= `MIN_REGISTRATION_DURATION` - `commitments[commitment]` is between 1 min and 24 hrs old - `msg.value` >= `rentPrice(name, duration)` + `5-10% (slippage)` Because the rent price is paid in ETH but denominated in USD, callers are recommended to send slightly more than the value returned by `rentPrice` to avoid issues with fast price changes. A premium of 3-5% will likely be sufficient. Any excess funds sent during registration are automatically returned to the caller. ```solidity ETHRegistrarController.register( name string, owner address, duration uint256, secret bytes32, resolver address, data bytes[], reverseRecord bool, ownerControlledFuses uint16 ) // For example register( "myname", // "myname.eth" but only the label 0x1234..., // The address you want to own the name 31536000, // 1 year (in seconds) 0x1234..., // The same secret you used in the `commit` transaction 0x1234..., // The address of the resolver you want to use [0x8b95dd71...], // Encoded function calls you want to pass to the resolver, like `setAddr()` false, // Whether or not to set the new name as your primary name 0 // The NameWrapper fuses you want to set ); ``` ## Renewing a Name ```solidity 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. ## Other features ```solidity ETHRegistrarController.MIN_COMMITMENT_AGE uint ETHRegistrarController.MAX_COMMITMENT_AGE uint ETHRegistrarController.MIN_REGISTRATION_DURATION uint // Get Commitment Timestamp ETHRegistrarController.commitments mapping(bytes32=>uint) // Get Rent Price ETHRegistrarController.rentPrice(string name, uint duration) view returns (uint) // Check Name Validity ETHRegistrarController.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 Hash ETHRegistrarController.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 Status BaseRegistrar.controllers mapping(address=>bool) // Check Token Approval BaseRegistrar.getApproved(uint256 tokenId) view returns (address operator) // Check All Tokens Approval BaseRegistrar.isApprovedForAll(address owner, address operator) view returns (bool) // Get Token Owner BaseRegistrar.ownerOf(uint256 tokenId) view returns (address) // Get Token URI BaseRegistrar.tokenURI(uint256 tokenId) view returns (string) ``` Writable ```solidity // Transfer a Name BaseRegistrar.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 Operator BaseRegistrar.approve(address to, uint256 tokenId) // Set Approval For All BaseRegistrar.setApprovalForAll(address operator, bool approved) // Reclaim ENS Record BaseRegistrar.reclaim(uint256 label) ``` Events ```solidity // BaseRegistrar event 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); // Controller event NameRegistered(string name, bytes32 indexed label, address indexed owner, uint cost, uint expires); event NameRenewed(string name, bytes32 indexed label, uint cost, uint expires); ``` --- # The Registry [Root Registry of the Ethereum Name Service] The ENS registry is the core contract that lies at the heart of ENS resolution. All ENS lookups start by querying the registry. The registry maintains a list of domains, recording the owner, resolver, and TTL for each, and allows the owner of a domain to make changes to that data. The ENS registry is specified in [EIP 137](https://eips.ethereum.org/EIPS/eip-137). ## Why Registries? Top-Level Domains (TLDs), like `.eth`, `.com`, and `.test`, are owned by smart contracts called registrars, which specify rules governing the allocation of their names. Anyone may, by following the rules imposed by these registrar contracts, obtain ownership of a domain for their own use. | TLD | Registrar Contract | | ------------------- | -------------------------------------- | | `[root]` | [The Registry](/registry/ens) | | `.eth` | [ETH Registry](/registry/eth) | | `.com`, `.xyz`, etc | [DNS Registrar](/registry/dns) | | `.addr.reverse` | [Reverse Registrar](/registry/reverse) | ## Who owns the root Registry? The [ENS Registry](https://etherscan.io/address/0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e) is owned by the [ENS Root](https://etherscan.io/address/0xaB528d626EC275E3faD363fF1393A41F581c5897) which is owned by the [ENS DAO Wallet](https://etherscan.io/address/0xFe89cc7aBB2C4183683ab71653C4cdc9B02D44b7). To verify this you can run the `owner` function on the registry & root contracts. ## Other Functions ```ts // Get Owner ENS.owner(bytes32 node) view returns (address) // Get Resolver ENS.resolver(bytes32 node) view returns (address) // Get TTL ENS.ttl(bytes32 node) view returns (uint64) // Get Approval ENS.isApprovedForAll(address owner, address operator) view returns (bool) // Check Record Existence ENS.recordExists(bytes32 node) view returns (bool) ``` ```ts // Set Owner (only callable by current owner) ENS.setOwner(bytes32 node, address owner) // Set Resolver ENS.setResolver(bytes32 node, address resolver) // Set TTL ENS.setTTL(bytes32 node, uint64 ttl) // Set Subnode Owner ENS.setSubnodeOwner(bytes32 node, bytes32 label, address owner) // Set Multiple (convenience function (setResolver, setTTL, setOwner)) ENS.setRecord(bytes32 node, address owner, address resolver, uint64 ttl) // Set Multiple Subnode ENS.setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) // Set Approval ENS.setApprovalForAll(address operator, bool approved) ``` Events ```ts // Transfer Event event Transfer(bytes32 indexed node, address owner) // New Resolver Event event NewResolver(bytes32 indexed node, address resolver) // New TTL Event event NewTTL(bytes32 indexed node, uint64 ttl) // New Owner Event event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner) ``` --- # FAQ ## Which wallets and dApps support ENS? ENS is supported by a wide range of wallets and dApps, some notable ones can be found on the [integrations page](https://ens.domains/). This page is currently under construction however a link to add yourself will be put here soon. ## Can I hold my name with one address, and point it at the other? Yes, you can hold your name with one address and point it at another. Simply visit the [ENS Manager App](https://ens.app/) and update the appropriate address record (by chain) for your name to point to the address you wish. ## Once I own a name, can I create my own subdomains? Yes. You can create whatever subdomains you wish and assign ownership of them to other people if you desire. You can even set up your own registrar for your domain. Some resolvers might provide even more advanced features, read more [about Resolvers](/resolvers/quickstart). ## Can I change the address my name points to after I've bought it? Yes, you can update the addresses and other resources pointed to by your name at any time. To update your name checkout the [ENS Manager App](https://ens.app/). ## ETH Registration ### Why are names registered as hashes? Hashes provide a fixed length identifier that can easily be passed around between contracts with fixed overhead and no issues passing around variable-length strings. Read more about [labelhash, namehash, and encodings](/resolution/names). ### What characters are supported? ENS names are generally encoded using UTS-46. This means there is partial support for Unicode characters, including emoji. However technically possible to register any name, names that are not valid UTS-46 will not be resolvable by most resolvers. Therefore it is generally recommended for apps that implement registration to limit the characters that can be registered to ensure a smooth experience. To read more about supported characters [name normalization](/resolution/names). ### What does it cost to register a .eth domain? Currently, registration costs are set at the following prices: - 5+ character .eth names: $5 in ETH per year. - 4 character .eth names: $160 in ETH per year. - 3 character .eth names: $640 in ETH per year. 3 and 4 character names have higher pricing to reflect the small number of these names available. To read more about the pricing structure of .eth names [read more about pricing](/registry/eth) ### How long can I register a name for? You can register a name for as long as you would like. There is no maximum registration duration. ### What happens if I forget to renew my name? If you forget to renew your name, it will be released back to the public pool of available names. Luckily the expiration process has a 90 day grace period. This means that once the name expires the original owner has 90 days to renew the name before it is released. After the grace period, the name is released for registration by anyone with a temporary premium which decreases over a 21 days period. The released name continues to resolve your ETH address until the new owner overwrites it. ### In what way could I lose access to my name? The .eth registrar is built to ensure once issued, a name cannot be revoked or taken away from its owner. Potential loss can occur if the owner loses access to their private key, or if the owner forgets to renew their name. ## Root Registry ### Who owns the ENS rootnode? What powers does it grant them? The ENS rootnode is currently owned by the ENS DAO. It used to be owned by the ENS Multi-sig, a group of keyholders from different parts of the ecosystem, however as of [EP4.10](/dao/proposals/4.10) the ownership has been transferred to the ENS DAO. Ownership of the rootnode grants the ability to do the following: - Control allocation and replacement of TLDs other than .eth - this is required to implement DNSSEC integration. - Enable and disable controllers for the .eth registrar, which affect registration and renewal policies for .eth names. - Update the pricing for .eth names. - Receive and manage registration revenue. ### Can I register a TLD of my own within ENS? Yes and No, We consider ENS to be part of the 'global namespace' in co-existence with DNS, and it is our priority to not pollute the namespace. ENS-specific TLDs are restricted to only '.eth' on Mainnet Ethereum, or .eth and .test on testnets. By default ENS allows users to [import their DNS name](/learn/dns) through the use of the [DNS Registrar](/registry/dns). Existing DNS TLDs can [reach out to us](mailto:info@ens.domains) to take control of their TLD. ## What are the differences between ENS and other naming services such as Namecoin or Handshake? ENS complements and extends the usefulness of DNS with decentralised, trustworthy name resolution for web3 resources such as blockchain addresses and distributed content, while Namecoin and Handshake are efforts to replace all or part of DNS with a blockchain-based alternative. ## Governance Token ### Can I recover tokens accidentally sent to the wrong address? The answer depends on the address the token was sent to. If you accidentally sent the token to the token.ensdao.eth address (0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72) or the wallet.ensdao.eth address (0xFe89cc7aBB2C4183683ab71653C4cdc9B02D44b7) then the tokens might be recoverable. Contact the [Meta-governance working group](/dao/stewards/) at the [ENS Forum](https://discuss.ens.domains) and explain the situation. Tokens can only be sent back to the address they were sent from, so if it was sent from an exchange, contact your exchange support to make sure the address can receive tokens. If the tokens were sent to the null address (0x000..) or an address with a typo, then the tokens are unrecoverable and there's nothing that anyone can do. If the tokens were sent to an exchange or a third party, then contact that third party for help. --- import { Badge } from '../../components/ui/Badge' import { Card } from '../../components/ui/Card' # Hosting a Decentralized Website [Introduction to hosting a decentralized website using ENS] ## ContentHash The ContentHash is a very popular component of an ENS name, first introduced in [ENSIP-7](/ensip/7). It can be queried by hitting the [contenthash(bytes32)](/resolvers/interfaces#0xbc1c58d1) function on a name's resolver. You can also [set the contenthash on a name](/resolvers/interfaces#0x304e6ade) if the resolver supports it. {['ipfs://qMhx...', 'bzz:/2477', 'ar://HGa8...'].map((tag) => ( {tag} ))} ## Hosting & Pinning When it comes to hosting your files there are many options to choose from. {['IPFS / Filecoin', 'Swarm', 'Arweave'].map((tag) => ( {tag} ))} Popular options include [IPFS](https://ipfs.io), [Swarm](https://ethswarm.org), and [Arweave](https://arweave.org). Depending on what option you go with your files are either permanently stored on a network, or require to be actively stored on at least one machine, also known as "pinning". ### Deploy your sites Several helpful tools and platforms exist that you can use to deploy your website to IPFS, Swarm, or Arweave. Most notably [fleek](https://fleek.xyz), [Pinata](https://pinata.cloud), and [Blumen](https://blumen.stauro.dev/). Helping you easily deploy your website to a decentralized storage network. ## Setting your ContentHash If you are using the public resolver (the default for names registered using the ENS Manager App), you can set the contenthash directly from within the [ENS Manager App](https://app.ens.domains). If you are using a custom resolver, or are writing your own resolver you will be able to have more fine grained control over the contenthash field. See [ENSIP-7](/ensip/7) for more information on the contenthash field. ## Browser Support & Gateways In the ideal world every browser supports decentralized websites out of the box. If you are using [MetaMask](https://metamask.io) or [Brave Browser](https://brave.com) you can already access IPFS websites directly. On non-conforming browsers you can use a gateway such as [eth.link](https://eth.link) or [eth.limo](https://eth.limo) to access your website. You can test if your browser supports decentralized websites by visiting [ens.eth](https://ens.eth) or use a gateway via [ens.eth.link](https://ens.eth.link). --- import { Table } from '../../components/ui/Table' import ensips from '../../data/generated/ensips.json' # ENS Improvement Proposals This page contains a summary of all the ENS Improvement Proposals (ENSIPs) that have been proposed, and their current status. Improvement Proposals have included anything from new contract features, to text record standards, protocol features, and more. ## ENSIPs [ensip.title, ensip.status])} /> ## Propose an ENSIP Feel free to [open a pull request](https://github.com/ensdomains/ensips/pulls) on the `ensdomains/ensips` repository. --- import { Button } from '../components/ui/Button' # 🪲 Bug Bounty Program The ENS bug bounty program rewards anyone who finds a bug in covered ENS smart contracts and ENS Labs assets. This page provides a brief overview of the program which is operated by Immunefi and ENS Labs. [See the full program](https://immunefi.com/bug-bounty/ens) ## Bounties 💸 Reward sizes are guided by the rules below, but are in the end, determined at the sole discretion of the ENS Labs team. ### Smart Contracts - **Critical**: up to $250,000 USD - **High**: up to $150,000 USD - **Medium**: up to $100,000 USD ### Websites and Applications - **Critical**: up to $50,000 USD - **High**: up to $20,000 USD - **Medium**: up to $5,000 USD - **Low**: up to $1,000 USD The ENS Labs team reserves the right to adjust bounty amounts at any time in the future. --- # 📝 Changelog This page contains a list of changes and events that happened to the ENS protocol & ecosystem. ## Dentity Announcement On August 21st, 2024 the ENS Labs team announced a new integration with Dentity, an independent identity provider that allows users to verify information and share it on their ENS profile.0 This integration leverages a draft ENSIP that allows for W3C Verifiable Credentials to be stored inside ENS profiles. ## ENSv2 Announcement On March 28th, 2024 the ENS Labs team announced our plans and roadmap for scaling ENS to the entire internet and beyond. This involves migrating .eth registrations to a brand new system, in addition to improving support for existing L2 solutions. You can read more [on our blog](https://blog.ens.domains/post/ensv2), [on X](https://twitter.com/ensdomains/status/1795440186513576318), and [the forums](https://discuss.ens.domains/t/technical-feedback-thread-for-ensv2/19233). --- # Creating a Subname Registrar In the [Use Cases](/wrapper/usecases#sell-or-rent-subnames) section, we talked about the ability to stand up your own "registrar" to allow other people to register/claim subnames automatically. Maybe you want to give wrapped subnames out for free, or maybe you want to charge for them. Maybe you want to apply specific rules to the subnames, such as only allowing alphanumeric names. All of this is possible, and this article will break down what you need to do. It's recommended to first read the [Use Cases](/wrapper/usecases#sell-or-rent-subnames) section to get an overview of the decisions you'll need to make. ## Prerequisites This guide assumes that your parent name (such as `myname.eth`) is already wrapped. If you're not sure whether your name is wrapped, look at the More tab on the Manager app. If the name is unwrapped, it will say so, and it will show you a "Wrap Name" button. If you want to issue [Emancipated](/wrapper/states#emancipated) subnames, or subnames with [any other fuses](/wrapper/fuses) burned, then your parent name must first be [Locked](/wrapper/states#locked). You can do this on the Permissions tab in the ENS manager app. :::note Locking your name (in other words revoking the permission to unwrap) is an **irreversible** change. After you lock the name, you will no longer be able to unwrap it. This is a security guarantee for the holders of all subnames. It ensures that the owner of the parent name cannot get around the security guarantees of the Name Wrapper. Best to do this on a testnet (Sepolia/Holesky) name first, for development or testing purposes. ::: ## Creating and Deploying your Registrar Contract In order to create a new subname, your contract should call either `setSubnodeOwner` or `setSubnodeRecord` on the [NameWrapper contract](/learn/deployments#deployments). Also pass in the fuses and expiry at the same time, as needed. ```solidity NameWrapper.setSubnodeOwner(bytes32 parentNode, string label, address owner, uint32 fuses, uint64 expiry) // For example setSubnodeOwner( 0x6cbc..., // The namehash of the parent node, e.g. "myname.eth" "sub", // The label of the subname to create 0x1234..., // The address you want to be the owner of the new subname 65536, // The fuse bits OR'd together, that you want to burn 2021232060 // The expiry for the subname ) NameWrapper.setSubnodeRecord(bytes32 parentNode, string label, address owner, address resolver, uint64 ttl, uint32 fuses, uint64 expiry) // For example setSubnodeRecord( 0x6cbc..., // The namehash of the parent node, e.g. "myname.eth" "sub", // The label of the subname to create 0x1234..., // The address you want to be the owner of the new subname 0x5678..., // The address of the resolver to set for the new subname 0, // The TTL to set for the new subname 65536, // The fuse bits OR'd together, that you want to burn 2021232060 // The expiry for the subname ) ``` Your public-facing registration function would typically take at _least_ the parent node (namehash) and subname label as inputs, such as: ```solidity register(bytes32 parentNode, string calldata label) ``` Then under the hood, your contract will call `setSubnodeRecord` and fill in the rest of the parameters on behalf of the user: - owner: Typically the caller account, `msg.sender` - resolver: Typically the default public resolver, `resolver.eth` - ttl: 0 - fuses: Up to you and your goals. See the [Use Cases](/wrapper/usecases#sell-or-rent-subnames) section for a discussion on this. Typically 65536 for an enamcipated rental subname, or 327680 for an emancipated "forever" name. - expiry: Up to you and your goals. If you are renting subnames for a particular length of time, this expiry would reflect that. If you are allowing registration of "forever" names, then you can just set the expiry equal to the parent name's current expiry. Of course, if you want to give the registrant more power/convenience, you could allow some of those parameters to be passed in to your public register function as well. ### Setting Resolver Records If you want your subname registrar to set records on a subname in the same registration transaction, then the flow will be slightly different. In that case, perform these steps: - Call `setSubnodeOwner`, setting the _contract itself_ (`address(this)`) as the owner of the subname, temporarily. This first step is needed for the default Public Resolver so that the contract has the authority to set records for the subname. - Call whatever [resolver methods](/resolvers/interacting) you need to. Perhaps these are records that you want to be pre-set on your subnames (such as an ETH address that the subname points to). Or perhaps these are records that you allow the registrant to pass in, so that they can register their subname and set whatever records they want all in one transaction. - Call `setSubnodeRecord`, but this time set the owner to the actual intended owner of the subname. This is the point at which you should set the appropriate fuses and expiry you want to, as well. In addition, you will need to make sure your contract follows the [ERC-1155 Token Receiver rules](https://eips.ethereum.org/EIPS/eip-1155#erc-1155-token-receiver). This means implementing the `onERC1155Received` and `onERC1155BatchReceived` methods, and signaling support for them in your ERC-165 `supportsInterface` method. OpenZeppelin has an easy abstract contract you can include for all this: [ERC1155Holder.sol](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/utils/ERC1155Holder.sol) ### Taking fees If you are setting up a "rental" registrar, then your registration function should require a certain amount of ETH to be sent in as well. Alternatively, you could choose to allow users to spend ERC-20 tokens instead. To accomplish that, you would typically call the ERC-20 method `transferFrom` on the token contract. This also means that the registrant would first need to approve your contract as a spender for that token, meaning they would need to execute a separate approval transaction first (either to approve unlimited spending, or to approve the specific number of tokens needed to register the subname). ### Reference Implementation Luckily, you don't need to start from scratch! The ENS Labs devs have created some example contracts you can start from: https://github.com/ensdomains/ens-contracts/tree/feature/subdomain-registrar/contracts/subdomainregistrar These contracts include two different implementations: #### Forever Subname Registrar This is a basic FIFS (First in first serve) registrar. The registration can take a fixed fee, or this fee can be set to 0 if you wish for subnames to be free. Names automatically are set to the parent's expiry can the fuse for `CAN_EXTEND_EXPIRY` will be burnt on registration so the user can extend their expiry if the parent also extends theirs. For a better UX, it is recommended that the parent sets their expiration as high as possible to allow their users to not have to think about renewing. #### Rental Subname Registrar This is a basic FIFS (First in first serve) registrar. The key difference between this and the ForeverSubdomainRegistrar is that it does not auto-burn the `CAN_EXTEND_EXPIRY` fuse and instead exposes a `renew()` function that allows paid renewal. This registrar also needs to be paired with a rental-based pricing contract. For simplicity, the deployer can deploy this pricing contract and the UI can pass this address through to `setupDomain()` when a new user wants to setup a subname. ## Setting Everything Up Once you have a parent name ready and a subname registrar contract deployed, then you just need a few extra steps to set everything up: ### (If needed) Call setupDomain on your contract This will only apply to you if you have a specific `setupDomain` method or something similar on your contract, such as the [reference implementation](/wrapper/creating-subname-registrar#reference-implementation) contracts do. Calling this method will "enable" a specific parent name in your subname registrar. It can also allow you to set or update the pricing terms or beneficiary account, if needed. ### Approve your contract Call `setApprovalForAll` on the NameWrapper contract, approving your subname registrar contract as an operator for any names you own. This allows you to keep ownership of the parent name, and just delegate subname creation to your contract. ### (If needed) Approve token spending If your registrar contract takes ERC-20 tokens as a registration fee, then a potential registrant will need to approve your contract as a spender first. ### Register a subname Finally, the registrant will call your public registration method. Upon transaction success, they will own the wrapped name (ERC-1155 NFT) with whatever fuse/expiry guarantees that you setup in your registrar. If you are allowing "forever" subnames to be registered (meaning that you've burned the `CAN_EXTEND_EXPIRY` fuse on the subnames), then the registrant can extend their own expiry at any time. Note that a subname's expiry can be set up to a maximum of whatever the parent name's expiry is. And that's it! --- # Name Wrapper Fuses A "fuse" is a permission or perk that can be granted/revoked on a name. As the name implies, once the fuse is "burned", it cannot be unburned. Fuses will only reset when the **expiry** is reached. In the ENS Manager UI, this is available in the "Permissions" section of the name. By **wrapped expiry**, we mean that for .eth second-level names (like `name.eth`), this is the end of the 90-day grace period, the time at which the .eth 2LD is truly released. For all other names (such as subnames), there is no grace period, so the expiry is just the expiration date for that specific subname. For example, by default when you wrap a name, you can transfer that NFT around freely, just as you can with other NFTs. However, if the **`CANNOT_TRANSFER`** fuse is burned, then the NFT becomes non-transferrable. In the ENS Manager UI, you would do this by revoking the "Can send this name" permission. In order to burn fuses on a name, the parent name must be **Locked** (meaning, you cannot unwrap the name). The reason is, if the parent name was not locked, then the owner of the parent name could simply get around the constraints of the Name Wrapper by unwrapping the name, and replacing/revoking subnames against the core ENS Registry. There are parent-controlled and owner-controlled fuses: ## Parent-Controlled Fuses Only the owner of the parent name can burn one of these fuses on a name. These can generally be thought of as "perks" that can be granted to a name, though they can be used in other ways. | Fuse name | Description | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **`PARENT_CANNOT_CONTROL`** | Allows a parent owner to **Emancipate** a child name. After this is burned, the parent will no longer be able to burn any further fuses, and will no longer be able to replace/delete the child name. This fuse must be burned in order for any owner-controlled fuses to be burned on the name. | | **`IS_DOT_ETH`** | This fuse cannot be burned by users of the Name Wrapper, it is only set internally when a .eth 2LD is wrapped. | | **`CAN_EXTEND_EXPIRY`** | The owner of the child name will be able to extend their own expiry. Normally, only the parent owner can extend the expiry of a child name. See the [Expiry](/wrapper/expiry) section for more information. | | **Custom Fuses** | There are 13 other parent-controlled fuses that are not reserved, and can be used in any custom way you want! | ## Owner-Controlled Fuses Either the owner of the name or the owner of the parent name can burn one of these fuses. These can generally be thought of as "permissions" that can be revoked on a name, though they can be used in other ways. | Fuse name | Description | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **`CANNOT_UNWRAP`** | The name will now be **Locked**, and can no longer be unwrapped. This fuse must be burned in order for any other owner-controlled fuses to be burned on the name. | | **`CANNOT_BURN_FUSES`** | No further fuses can be burned on the name. | | **`CANNOT_TRANSFER`** | The name (wrapped NFT) can no longer be transferred. | | **`CANNOT_SET_RESOLVER`** | The resolver contract for the name can no longer be updated. | | **`CANNOT_SET_TTL`** | The TTL for the name can no longer be updated. | | **`CANNOT_CREATE_SUBDOMAIN`** | New subdomains can no longer be created. | | **`CANNOT_APPROVE`** | The approved "subname renewal manager" for the name can no longer be updated. See the [Approved Operators](#approved-operators) section for more information. | | **Custom Fuses** | There are 9 other owner-controlled fuses that are not reserved, and can be used in any custom way you want! | ## The Emancipated and Locked States This is also covered in the Wrapped States section, but here is a quick recap: All .eth second-level names (like `name.eth`) are automatically placed into the Emancipated state when wrapped. **Emancipated** means that the parent no longer has control over the child name. It can no longer burn any fuses or replace the subname, up until the expiry. A name is Emancipated when the parent burns the **`PARENT_CANNOT_CONTROL`** (PCC) fuse. The parent must first be in the Locked state to be able to do this. **Locked** means that the name cannot be unwrapped. This provides assurance to subnames that the parent owner cannot unwrap and then, for example, start replacing subnames directly against the registry. An Emancipated name is Locked when the **`CANNOT_UNWRAP`** (CU) fuse is burned. Think of the special PCC / CU fuses recursively: - To burn owner-controlled or subname fuses, CU must be burned. - To burn CU, PCC must be burned. - Only the parent can burn PCC on the child name, and only if CU is first burned on the parent. - Only the grandparent can burn PCC on the parent name, and only if CU is first burned on the grandparent. - And so on... Follow that chain up until you hit a .eth second-level name like `name.eth`, since .eth second-level names will have PCC automatically burned when wrapping. The parent `eth` node is already in the Locked state. A parent name can burn all the fuses it needs to on a child name in one transaction. This can be done when the subname is created, or on an existing subname that has not yet been Emancipated. ## DNS Domains and Fuses Currently, only .eth names support fuses, because only the `eth` node is on-chain native and completely locked beyond anyone's control. Technically speaking, the owner of a DNS TLD has the ability to burn fuses on that TLD in the Name Wrapper, and set it to the "Locked" state. And then from there, all subnames under that DNS TLD _will_ be able to use fuses. The DNS TLD owner would need to: - Request the Controller of that TLD from the ENS DAO - Wrap the TLD node in the Name Wrapper - Burn the **`PARENT_CANNOT_CONTROL`** and **`CANNOT_UNWRAP`** fuses on the wrapped TLD to lock it However, this still does not have all the immutable guarantees that .eth names do. This is because for DNS names, the "source of truth" always lies not in the Ethereum network, but in the DNS network, and the DNS root zone governed by ICANN stakeholders. So even if the DNS TLD owner "Locks" that TLD in the ENS Name Wrapper, if that TLD were to ever change ownership on the DNS side, then (per the [ENS DAO Constitution](https://docs.ens.domains/v/governance/ens-dao-constitution#iv.-ens-integrates-with-the-global-namespace)) the new owner would be able to override control of that TLD on the ENS side, unwrap it, and replace/revoke all 2LDs. This is just something to keep in mind for wrapped DNS domains. Even if wrapped DNS domains do not support fuses, you can still use them as ERC-1155 NFTs. They will still have their own NFT metadata and show up in your wallet, with whatever avatar you have set, etc. They just won't have all the extra functionality that comes with the fuse/permission system. --- import { Card } from '../../components/ui/Card' # Name Wrapper Expiry In order to burn any fuses on a name, you must also set an **expiry** on it. This expiry determines how long any burned fuses are active for, and may also determine whether the name itself has expired. If the name is a .eth 2LD, then the expiry will automatically be set to the same expiry in the .eth Registrar. But for all other names, the parent can choose what expiry to set for a child name. ## Max Expiry for Subnames By default, the expiry for a name can only be set by the parent, and can only be increased, not decreased. The maximum value for the expiry of a name is the expiry of its parent name. For example, say a name expires in 5 years. The owner of the name can then set the expiry of its subnames to a maximum of 5 years as well. But the parent could also choose to set the expiry to something less. Let's say the parent sets the expiry of one of its subnames to 2 years. Then in turn, the owner of the subname can set the expiry of its own subnames up to a maximum of 2 years, but it could also set it to something less, like 1 year. Expiry Diagram The parent can set a different expiry for different subnames too, just as it can burn different fuses for different subnames. ## Renewals When a wrapped .eth second-level name (like `name.eth`) is renewed, that new expiry is automatically set in the Name Wrapper as well as in the .eth Registrar. However, the expiry for any other .eth names (like `sub.name.eth`) will not be automatically extended when the parent expiry is extended. The parent can extend the expiry for an existing subname at any time, even if the subname has been emancipated. The parent can also choose to approve a separate contract to allow the expiry for subnames to be extended by the subname owner or other accounts. That is basically how .eth second-level names work: Since the `eth` node is locked in the registrar contract and has the Name Wrapper (which exposes a renew method) approved as a controller, .eth second-level names can be directly renewed by their owners. The parent can further lock this approved contract in by burning the **`CANNOT_APPROVE`** fuse. There is also a special parent-controlled fuse called **`CAN_EXTEND_EXPIRY`**. If the parent burns this fuse on a subname, then the owner of that subname (or any approved controller) can also extend the expiry. So, if you are running a subname registrar and you want to enable "unruggable renewals", you can use one of the above options (or both). ## Special Cases for .eth 2LDs For .eth second-level names, the end of the name's grace period (from the .eth Registrar) is used for the expiry inside of the Name Wrapper. So if the name's expiration date in the Registrar is January 1st, then the expiry in the Name Wrapper will reflect that date _plus_ the grace period (currently 90 days, so approximately April 1st, depending on the year). When the name's expiration date (from the .eth Registrar) has been reached, and the name is now in the grace period, all Name Wrapper operations on the name will be restricted. The owner will _not_ yet lose ownership of the name, but they will also not be able to unwrap or update the name until it has been renewed. ## Expiry Implications When a name is merely **Wrapped** but not **Emancipated** or **Locked**, parent-controlled fuses can still be burned. This means that the parent can burn a custom fuse for a limited amount of time. When the expiry (end of grace period for .eth 2LDs) is reached, all fuses will be reset, but the name will otherwise be unaffected. When a name is **Emancipated** or **Locked**, the expiry has an important additional effect. In this scenario, when the expiry (end of grace period for .eth 2LDs) has been reached, **the name itself will expire**, and the owner **loses ownership** of the name. --- # Name Wrapper Use-Cases ## Lock the resolved records for a name By default, newly registered names will use the Public Resolver, which just allows the current manager/controller of the name to update any records. However, in some cases perhaps you want to make sure that a name resolves to specific records and **never** changes. You can accomplish this with the **`CANNOT_SET_RESOLVER`** fuse. Say you own `mycoolcontract.eth` representing a smart contract. You can use ENS subnames to refer to specific versions of that contract, like `1.mycoolcontract.eth`. And perhaps you want those versioned subnames to always point to: - The ETH address of that immutable contract - The ABI for that contract - The contenthash for some versioned documentation page - etc. One way to do this is just to make sure the name is **Locked**, all the records are set correctly, and then transfer the owner to some burn address so it can never be updated again. But of course this isn't ideal, because maybe there are some records that you _do_ want to update in the future. Or maybe you still want to keep ownership of that subname for other reasons. Instead of essentially burning the name, you could create a custom resolver that locks in certain records forever. Then: 1. Set the resolver of that name to your custom contract 2. Set the records however you want and lock them into the resolver 3. Burn these fuses on the name: - `PARENT_CANNOT_CONTROL | CANNOT_UNWRAP | CANNOT_SET_RESOLVER` Now you can still keep ownership and even some limited management power over the name, while still guaranteeing that the ETH address, ABI, and whatever other records are completely immutable, as long as the expiry is set appropriately. ## Issue subdomains as tickets to an event Maybe you have `mycoolevent.eth` and you want to issue tickets like `1.ticket.2023.mycoolevent.eth`. If you want, you can choose to not Emancipate those subnames, but still burn some custom parent-controlled fuses. Those fuses might: - Indicate what "tier" their event ticket is - Maybe they can upgrade their ticket to a higher tier, which would burn some additional fuses - Allow them access to the express line or some VIP room - Maybe even automatically via some smart door When you burn those fuses, perhaps you also set the expiry to the day after the event ends. Or, maybe you want your attendees to be able to keep their subnames as a souvenir or proof-of-attendance! If so, then instead of letting the names expire at the end of the event, you could extend the expiry and burn some additional fuses to allow the attendees to keep them forever! In that case you might want to burn these fuses: - `CAN_EXTEND_EXPIRY | PARENT_CANNOT_CONTROL` If you want those tickets to be non-transferrable (soulbound to the address that attended), then burn these fuses: - `CAN_EXTEND_EXPIRY | PARENT_CANNOT_CONTROL | CANNOT_UNWRAP | CANNOT_TRANSFER` ## Sell or rent subnames ### I want to sell / rent out subnames! Say you own the wrapped name `verypopularname.eth`. Obviously you can just manually create wrapped subnames like `my.verypopularname.eth` and then sell them on an NFT marketplace. But that sure doesn't scale well. To accomplish this, you will want to create a **subname registrar**. This is a contract that will handle all the registration / renewal for you, and then users will be able to interact with that contract in order to register their own subnames. In fact, this is exactly how .eth 2LDs are registered. The owner of the `eth` TLD (the NFT contract) delegates registration / renewal to the ETHRegistrarController contract. It is acting as a subname registrar for the name `eth`. Your contract would expose a `register` method that anyone can call. Under the hood it will use the [setSubnodeOwner](https://github.com/ensdomains/ens-contracts/tree/master/contracts/wrapper#setsubnodeowner) or [setSubnodeRecord](https://github.com/ensdomains/ens-contracts/tree/master/contracts/wrapper#setsubnoderecord) methods to create subnames, passing in the **fuses** and **expiry** you want to set. ### What fuses should I burn??? First, note that if you want to burn any fuses on subnames, then your name must be **Locked** (meaning **`CANNOT_UNWRAP`** is burned). Assuming that you want your subnames to be "unruggable", such that you cannot replace / revoke them, then you will want to burn **`PARENT_CANNOT_CONTROL`** on the subnames. This will place them in the **Emancipated** state upon registration. If you want to sell "forever" subnames, where users register once and can then keep them for as long as they wish, then you can consider burning the **`CAN_EXTEND_EXPIRY`** fuse. This will allow the subname owner to extend their own expiry whenever they want. The max expiry is the expiry of the parent name, but the .eth Registrar allows _anyone_ to renew/extend a .eth 2LD as well. If you just want to **rent** subnames, then do not burn **`CAN_EXTEND_EXPIRY`**. Instead, you could include a `renew` method on your contract that users can call for another fee. If you want to enable "unruggable renewals" for your registrar, to guarantee that users will always be able to renew, then you can call `approve` on the Name Wrapper and approve your registrar contract as the "subname renewal manager" for your name. Then, burn the **`CANNOT_APPROVE`** fuse on your name, to guarantee that you can never revoke that contract for subname renewals. See the Approved Operators section above for more info. If you want to impose other restrictions on your registered subnames, then you can burn the **`CANNOT_UNWRAP`** fuse to Lock the subname, and also burn whatever other fuses you want. For example, if you want to prevent owners of your subnames (like `my.verypopularname.eth` from creating their own subnames (like `buy.my.verypopularname.eth`), then you would burn **`CANNOT_UNWRAP`** and **`CANNOT_CREATE_SUBDOMAIN`**. To recap on fuses... - Sell permanent names: - `CAN_EXTEND_EXPIRY | PARENT_CANNOT_CONTROL` - Sell permanent names, but prevent them from creating their own subnames: - `CAN_EXTEND_EXPIRY | PARENT_CANNOT_CONTROL | CANNOT_UNWRAP | CANNOT_CREATE_SUBDOMAIN` - Rent out names: - `PARENT_CANNOT_CONTROL` - Rent out names, but prevent them from transferring or reselling them: - `PARENT_CANNOT_CONTROL | CANNOT_UNWRAP | CANNOT_TRANSFER` And so on, it's up to you. You can also burn whatever custom parent-controlled or owner-controlled fuses you want to. ### Can I customize my own rules and fees? Yes! It's your registrar contract, so you can impose whatever rules and fees you want. For example, the .eth Registrar imposes a 3-character minimum on all names, as well as a custom fee structure and a temporary premium auction upon expiration. By default there is no character limit on subnames, but your contract could have its own rules and fee structure or whatever you want. For example, you can: - Allow or disallow specific addresses from registering / renewing - Only allow registration based on some custom criteria like holding a specific NFT - Custom length restrictions like only 3+ characters or < 100 characters - Only allow names with characters `[a-z0-9]` and nothing else - Use a custom fee structure based on: - The length of the name - The specific characters that are in the name, like emojis - A pre-curated list of "good" names like people's first names - And whatever other rules you want. ### More information See this page for a step-by-step guide on creating and setting up your own subname registrar: Creating a Subname Registrar There is even a set of reference implementation contracts you can use as a starting base! ## Give subnames out to NFT holders ### I want to give subnames out to all of my DAO members / NFT holders! Say you own the wrapped name `mycoolnft.eth`, representing a popular NFT project you created. You want to distribute subnames like `6529.mycoolnft.eth` to all holders. One option is to just bulk create the subnames and drop the wrapped NFTs into their wallets. This might be good at least as an initial drop, because then the holders don't need to interact with any contract or spend any gas, you're doing that for them! To create the subnames, you'd use the setSubnodeOwner or setSubnodeRecord methods. You must also decide: ### How much control over the subnames do you want to relinquish? Do you want to be able to revoke subnames? Or do you want them to be completely outside your control? One thing to consider is whether you want the **current** holder of your NFT to always be able to claim/reclaim the corresponding ENS subname. If so, then you will **not** want to Emancipate those subnames (in other words, do not burn **`PARENT_CANNOT_CONTROL`**). If the subname is Emancipated, then the NFT holder could sell/transfer the NFT but keep the subname (up until the expiry). To make it easy for anyone to claim/reclaim a subname after your initial drop, you can set up a contract for this. ### Setting up a subname claim contract The claim method of your contract could: 1. Call `ownerOf` or `balanceOf` on your NFT contract to get or verify the current owner of the NFT 2. Call `ownerOf` or `balanceOf` on the ENS Name Wrapper contract to get or verify the current owner of the wrapped subname - If both owner addresses are the same, just return, nothing to do 3. Call `setSubnodeOwner` or `setSubnodeRecord` on the ENS Name Wrapper: - **owner:** The current owner of the NFT - **fuses:** What fuses you want to burn (if any) on that subname. If you burn any fuses, you must also set an expiry. - **expiry:** When the subname will expire. Then, to give that contract access to create subnames on your behalf, you would call `setApprovalForAll` on the Name Wrapper to approve your contract as an operator. Now, even if the NFT gets sold / transferred, the new owner will be able to claim their `mycoolnft.eth` subname at any time. In addition, if you expand your NFT collection in the future and there are new owners, then those new owners would be able to claim their subnames as well. If you are creating a new NFT contract, you could even bake this functionality **directly into the NFT contract** too, instead of needing a separate contract! By doing this, you wouldn't need a separate `claim` method either, your NFT contract would just **automatically transfer the wrapped ENS subname** whenever the NFT itself gets transferred! ### Giving your subname owners perks If you decide to not Emancipate the subnames that you issue, you _will_ still be able to burn any Parent-Controlled Fuses. There are 13 unreserved parent-controlled fuses that you can use however you wish! For example, perhaps you want to grant on-chain "perks" or "roles" to certain holders. You would call [setChildFuses](https://github.com/ensdomains/ens-contracts/tree/master/contracts/wrapper#setchildfuses) on the Name Wrapper and pass in the fuses you want to burn, and the expiry. This means that those "perks" or "roles" can also be time-boxed if you want. Maybe a perk expires in 1 week or something, up to you. There is also the reserved **`CAN_EXTEND_EXPIRY`** parent-controlled fuse. If you burn this, then the subname owner will be able to extend their own expiry whenever they want. --- # Name Wrapper Contract Details The Name Wrapper contract is deployed on these chains: - Mainnet: [wrapper.ens.eth](https://etherscan.io/address/0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401#code) ( `0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401` ) - Sepolia: [wrapper.ens.eth](https://sepolia.etherscan.io/address/0x0635513f179D50A207757E05759CbD106d7dFcE8#code) ( `0x0635513f179D50A207757E05759CbD106d7dFcE8` ) ## Wrapping and Unwrapping When wrapping a .eth 2LD, you transfer the Owner (Registrant) of the ERC-721 NFT to the Name Wrapper contract. The contract will then automatically take over the Manager (Controller) for the name as well. You can do this by calling the wrapETH2LD method. Or, you can directly transfer the ERC-721 NFT to the Name Wrapper contract. In return, the contract issues you an ERC-1155 NFT. ```solidity NameWrapper.wrapETH2LD(string label, address wrappedOwner, uint16 ownerControlledFuses, address resolver) // For example wrapETH2LD( "myname", // "myname.eth" but only the label 0x1234..., // The address you want to own the wrapped name 0, // The owner-controlled fuse bits OR'd together, that you want to burn 0x1234... // The address of the resolver you want to use ) ``` When wrapping any other ENS name, you transfer the Manager (Controller) of the name to the Name Wrapper contract. You can do this by calling the wrap method. In return, the contract issues you an ERC-1155 NFT. ```solidity NameWrapper.wrap(bytes name, address wrappedOwner, address resolver) // For example wrapETH2LD( 0x03737562046e616d650365746800, // The DNS-encoded version of "sub.myname.eth" 0x1234..., // The address you want to own the wrapped name 0x1234... // The address of the resolver you want to use ) ``` As the owner of the wrapped name, you can unwrap at any time by calling either unwrapETH2LD or unwrap. You can do this as long as the permission to unwrap has not been revoked. ```solidity NameWrapper.unwrapETH2LD(bytes32 labelhash, address registrant, address controller) // For example unwrapETH2LD( 0x952f..., // "myname.eth" but only the labelhash: keccak256('myname') 0x1234..., // The address you want to own the unwrapped name 0x1234... // The address you want to be the manager of the unwrapped name ) NameWrapper.unwrap(bytes32 parentNode, bytes32 labelhash, address controller) // For example unwrap( 0x6cbc..., // The namehash of the parent node, e.g. "myname.eth" 0xfa1e..., // The labelhash of the child to unwrap, e.g. keccak256('sub') 0x1234... // The address you want to be the manager of the unwrapped name ) ``` ## Burning Fuses / Setting Expiry If you are wrapping an existing .eth 2LD, then you can pass in the owner-controlled fuses at that time, see the above [Wrapping and Unwrapping](#wrapping-and-unwrapping) section. If you are creating a new subname, and you want to burn fuses at the same time, see the below [Creating Subnames](#creating-subnames) section. For other existing wrapped names, you can burn fuses with either the `setFuses` or `setChildFuses` methods. The `setFuses` method is used for a name that you own, but you do not necessarily own the parent of. You have the ability to burn any [Owner-Controlled Fuses](/wrapper/fuses#owner-controlled-fuses) you want. Note that your name must first be [Emancipated](/wrapper/states#emancipated) in order for you to be able to burn any owner-controlled fuses. All .eth 2LDs are automatically emancipated upon wrapping. When burning owner-controlled fuses, at a minimum you must burn the **`CANNOT_UNWRAP`** fuse (if it has not already been burned). ```solidity NameWrapper.setFuses(bytes32 node, uint16 ownerControlledFuses) // For example setFuses( 0x6cbc..., // The namehash of the node, e.g. "myname.eth" 1 // The owner-controlled fuse bits OR'd together, that you want to burn ) ``` The `setChildFuses` method is used for a subname that you own the parent of. As long as the subname has not yet been [Emancipated](/wrapper/states#emancipated), you can burn whatever [Parent-Controlled Fuses](/wrapper/fuses#parent-controlled-fuses) and [Owner-Controlled Fuses](/wrapper/fuses#owner-controlled-fuses) you want. At the same time, you must set an expiry for those fuses, if one is not already set. Note that your name must first be [Locked](/wrapper/states#locked) in order for you to burn fuses on any subnames. If you are only burning parent-controlled fuses, then there are no further restrictions. However, if you are burning owner-controlled fuses, then you must at a minimum burn both **`PARENT_CANNOT_CONTROL`** and **`CANNOT_UNWRAP`** on the subname to lock it at the same time. ```solidity NameWrapper.setChildFuses(bytes32 parentNode, bytes32 labelhash, uint32 fuses, uint64 expiry) // For example setChildFuses( 0x6cbc..., // The namehash of the parent node, e.g. "myname.eth" 0xfa1e..., // The labelhash of the child, e.g. keccak256('sub') 65537, // The fuse bits OR'd together, that you want to burn 2021232060 // The expiry for the subname ) ``` ## Creating Subnames This is done very similarly to how unwrapped subnames are created. You call either `setSubnodeOwner` or `setSubnodeRecord` on the wrapper contract. When a name is wrapped, all subnames created will also be wrapped by default. You can also pass in the fuses and expiry at the same time, so that the subname will be created in the fuse/permission state that you want, without needing to perform an extra transaction. ```solidity NameWrapper.setSubnodeOwner(bytes32 parentNode, string label, address owner, uint32 fuses, uint64 expiry) // For example setSubnodeOwner( 0x6cbc..., // The namehash of the parent node, e.g. "myname.eth" "sub", // The label of the subname to create 0x1234..., // The address you want to be the owner of the new subname 65536, // The fuse bits OR'd together, that you want to burn 2021232060 // The expiry for the subname ) NameWrapper.setSubnodeRecord(bytes32 parentNode, string label, address owner, address resolver, uint64 ttl, uint32 fuses, uint64 expiry) // For example setSubnodeRecord( 0x6cbc..., // The namehash of the parent node, e.g. "myname.eth" "sub", // The label of the subname to create 0x1234..., // The address you want to be the owner of the new subname 0x5678..., // The address of the resolver to set for the new subname 0, // The TTL to set for the new subname 65536, // The fuse bits OR'd together, that you want to burn 2021232060 // The expiry for the subname ) ``` ## Approved Operators ### Full-Control Operator Batch Approvals Your wrapped name is an ERC-1155 NFT that supports the `setApprovalForAll` method. When you approve an address using this method, it will have **full control** over all wrapped ENS names that you own. This method is typically used by NFT marketplace contracts. ### Name-Specific Subname Renewal Manager Approvals The Name Wrapper also supports the ERC-721 `approve` method. This method is used to approve a single "Subname Renewal Manager" for a specific name. The "Renewal Manager" does not have full control over your wrapped name, it can only set / extend the expiry on subnames. Further, if you burn the **`CANNOT_APPROVE`** fuse on your name, then the approved renewal manager can no longer be changed. You can use this to "lock in" that contract, so that you can guarantee to all subname owners that renewals/extensions can always be done. This approved renewal manager will be reset if the wrapped NFT is burned or re-minted, which happens if you unwrap the name, or if an expired name gets re-registered. It will also be reset if the wrapped NFT is transferred, **unless** the **`CANNOT_APPROVE`** fuse is burned. ### Example - Subname Registrar Contract You can use these operator approval methods to setup a separate contract that can take certain actions on your behalf. One example is setting up a "subname registrar" to allow users to register/renew subnames. That subname registrar contract would act on your behalf and allow users to register subnames. To allow this, you would call `setApprovalForAll` to give that contract full control over your name (and thus the ability to create subnames). Then, to enable "unruggable renewals", you could call `approve` on that same contract (or a separate one specific to renewals if you wish) and burn **`CANNOT_APPROVE`** to lock in subname renewals for that contract. If you need to later on, you would still be able to revoke with `setApprovalForAll`. So the contract would lose full control over your name (and the ability to create new subnames), but it would still be able to perpetually renew/extend existing subnames. And you can do all of this **without** needing to send your wrapped NFT to that contract. --- # Wrapped States ```mermaid graph LR; unregistered((Unregistered)); unwrapped(Unwrapped); wrapped(Wrapped); emancipated(Emancipated); locked(Locked); unregistered--->|register|unwrapped; unwrapped--->|wrap|wrapped; wrapped--->|unwrap|unwrapped; wrapped--->|protect|emancipated; emancipated--->|lock|locked; emancipated--->|unwrap|unwrapped; emancipated--->|expire|unregistered; locked-->|expire|unregistered; ``` Taking the Name Wrapper into account, an ENS name can be in one of these possible states: ### Unregistered The name has not even been registered/created yet, or it has expired. ### Unwrapped The name exists and has not expired (in the case of .eth second-level names). The Name Wrapper contract does not have ownership over the name. You own the name in the registry and/or .eth registrar. ### Wrapped The Name Wrapper contract has ownership of the name (in the registry/registrar). You are issued an ERC-1155 NFT in return, which proves that you are the actual owner. You can unwrap the name at any time, which burns the ERC-1155 NFT, and returns ownership in the registry/registrar back to you. If your name is a subname like `sub.name.eth`, then the owner of `name.eth` can technically replace the subname and transfer it to a different owner. In addition, the parent owner can burn parent-controlled fuses on your name. ### Emancipated The owner of the parent name is no longer able to replace this name, or burn any additional fuses on it. All .eth second-level names (like `name.eth`) are automatically put into the Emancipated state when they are wrapped. The name can still be unwrapped and rewrapped by the owner. ### Locked The name can no longer be unwrapped. The owner can now burn owner-controlled fuses on the name. Fuses for subnames of this name can now be burned as well. --- import { Card } from '../../components/ui/Card' # Name Wrapper Overview :::note Are you looking for user-facing guides on how to interact with the Name Wrapper in the ENS Manager App? If so, see here instead: Name Wrapper Guides :::