Overview
The PublicResolver is a general-purpose ENS resolver that implements all standard resolver profiles. It’s the most commonly deployed resolver in the ENS ecosystem and is suitable for most use cases.
Contract Location
import '@ensdomains/ens-contracts/contracts/resolvers/PublicResolver.sol' ;
Inheritance
PublicResolver inherits from multiple resolver profiles:
contract PublicResolver is
Multicallable ,
ABIResolver ,
AddrResolver ,
ContentHashResolver ,
DNSResolver ,
InterfaceResolver ,
NameResolver ,
PubkeyResolver ,
TextResolver ,
ReverseClaimer
{
// Implementation
}
Constructor
constructor (
ENS _ens ,
INameWrapper wrapperAddress ,
address _trustedETHController ,
address _trustedReverseRegistrar
)
Parameters
_ens: The ENS registry contract address
wrapperAddress: The NameWrapper contract address for wrapped names
_trustedETHController: Address of the ETH Registrar Controller (can bypass authorization)
_trustedReverseRegistrar: Address of the Reverse Registrar (can bypass authorization)
Authorization System
The PublicResolver implements a three-tier authorization system to control who can update records.
Operators
Operators can manage all names owned by a specific address.
// Set operator approval
function setApprovalForAll ( address operator , bool approved ) external
// Check operator approval
function isApprovedForAll ( address account , address operator ) public view returns ( bool )
Events
event ApprovalForAll (
address indexed owner ,
address indexed operator ,
bool approved
);
Usage Example
// Allow an operator to manage all your names
resolver. setApprovalForAll (operatorAddress, true );
// Revoke operator access
resolver. setApprovalForAll (operatorAddress, false );
Delegates
Delegates can manage a specific name on behalf of the owner.
// Approve a delegate for a specific node
function approve ( bytes32 node , address delegate , bool approved ) external
// Check delegate approval
function isApprovedFor (
address owner ,
bytes32 node ,
address delegate
) public view returns ( bool )
Events
event Approved (
address owner ,
bytes32 indexed node ,
address indexed delegate ,
bool indexed approved
);
Usage Example
// Allow a delegate to manage a specific name
bytes32 node = namehash ( "example.eth" );
resolver. approve (node, delegateAddress, true );
// Revoke delegate access
resolver. approve (node, delegateAddress, false );
Authorization Logic
The internal isAuthorised() function determines if an address can modify a node:
function isAuthorised ( bytes32 node ) internal view override returns ( bool ) {
// Trusted controllers always authorized
if (
msg.sender == trustedETHController ||
msg.sender == trustedReverseRegistrar
) {
return true ;
}
// Get the owner (check NameWrapper if needed)
address owner = ens. owner (node);
if (owner == address (nameWrapper)) {
owner = nameWrapper. ownerOf ( uint256 (node));
}
// Check if sender is owner, operator, or delegate
return
owner == msg.sender ||
isApprovedForAll (owner, msg.sender ) ||
isApprovedFor (owner, node, msg.sender );
}
Multicall Support
The PublicResolver inherits from Multicallable, allowing multiple operations in a single transaction.
function multicall ( bytes [] calldata data ) external returns ( bytes [] memory results )
function multicallWithNodeCheck (
bytes32 nodehash ,
bytes [] calldata data
) external returns ( bytes [] memory results )
Usage Example
// Prepare multiple function calls
bytes [] memory calls = new bytes []( 3 );
calls[ 0 ] = abi . encodeWithSelector (
resolver.setAddr.selector,
node,
myAddress
);
calls[ 1 ] = abi . encodeWithSelector (
resolver.setText.selector,
node,
"email" ,
"[email protected] "
);
calls[ 2 ] = abi . encodeWithSelector (
resolver.setText.selector,
node,
"url" ,
"https://example.com"
);
// Execute all in one transaction
resolver. multicall (calls);
Interface Support
The PublicResolver supports interface detection via EIP-165:
function supportsInterface ( bytes4 interfaceID ) public view override returns ( bool )
This function returns true for all supported resolver profile interfaces.
Supported Interfaces
IABIResolver
IAddrResolver
IAddressResolver
IContentHashResolver
IDNSRecordResolver
IDNSZoneResolver
IInterfaceResolver
INameResolver
IPubkeyResolver
ITextResolver
Resolver Profiles
The PublicResolver implements all standard resolver profiles. Each profile provides specific functionality:
Complete Usage Example
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17 ;
import "@ensdomains/ens-contracts/contracts/registry/ENS.sol" ;
import "@ensdomains/ens-contracts/contracts/resolvers/PublicResolver.sol" ;
contract ENSExample {
ENS public ens;
PublicResolver public resolver;
constructor ( address ensAddress , address resolverAddress ) {
ens = ENS (ensAddress);
resolver = PublicResolver (resolverAddress);
}
// Set up a complete ENS name
function setupName (
bytes32 node ,
address ethAddress ,
string memory email ,
string memory url ,
bytes memory contentHash
) external {
// Ensure this contract is authorized
require (resolver. isAuthorised (node), "Not authorized" );
// Batch all updates in one transaction
bytes [] memory calls = new bytes []( 4 );
calls[ 0 ] = abi . encodeWithSelector (
resolver.setAddr.selector,
node,
ethAddress
);
calls[ 1 ] = abi . encodeWithSelector (
resolver.setText.selector,
node,
"email" ,
email
);
calls[ 2 ] = abi . encodeWithSelector (
resolver.setText.selector,
node,
"url" ,
url
);
calls[ 3 ] = abi . encodeWithSelector (
resolver.setContenthash.selector,
node,
contentHash
);
resolver. multicall (calls);
}
// Read all data for a name
function getName ( bytes32 node ) external view returns (
address ethAddress ,
string memory email ,
string memory url ,
bytes memory contentHash
) {
ethAddress = resolver. addr (node);
email = resolver. text (node, "email" );
url = resolver. text (node, "url" );
contentHash = resolver. contenthash (node);
}
}
Security Considerations
The PublicResolver trusts the trustedETHController and trustedReverseRegistrar addresses. These addresses can modify any records without ownership checks. Ensure these are set to the correct, trusted contracts.
When using operators or delegates, remember that:
Operators can modify ALL names owned by an address
Delegates can only modify the specific name they’re approved for
The owner can always revoke these permissions
Next Steps
Resolver Profiles Explore individual resolver profiles and their functions
Resolvers Overview Back to resolvers overview