Developer Guide
Registrar

Base Registrar & Controller

The Base Registrar manages the .vet name space within an on-chain registy and the Registrar Controller allows trustless on-chain name registration by everyone.

Commit Reveal

The Registrar Controller implements a commit reveal scheme to prevent frontrunning. The way it works is that during the registration process we first call the commit function with an opaque bit of data (the commitmenthash). Wait one blocks 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 ensures no eavesdropping third-party is able to register your name before you can.

RegistrarController.makeCommitment(name string, owner address, duration uint256, secret bytes32, resolver address, data bytes[], reverseRecord bool, ownerControlledFuses uint16)
 
// For example
makeCommitment(
    "hello", // "hello.vet" but only the label
    0x1234..., // The address you want to own the name
    31536000, // 1 year (in seconds)
    0x1234..., // A secret that you have generated (32 bytes)
    0x1234..., // The address of the resolver you want to use
    [],
    false, // Set as primary name?
    0
);

Once you have calculated the commitment hash you can call the commit function.

RegistrarController.commit(commitment bytes32)

Note this does require an on-chain transaction. After having committed it is recommended to wait at least the MIN_COMMITMENT_AGE (~10 seconds) before registering.

Registering

Once you have committed you can register your name. Registration takes in the same parameters as the makeCommitment function, but this time is in the form of a transaction.

Before initiating registration ensure that:

  • available(name) == true
  • duration >= MIN_REGISTRATION_DURATION
  • commitments[commitment] is between 1 min and 24 hrs old
  • msg.value >= rentPrice(name, duration)
RegistrarController.register(name string, owner address, duration uint256, secret bytes32, resolver address, data bytes[], reverseRecord bool, ownerControlledFuses uint16)
 
// For example
register(
    "hello", // "hello.vet" but only the label
    0x1234..., // The address you want to own the name
    31536000, // 1 year (in seconds)
    0x1234..., // A secret that you have generated (32 bytes)
    0x1234..., // The address of the resolver you want to use
    [],
    false, // Set as primary name?
    0
);

Renewing a Name

RegistrarController.renew()

Any user, not solely the owner, has the capability to renew a domain. This enables you to renew a domain on behalf of someone else to prevent its expiration.

The system permits renewals for any chosen duration, ensuring that domain names remain active. Despite any updates to the controller, the separation between the registry and controller guarantees that your domain remains under your ownership.

Interface

pragma solidity >=0.8.4;
 
interface IRegistrarController {
    // Error to indicate the commitment is too new
    error CommitmentTooNew(bytes32);
 
    // Error to indicate the commitment is too old
    error CommitmentTooOld(bytes32);
 
    // Error to indicate the duration is too short
    error DurationTooShort(uint256);
 
    // Error to indicate the value sent with the transaction is insufficient
    error InsufficientValue();
 
    // Error to indicate the maximum commitment age is too high
    error MaxCommitmentAgeTooHigh();
 
    // Error to indicate the maximum commitment age is too low
    error MaxCommitmentAgeTooLow();
 
    // Error to indicate the name is not available for registration
    error NameNotAvailable(string);
 
    // Error to indicate a resolver is required when data is supplied
    error ResolverRequiredWhenDataSupplied();
 
    // Error to indicate an unexpired commitment exists
    error UnexpiredCommitmentExists(bytes32);
 
    // Event emitted when a name is registered
    event NameRegistered(string,bytes32 indexed,address indexed,uint256,uint256,uint256);
 
    // Event emitted when a name is renewed
    event NameRenewed(string,bytes32 indexed,uint256,uint256);
 
    // Function to get the minimum registration duration
    function MIN_REGISTRATION_DURATION() view returns (uint256);
 
    // Function to check if a name is available for registration
    function available(string) view returns (bool);
 
    // Function to commit a name registration
    function commit(bytes32);
 
    // Function to get the timestamp of a commitment
    function commitments(bytes32) view returns (uint256);
 
    // Function to make a commitment to register a name
    function makeCommitment(string,address,uint256,bytes32,address,bytes[],bool,uint16) pure returns (bytes32);
 
    // Function to get the maximum commitment age
    function maxCommitmentAge() view returns (uint256);
 
    // Function to get the minimum commitment age
    function minCommitmentAge() view returns (uint256);
 
    // Function to get the address of the name wrapper contract
    function nameWrapper() view returns (address);
 
    // Function to get the address of the prices contract
    function prices() view returns (address);
 
    // Function to register a name
    function register(string,address,uint256,bytes32,address,bytes[],bool,uint16) payable;
 
    // Function to renew a name registration
    function renew(string,uint256) payable;
 
    // Function to get the rent price for a name
    function rentPrice(string,uint256) view returns (tuple(uint256,uint256));
 
    // Function to get the address of the reverse registrar contract
    function reverseRegistrar() view returns (address);
 
    // Function to check if the contract supports an interface
    function supportsInterface(bytes4) pure returns (bool);
 
    // Function to check if a string is a valid name
    function valid(string) pure returns (bool);
 
    // Function to withdraw funds from the contract
    function withdraw();
}
pragma solidity >=0.8.4;
 
interface IBaseRegistrar {
    // Emitted when a token is approved to another address
    event Approval(address indexed, address indexed, uint256 indexed);
 
    // Emitted when an operator is approved or disapproved for all tokens
    event ApprovalForAll(address indexed, address indexed, bool);
 
    // Emitted when a name is migrated to a new registrar
    event NameMigrated(uint256 indexed, address indexed, uint256);
 
    // Emitted when a name is registered
    event NameRegistered(uint256 indexed, address indexed, uint256);
 
    // Emitted when a name is renewed
    event NameRenewed(uint256 indexed, uint256);
 
    // Emitted when a token is transferred from one address to another
    event Transfer(address indexed, address indexed, uint256 indexed);
 
    // Returns the grace period for renewals
    function GRACE_PERIOD() external view returns (uint256);
 
    // Approves a token to an address
    function approve(address, uint256);
 
    // Checks if a name is available for registration
    function available(uint256) external view returns (bool);
 
    // Returns the balance of an address
    function balanceOf(address) external view returns (uint256);
 
    // Returns the base node of the registrar
    function baseNode() external view returns (bytes32);
 
    // Returns the address of the registry
    function ens() external view returns (address);
 
    // Returns the approved address for a token
    function getApproved(uint256) external view returns (address);
 
    // Checks if an operator is approved for all tokens of an owner
    function isApprovedForAll(address, address) external view returns (bool);
 
    // Returns the name associated with the registrar
    function name() external view returns (string);
 
    // Returns the expiration date of a name
    function nameExpires(uint256) external view returns (uint256);
 
    // Returns the owner of a token
    function ownerOf(uint256) external view returns (address);
 
    // Reclaims a name to an address
    function reclaim(uint256, address);
 
    // Registers a name
    function register(uint256, address, uint256) external returns (uint256);
 
    // Registers a name, only if it's available
    function registerOnly(uint256, address, uint256) external returns (uint256);
 
    // Renews a name
    function renew(uint256, uint256) external returns (uint256);
 
    // Safely transfers a token from one address to another
    function safeTransferFrom(address, address, uint256);
 
    // Safely transfers a token from one address to another with additional data
    function safeTransferFrom(address, address, uint256, bytes calldata);
 
    // Sets or unsets an operator for all tokens
    function setApprovalForAll(address, bool);
 
    // Sets the resolver for the base node
    function setResolver(address);
 
    // Checks if the contract implements an interface
    function supportsInterface(bytes4) external view returns (bool);
 
    // Returns the symbol of the registrar
    function symbol() external view returns (string);
 
    // Returns the URI of a token
    function tokenURI(uint256) external view returns (string);
 
    // Transfers a token from one address to another
    function transferFrom(address, address, uint256);
}