The TestRegistrar is a registrar contract designed for testing ENS functionality on Ethereum test networks. It allocates subdomains to the first person to claim them, with automatic expiration after a fixed period.
Overview
TestRegistrar provides:
- First-come-first-served subdomain registration for testing
- Automatic expiration after 4 weeks (28 days)
- Re-registration capability after expiration by anyone
- Simple registration without payment or complex logic
- Currently deployed on test networks under the
.test TLD
Import
import '@ensdomains/ens-contracts/contracts/registry/TestRegistrar.sol';
Constructor
constructor(ENS ensAddr, bytes32 node)
Creates a new test registrar.
The address of the ENS registry
The node that this registrar administers (typically the .test TLD)
Constants
registrationPeriod
uint256 constant registrationPeriod = 4 weeks
The fixed period for which registrations are valid (28 days).
State Variables
ens
Reference to the ENS registry contract.
rootNode
bytes32 public immutable rootNode
The parent node that this registrar has authority over.
expiryTimes
mapping(bytes32 => uint256) public expiryTimes
Maps label hashes to their expiration timestamps.
Functions
register
function register(bytes32 label, address owner) public
Registers a name that’s not currently registered or has expired.
The hash of the label to register (e.g., keccak256(‘testname’))
The address of the new owner
This function will revert if the name is currently registered and hasn’t expired yet (expiryTimes[label] >= block.timestamp).
Behavior:
- Checks if the current timestamp is greater than or equal to the expiry time
- Sets a new expiry time to
block.timestamp + 4 weeks
- Creates the subdomain with the specified owner via
ens.setSubnodeOwner()
How It Works
- Anyone can register an available subdomain by calling
register()
- The registration is valid for exactly 4 weeks from the registration timestamp
- After expiration, anyone can re-register the name (including the previous owner)
- There’s no mechanism to extend registration - names must be re-registered after expiration
Usage Examples
Basic Registration
Check Expiry
Auto Re-registration
Deployment
import '@ensdomains/ens-contracts/contracts/registry/TestRegistrar.sol';
contract TestRegistrarExample {
TestRegistrar public registrar;
constructor(TestRegistrar _registrar) {
registrar = _registrar;
}
function claimTestName(string memory label) public {
bytes32 labelHash = keccak256(bytes(label));
// Register the name for the caller
// Will expire in 4 weeks
registrar.register(labelHash, msg.sender);
// Caller now owns label.test for 4 weeks
}
}
import '@ensdomains/ens-contracts/contracts/registry/TestRegistrar.sol';
contract ExpiryChecker {
TestRegistrar public registrar;
constructor(TestRegistrar _registrar) {
registrar = _registrar;
}
function isAvailable(string memory label) public view returns (bool) {
bytes32 labelHash = keccak256(bytes(label));
uint256 expiry = registrar.expiryTimes(labelHash);
// Name is available if it has never been registered
// or if the expiry time has passed
return expiry < block.timestamp;
}
function getExpiry(string memory label) public view returns (uint256) {
bytes32 labelHash = keccak256(bytes(label));
return registrar.expiryTimes(labelHash);
}
function timeUntilExpiry(
string memory label
) public view returns (uint256) {
bytes32 labelHash = keccak256(bytes(label));
uint256 expiry = registrar.expiryTimes(labelHash);
if (expiry <= block.timestamp) {
return 0; // Already expired
}
return expiry - block.timestamp;
}
}
import '@ensdomains/ens-contracts/contracts/registry/TestRegistrar.sol';
contract AutoReregister {
TestRegistrar public registrar;
bytes32 public myLabel;
address public desiredOwner;
constructor(
TestRegistrar _registrar,
string memory label,
address owner
) {
registrar = _registrar;
myLabel = keccak256(bytes(label));
desiredOwner = owner;
}
function reregisterIfExpired() public {
uint256 expiry = registrar.expiryTimes(myLabel);
require(
expiry < block.timestamp,
"Name has not expired yet"
);
// Re-register the name
registrar.register(myLabel, desiredOwner);
}
function tryRegister() public returns (bool) {
uint256 expiry = registrar.expiryTimes(myLabel);
if (expiry >= block.timestamp) {
return false; // Still registered
}
registrar.register(myLabel, desiredOwner);
return true;
}
}
import '@ensdomains/ens-contracts/contracts/registry/TestRegistrar.sol';
import '@ensdomains/ens-contracts/contracts/registry/ENS.sol';
// Deploy TestRegistrar for .test TLD
ENS ens = ENS(0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e);
bytes32 testNode = 0xeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1; // namehash('test')
// Deploy the test registrar
TestRegistrar testRegistrar = new TestRegistrar(ens, testNode);
// Transfer ownership of .test TLD to the registrar
ens.setOwner(testNode, address(testRegistrar));
// Now anyone can register .test names that expire after 4 weeks
The TestRegistrar is currently deployed on Ethereum test networks to facilitate testing:
- Manages the
.test TLD
- Allows developers to easily claim test names
- Automatic expiration prevents name squatting on test networks
- No cost beyond gas fees
Use Cases
Development Testing
Quickly claim test names for development:
// Register myproject.test for testing
const label = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('myproject'));
await testRegistrar.register(label, myAddress);
Integration Tests
Claim temporary names in your test suite:
it('should register a test name', async () => {
const label = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('testname'));
await testRegistrar.register(label, owner.address);
const subnode = ethers.utils.namehash('testname.test');
expect(await ens.owner(subnode)).to.equal(owner.address);
});
Temporary Demo Names
Create temporary names for demos that automatically expire:
demo.test - expires in 4 weeks
prototype.test - expires in 4 weeks
showcase.test - expires in 4 weeks
Comparison with FIFSRegistrar
Unlike the FIFSRegistrar:
- TestRegistrar includes automatic expiration (4 weeks)
- TestRegistrar allows anyone to re-register expired names
- TestRegistrar tracks expiry times in a public mapping
- FIFSRegistrar provides permanent registration
Limitations
- Names expire after exactly 4 weeks - no extension mechanism
- Anyone can claim your name after it expires
- Not suitable for production use - designed for test networks only
- No ownership protection after expiration
- Vulnerable to frontrunning on re-registration
Best Practices
- Only use on test networks, never in production
- Monitor expiry times if you need to maintain control of a name
- Re-register before expiration if you need to keep the name
- Remember that test names are temporary by design