The ENSRegistryWithFallback contract extends ENSRegistry to provide backward compatibility with a previous registry deployment. This contract was deployed as part of the 2020 ENS Registry Migration.
Overview
ENSRegistryWithFallback provides:
- All functionality of the standard ENSRegistry
- Fallback queries to an old registry for records that don’t exist in the new registry
- Seamless migration path from the old registry to the new one
- Zero address handling to prevent conflicts with the registry’s own address
Import
import '@ensdomains/ens-contracts/contracts/registry/ENSRegistryWithFallback.sol';
Constructor
constructor(ENS _old) public ENSRegistry()
Constructs a new ENS registry with fallback support.
The address of the previous ENS registry to fall back to
State Variables
old
Reference to the previous ENS registry contract for fallback queries.
Functions
resolver
function resolver(bytes32 node) public view override returns (address)
Returns the address of the resolver for the specified node. If the record doesn’t exist in this registry, it falls back to querying the old registry.
Returns: The address of the resolver from this registry or the old registry if not found
owner
function owner(bytes32 node) public view override returns (address)
Returns the address that owns the specified node. If the record doesn’t exist in this registry, it falls back to querying the old registry.
Returns: The address of the owner from this registry or the old registry if not found
ttl
function ttl(bytes32 node) public view override returns (uint64)
Returns the TTL of a node and any records associated with it. If the record doesn’t exist in this registry, it falls back to querying the old registry.
Returns: The TTL of the node from this registry or the old registry if not found
Internal Functions
_setOwner
function _setOwner(bytes32 node, address owner) internal override
Internal function to set the owner of a node. Prevents setting the owner to address(0x0) by converting it to the registry’s own address instead.
The address of the new owner (converted to registry address if zero)
This special handling of the zero address prevents conflicts where the registry’s own address is used as a sentinel value.
Fallback Behavior
The fallback mechanism works as follows:
- When querying
owner(), resolver(), or ttl(), the contract first checks if a record exists in the new registry
- If
recordExists(node) returns false, the query is forwarded to the old registry
- If a record exists in the new registry, it is returned directly without consulting the old registry
This allows for:
- Transparent migration of records over time
- No disruption to existing ENS names during migration
- New records to be created in the new registry while old ones remain accessible
Usage Examples
Deployment
Querying Records
Migrating Records
import '@ensdomains/ens-contracts/contracts/registry/ENSRegistryWithFallback.sol';
import '@ensdomains/ens-contracts/contracts/registry/ENS.sol';
// Deploy with reference to old registry
ENS oldRegistry = ENS(0x314159265dD8dbb310642f98f50C066173C1259b);
ENSRegistryWithFallback newRegistry = new ENSRegistryWithFallback(oldRegistry);
// The new registry can now serve records from both registries
import '@ensdomains/ens-contracts/contracts/registry/ENSRegistryWithFallback.sol';
contract MigrationExample {
ENSRegistryWithFallback public registry;
constructor(ENSRegistryWithFallback _registry) {
registry = _registry;
}
function checkOwner(bytes32 node) public view returns (address) {
// This will check the new registry first,
// then fall back to the old registry if not found
return registry.owner(node);
}
function getResolver(bytes32 node) public view returns (address) {
// Same fallback behavior
return registry.resolver(node);
}
function recordMigrated(bytes32 node) public view returns (bool) {
// Check if record exists in new registry
return registry.recordExists(node);
}
}
import '@ensdomains/ens-contracts/contracts/registry/ENSRegistryWithFallback.sol';
contract RecordMigration {
ENSRegistryWithFallback public newRegistry;
constructor(ENSRegistryWithFallback _newRegistry) {
newRegistry = _newRegistry;
}
function migrateRecord(bytes32 node) public {
// Get current values (from old or new registry)
address currentOwner = newRegistry.owner(node);
address currentResolver = newRegistry.resolver(node);
uint64 currentTTL = newRegistry.ttl(node);
// Only the owner can migrate their record
require(msg.sender == currentOwner, "Not the owner");
// Set the record in the new registry
// This makes it no longer fall back to the old registry
newRegistry.setRecord(
node,
currentOwner,
currentResolver,
currentTTL
);
}
}
Migration Context
This contract was created for the 2020 ENS Registry Migration, which addressed several issues with the original registry:
- Improved handling of ownership transfers
- Better support for future upgrades
- Enhanced security and reliability
The fallback mechanism ensures that all existing ENS names continue to work during and after the migration, without requiring immediate action from name owners.