Registrar Frequently Asked Questions

About the Domains Registrar

How many transactions are required to register a .tomi name?

The registrar uses two transactions (commit and reveal) to register a name.

How long does it take to register a name using the .tomi registrar?

It takes less than 5 minutes to register a name, including a 1-minute delay between the first and second transactions to prevent frontrunning. Do we need to do anything to ensure the continued use of existing Domains names?

Make sure you renew your Domains names before they expire! You add registration years to any name at any time, and for any duration you'd like. What happens if I have several Domains names with different renewal dates?

You can add registration years to many names at a time on your My Account page in the Domains Manager App. How do renewals work?

Anyone can add registration years to any existing name by paying the required fee, at any time.

There is no maximum limitation of the renewal duration but there is a minimum renewal period of 28 days. Can someone grab my domains at the end of my subscription period?

You can renew your name at any time during the period you own it. Making sure you renew before the name expires will prevent someone else from registering the name.

There is also a 'grace period' of 90 days after your name expires. You can renew the name to retain ownership of it during the grace period. How will Domains team manage and spend the funds? Will there be a foundation or transparent oversight?

It will be spent through the Dao. How are funds from .tomi registration income used?

It's ultimately up to the keyholders to allocate the funds. We hope they will fund Domains ecosystems projects. If available funds exceed the reasonable needs of the Domains ecosystem, we hope other Ethereum projects will receive them. Where can I manage all my Domain names?

Simply go to https://domains.tomi.com/ and click on "My Account". Can I trade Domain domains on NFT exchanges?

Yes, .com .tomi names are tradeable as NFTs. How can I transfer domains registered in the .tomi registry to someone else?

You can do this using our Manager interface here, or using any tool with NFT support. What prohibits large-scale domain grabbing besides registration fees?

The cost of doing this is the only limitation in place. What is the "registrant" and "controller" of a name?

The registrant is the account that owns the .tomi name. They can transfer ownership to another account, and they can replace the controller address. The registrant is the owner of the NFT token that represents the name.

The controller is the account that controls day-to-day operations with the name: creating subdomains, setting the resolver and records, and so forth.

Deploy the Registry

The registry is the Domains central component and stores, among other things, who owns which domain. This is the example using ethers and hardhat.

const TDNSRegistry = await ethers.getContractFactory("TDNSRegistry")
await TDNSRegistry.deploy()

Once deployed, you will have a fresh Domains registry, whose root node is owned by the account that submitted the transaction. This account has total control over the Domains registry - it can create and replace any node in the entire tree.

From here, it's possible to create and manage names by directly interacting with the registry, as described in Managing Names. However, you will probably want to deploy a resolver, and you may want to deploy a registrar so other users can register names.

Deploy a Resolver

Records in the registry can point to resolver contracts which store additional domain information. The most common use-case is to store an address for a domain, but storing a contract ABI or text is also possible. For most purposes on private networks it's convenient to have an unrestricted general-purpose resolver available. Deploying one is straightforward:

const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
const TDNSRegistry = await ethers.getContractFactory("TDNSRegistry")
const registry = await TDNSRegistry.deploy()
await registry.deployed()
const PublicResolver = await ethers.getContractFactory("PublicResolver")
const resolver = await PublicResolver.deploy(registry.address, ZERO_ADDRESS);
await resolver.deployed()

The PublicResolver looks up ownership in the registry, which is why the registry's address is required at deployment.

For ease of use, we can give this resolver a name:

const ethers = require('ethers');
const utils = ethers.utils;
const labelhash = (label) => utils.keccak256(utils.toUtf8Bytes(label))
const namehash = require('eth-ens-namehash');

async function setupResolver(tdns, resolver, accounts) {
 const resolverNode = namehash.hash("resolver");
 const resolverLabel = labelhash("resolver");

 await tdns.setSubnodeOwner("0x0000000000000000000000000000000000000000", resolverLabel, 
 await tdns.setResolver(resolverNode, resolver.address);
 await resolver.setAddr(resolverNode, resolver.address);
}

Above, we first create a new top-level domain, "resolver", then set its resolver address to our newly deployed public resolver. Finally, we set up an address record for "resolver", pointing back to the resolver address. In effect, the resolver is answering queries about its own address. After this, anyone can find the public resolver at the special Domains name "resolver". We call this function after deploying the public resolver in a .then() block as we did with the resolver.

Deploy a Registrar

So far, domains can only be registered manually by the owner of the registry's root node. Fortunately, contracts can also own nodes. This means we can set up a registrar contract as the owner of a node, e.g. "test", in the registry which enables it to distribute subdomains such as "mycontract.test". It allows us to have custom, on-chain logic which governs domain allocation. Once we own a (sub-)node we are free to repeat this process and set up another registrar. If you are part of the "myorg" organisation you could register "myorg.test" and let it point to your custom registrar which only allows certified members of your organisation to claim subdomains such as "bob.myorg.test". For our private network, we'll use the simple 'first come, first served' FIFSRegistrar, and set it as the owner of the top-level domain "test" in our migration script:

...
 const registrar = await FIFSRegistrar.deploy(tdns.address, namehash.hash("test"));
 await registrar.deployed();
 await tdns.setSubnodeOwner("0x0000000000000000000000000000000000000000", sha3("test"), registrar.address);
})
...

Deploy the Reverse Registrar

Similarly, if you wish to enable reverse resolution on your deployment, you will need to deploy the reverse registrar:

...
const reverseRegistrar = await ReverseRegistrar.deploy(tdns.address, resolver.address);
await reverseRegistrar.deployed();
setupReverseRegistrar(tdns, resolver, 
async function setupReverseRegistrar(tdns, resolver, reverseRegistrar, accounts) {
  await tdns.setSubnodeOwner("0x0000000000000000000000000000000000000000", utils.sha3("reverse"), accounts[0]);
  await tdns.setSubnodeOwner(namehash.hash("reverse"), utils.sha3("addr"), reverseRegistrar.address);
}

Migration File Example

We can combine the steps above in a single hardhat migration file. This allows us to deploy Domains in one go:

script/deploy.js

const ethers = hre.ethers;
const utils = ethers.utils;
const labelhash = (label) => utils.keccak256(utils.toUtf8Bytes(label))
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
const ZERO_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000";
async function main() {
const TDNSRegistry = await ethers.getContractFactory("TDNSRegistry")
const FIFSRegistrar = await ethers.getContractFactory("FIFSRegistrar")
const ReverseRegistrar = await ethers.getContractFactory("ReverseRegistrar")
const PublicResolver = await ethers.getContractFactory("PublicResolver")
const signers = await ethers.getSigners();
const accounts = signers.map(s => s.address)
const tdns = await TDNSRegistry.deploy()
await tdns.deployed()
const resolver = await PublicResolver.deploy(tdns.address, ZERO_ADDRESS);
await resolver.deployed()
await setupResolver(tdns, resolver, accounts)
const registrar = await FIFSRegistrar.deploy(tdns.address, namehash.hash(tld));
await registrar.deployed()
await setupRegistrar(tdns, registrar);
const reverseRegistrar = await ReverseRegistrar.deploy(tdns.address, resolver.address);
await reverseRegistrar.deployed()
await setupReverseRegistrar(tdns, registrar, reverseRegistrar, accounts);
};
async function setupResolver(tdns, resolver, accounts) {
const resolverNode = namehash.hash("resolver");
const resolverLabel = labelhash("resolver");
await tdns.setSubnodeOwner(ZERO_HASH, resolverLabel, accounts[0]);
await tdns.setResolver(resolverNode, resolver.address);
await resolver['setAddr(bytes32,address)'](resolverNode, resolver.address);
}
async function setupRegistrar(tdns, registrar) {
await tdns.setSubnodeOwner(ZERO_HASH, labelhash(tld), registrar.address);
}
async function setupReverseRegistrar(tdns, registrar, reverseRegistrar, accounts) {
await tdns.setSubnodeOwner(ZERO_HASH, labelhash("reverse"), accounts[0]);
await tdns.setSubnodeOwner(namehash.hash("reverse"), labelhash("addr"), reverseRegistrar.address);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

To execute the migration file on hardhat, run the following command line.

npx hardhat run scripts/deploy.js

Last updated