Developer Guide
Guides
Assign Name for Contract

How to Assign a .vet Name to Your Contract

The following steps outline the process for automatically managing name assignments for a contract project.

You will:

  1. Assign management permissions to a private key within your deployment project.
  2. Dynamically create subdomains.
  3. Assign forward-pointing records for subdomains.
  4. Assign reverse records for the contract, pointing to a subdomain.

The addresses for the contracts on TestNet and MainNet are available in the Contracts section.

To test the resolution of a name or address, visit vet.domains/lookup (opens in a new tab) or, for TestNet, testnet.vet.domains/lookup (opens in a new tab).

Creating Management Permissions

By assigning management permissions to the address associated with your deployment project, you enable the ability to programmatically manage naming records.

Option 1: Creating a Subdomain

Create a subdomain to isolate all contracts, which can then be managed using your deployment keys.

Create Subdomain

Option 2: Assigning Name Manager

Alternatively, assign the name manager to your deployment keys. Name managers can be configured in the Ownership section. The advantage of appointing a name manager without transferring ownership is the capability to reclaim full ownership if necessary.

Ownership

Creating a Subdomain for Your Contract

The initial step involves generating a new subdomain specifically for your newly deployed contract. This action is performed on the Registry Contract.

Here is the function definition:

function setSubnodeRecord(
    bytes32 node,
    bytes32 label,
    address owner,
    address resolver,
    uint64 ttl
) external;

With setSubnodeRecord you will pass:

  • node: the namehash of the parent domain
  • label: the hash of your the new subdomain
  • owner: the new owner of the subdomain
  • resolver: the responsible resolver, should be the PublicResolver
  • ttl: time to live setting, indicating clients on how long it is suggested to cache results

Below is an example from a Hardhat script:

import { namehash, id } from "ethers";
// ..
const registry = await hre.ethers.getContractAt(Registry.abi, REGISTRY_ADDRESS)
await registry.setSubnodeRecord(namehash('contracts.demo.vet'), id('mytoken'), owner, PUBLIC_RESOLVER_ADDRESS, 0)

Assigning a Forward Record

You can configure the newly created subdomain with records by utilizing the setAddr() function at the specified resolver.

Here is the function definition:

function setAddr(
    bytes32 node,
    address a
) external virtual authorised(node) {
    setAddr(node, COIN_TYPE_ETH, addressToBytes(a));
}

When utilizing setAddr, the following parameters must be supplied:

  • node: the namehash of the new subdomain including its parent domain
  • a: the address record to which it will point

Below is an example from a Hardhat script:

import { namehash, id } from "ethers";
// ..
const publicResolver = await hre.ethers.getContractAt(PublicResolver.abi, PUBLIC_RESOLVER_ADDRESS)
await publicResolver.setAddr(namehash('token.contracts.demo.vet'), contractAddress);

Assign a Reverse Record

To close the loop, the contract's address must be linked to the newly created subdomain. This is achieved through the Reverse Registrar contract and its setNameForAddr() function.

Here is the function definition:

function setNameForAddr(
    address addr,
    address owner,
    address resolver,
    string memory name
) external returns (bytes32);

When using setNameForAddr, you need to provide:

  • addr: The contract address for which you are setting the primary name.
  • owner: The owner of the reverse node in the Registry.
  • resolver: The resolver to be used for the reverse node, typically the Public Resolver.
  • name: The primary name to be assigned to the contract. This name must already forward-resolve to the contract address for the Primary Name resolution to work correctly.

Below is an example from a Hardhat script:

import { namehash, id } from "ethers";
// ..
const reverseRegistrar = await hre.ethers.getContractAt(ReverseRegistrar.abi, REVERSE_REGISTRAR_ADDRESS)
await reverseRegistrar.setNameForAddr(contractAddress, owner, PUBLIC_RESOLVER_ADDRESS, FULL_CONTRACT_NAME);

Example Hardhat Script

Below is a single script that combines the example snippets for a test deployment.

For simplified interaction, the script utilizes the official ENS module @ensdomains/ens-contracts, which has been installed (yarn add @ensdomains/ens-contracts) into the project for their interfaces.

import hre from "hardhat";
 
// import interfaces for contract interactions
import ReverseRegistrar from "@ensdomains/ens-contracts/artifacts/contracts/reverseRegistrar/ReverseRegistrar.sol/ReverseRegistrar.json"
import PublicResolver from "@ensdomains/ens-contracts/artifacts/contracts/resolvers/PublicResolver.sol/PublicResolver.json"
import Registry from "@ensdomains/ens-contracts/artifacts/contracts/registry/ENSRegistry.sol/ENSRegistry.json"
 
// import ethers hashing helpers
import { namehash, id } from "ethers";
 
// contract addresses are available on: https://docs.vet.domains/Developers/Contracts/
const REVERSE_REGISTRAR_ADDRESS = "0x6878f1aD5e3015310CfE5B38d7B7071C5D8818Ca"   // TestNet address
const PUBLIC_RESOLVER_ADDRESS = "0xA6eFd130085a127D090ACb0b100294aD1079EA6f"     // TestNet address
const REGISTRY_ADDRESS = "0xcBFB30c1F267914816668d53AcBA7bA7c9806D13"            // TestNet address
 
async function main() {
    // deploy a sample contract "MyToken"
    const nft = await hre.ethers.deployContract("MyToken", [], {});
    const tx = await nft.deploymentTransaction();
    const receipt = await hre.ethers.provider.getTransactionReceipt(tx!.hash);
 
    const contractAddress = receipt!.contractAddress
    console.log(`NFT deployed to ${contractAddress}`);
 
    // define the contracts subdomain name
    const CONTRACT_NAME = 'test-deployment'
 
    // and the parent name
    const BASE_NAME = 'contracts.demo.vet'
 
    // both joined result in the full domain name
    const CONTRACT_SUBDOMAIN = [CONTRACT_NAME, BASE_NAME].join('.')
    console.log(`Setting name for ${contractAddress} to ${CONTRACT_SUBDOMAIN}`);
 
    // get the address of the current signer been used
    const owner = (await hre.ethers.provider.getSigner()).address
 
    // create subnode
    const registry = await hre.ethers.getContractAt(Registry.abi, REGISTRY_ADDRESS)
    await registry.setSubnodeRecord(namehash(BASE_NAME), id(CONTRACT_NAME), owner, PUBLIC_RESOLVER_ADDRESS, 0)
 
    // set forward record
    const publicResolver = await hre.ethers.getContractAt(PublicResolver.abi, PUBLIC_RESOLVER_ADDRESS)
    await publicResolver.setAddr(namehash(CONTRACT_SUBDOMAIN), contractAddress);
 
    // set reverse entry
    const reverseRegistrar = await hre.ethers.getContractAt(ReverseRegistrar.abi, REVERSE_REGISTRAR_ADDRESS)
    await reverseRegistrar.setNameForAddr(contractAddress, owner, PUBLIC_RESOLVER_ADDRESS, CONTRACT_SUBDOMAIN);
 
}
 
main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exitCode = 1;
    })