Problem Statement
Currently, setting primary ENS names for smart contracts is limited to a subset of contracts. To be able to set a primary name, a contract must:
-
Extend
Ownable
orERC-173
-
Be capable of delegating reverse address claim permissions to another externally owned account (EOA) via methods like
reverseClaimer
orreverseSetter
(which must be set at deployment and cannot be changed afterward) -
Able to make arbitrary calls, can set a primary name.
This significantly restricts the number of contracts, especially those already deployed or not meeting the above criteria, that can obtain a primary name.
The Enscribe team has been thinking about how we could expand this capability so that, in principle, every contract can have a primary name set.
High-Level Solution
We propose extending the current permission logic in the Reverse Registrar contract.
Instead of limiting this capability exclusively to contracts that implement Ownable
/ERC-173
, we suggest also allowing the original deployer of the contract to set the primary name.
This approach achieves two key objectives:
-
Universal Accessibility: Enables every contract address to set a primary name.
-
Security: Ensures only authorized entities (contract owner or verified deployer) can set primary names.
To achieve this, we must reliably verify the contract deployer on-chain or allow any address to securely prove that it deployed the contract.
Potential Implementation Approaches
We have identified a number of potential methods for verifying deployer addresses:
-
Oracle / CCIP-Read / EigenLayer AVS:
Utilize off-chain services to fetch and verify deployer addresses, with on-chain verification. -
ZK Proofs:
Generate cryptographic proofs off-chain that verify deployer information, then verify these proofs on-chain. -
Deployer Decoding from Contract Address:
Derive the deployerâs address directly from the contract address by analyzing the nonce (forCREATE
) or salt (forCREATE2
) used during deployment.
Note: We still need to explore the possible implementation strategies in more depth and would love to initiate a discussion around the proposed high-level solution before we commence work on a PoC.
Changes Requested
With the L2 primary name support discussions in ENSIP-19, which enable setting primary names for L2 chains, we want to propose some changes to the L2ReverseRegistrar
contract.
Since the L2ReverseRegistrar
implementation has not yet been finalized and the mainnet deployment is still pending with only testing ongoing in L2 testnets, there are a few changes we can make now to enable setting primary names not just for Ownable
/ERC-173
contracts but for all existing and new contracts.
Refer to the L2ReverseRegistrar.sol Implementation
Authorized modifier
Source Link
/// @notice Checks if the caller is authorised
/// @param addr The address to check.
modifier authorised(address addr) {
if (addr != msg.sender && !_ownsContract(addr, msg.sender)) {
revert Unauthorised();
}
_;
}
We want to highlight the _ownsContract()
function
Source Link
/// @notice Checks if the provided contractAddr is a contract and is owned by the provided addr.
/// @param contractAddr The address of the contract to check.
/// @param addr The address to check ownership against.
function _ownsContract(
address contractAddr,
address addr
) internal view returns (bool) {
if (contractAddr.code.length == 0) return false;
try Ownable(contractAddr).owner() returns (address owner) {
return owner == addr;
} catch {
return false;
}
}
In this we want to add a new check for contract deployer, which would look something like -
function _ownsContract(
address contractAddr,
address addr
) internal view returns (bool) {
if (contractAddr.code.length == 0) return false;
// Check Ownable ownership first
try Ownable(contractAddr).owner() returns (address owner) {
if (owner == addr) {
return true;
}
} catch {
// Continue to check deployer if Ownable check fails
}
// Check if addr is the deployer (mock implementation)
if (_isAddrContractDeployer(addr, contractAddr)) {
return true;
}
return false;
}
// Dummy/mock function to simulate deployer address verification
function _isAddrContractDeployer(address addr, address contractAddress) internal pure returns (bool) {
// TODO: Implement actual deployer verification logic
return false;
}
Summary
To enable every contract - past or future - to set a primary ENS name, we propose expanding the current authorization logic beyond Ownable
/ERC-173
checks. By recognizing verified deployers as authorized entities, we unlock support for a broader range of contracts, including those already deployed without ownership functions.
Weâre suggesting a change to the L2ReverseRegistrar
contract to include deployer checks within _ownsContract
, using a pluggable _isAddrContractDeployer
method. This prepares the ENS ecosystem for more inclusive and flexible primary name assignments for contracts across L2s, including Namechain.