Naming Contracts
While it's commonly known that regular user accounts can have primary names, it's less known that smart contracts can also have names.
In order for you to manage the primary name of your smart contract, you need to own the reverse node for the contract address. There are several ways of doing this, depending on if you are actively developing your contract or if it is already deployed.
Reverse names are just half of ENS primary names. Remember that you always must set the ETH address of your name to the address at which your contract was deployed.
Depending on your use case, there are a few different approaches to setting the primary name of a new smart contract.
First, let's assume you want to be able to change the name in the future. The two ways to do this are:
- Take ownership of the reverse node (
{address}.addr.reverse
) for the contract address. - (Recommended) Make the contract Ownable, which is may already be, and set the owner to yourself.
The Ownable approach is recommended because it's possible that your contract will already have it implemented, and Etherscan will index the events correctly.
If you are deploying a new contract that does not have any admin permissions, and you don't want to be able to change the name in the future, you can set the reverse name in the constructor of the contract directly.
Let's look at a few examples.
While this method works perfectly at the ENS protocol level, Etherscan does not index the contract events correctly so it may not appear in their UI.
This is a simple drop-in module that transfers ownership of the reverse node to an address of your choice, which can then update the reverse name at any time.
import "@ensdomains/ens-contracts/contracts/registry/ENS.sol";
import "@ensdomains/ens-contracts/contracts/reverseRegistrar/ReverseClaimer.sol";
contract MyContract is ReverseClaimer {
constructor (
ENS ens
) ReverseClaimer(ens, msg.sender) {}
}
When you deploy your contract, the deployer account (msg.sender
) will be given ownership of the reverse node for that contract address. This gives you authorization to call setName(node, newName)
on the latest public resolver (resolver.ens.eth), where node
is the reverse node for the contract address and newName
is the name you want to set it to.
To find the reverse node for your contract address, you can use the following viem script:
import { namehash } from 'viem/ens'
import { Hex, keccak256 } from 'viem'
function getNodeFromParentNodeAndLabelhash(parentNode: Hex, labelhash: Hex) {
return keccak256((parentNode + labelhash.split('0x')[1]) as Hex)
}
const myContractAddress = '0x...' // replace with your contract address
const node = getNodeFromParentNodeAndLabelhash(
namehash('addr.reverse'),
labelhash(myContractAddress.slice(2).toLowerCase())
)
console.log(node)
An example of this is ownable.contract.gtest.eth
If you want to be able to change the name in the future, you can make your smart contract Ownable.
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract Contract is Ownable {
constructor(address initialOwner) Ownable(initialOwner) {}
}
The ReverseRegistrar supports the Ownable interface and will let the owner
of a contract set its primary name without having to add any ENS-specific code.
Once this contract is deployed, call setNameForAddr(address, address, address, string)
on the Reverse Registrar (reverse.ens.eth) from your authorized owner account.
- The first address argument is the address of your contract
- The second address argument is the owner of your smart contract
- The third address argument is the
defaultResolver()
from the Reverse Registrar - The fourth argument is the ENS name to set it to
An example of this contract.gtest.eth
If you don't want to be able to change the name in the future, you can inherit the following contract and assign an ENS name directly in the constructor.
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
interface ENS {
function owner(bytes32 node) external view returns (address);
}
interface IReverseRegistrar {
function setName(string memory name) external returns (bytes32);
}
// Variation of ReverseClaimer.sol from @ensdomains/ens-contracts that sets the reverse name directly.
contract ReverseSetter {
/// @dev The ENS registry
ENS private constant ens = ENS(0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e);
/// @dev Output of namehash("addr.reverse")
bytes32 private constant ADDR_REVERSE_NODE =
0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;
/// @param name The reverse name to set for this contract's address.
constructor(string memory name) {
IReverseRegistrar reverseRegistrar = IReverseRegistrar(
ens.owner(ADDR_REVERSE_NODE)
);
reverseRegistrar.setName(name);
}
}
Using this in your contract is as simple as:
import {ReverseSetter} from "./ReverseSetter.sol";
contract Contract is ReverseSetter {
constructor(string memory name) ReverseSetter(name) {}
}
If your contract is already deployed you might still be able to set a name for it. If your contract supports the Ownable interface from OpenZeppelin, read the section above.
If your contract is a Safe, Multisig, DAO, or has a function that can send arbitrary ETH calls, you can use the ReverseRegistrar contract directly to set a name for it. You might even be able to use the ENS Manager App inside of your safe app to set a primary name.