Updated ENSIP draft: Contract Self-Naming via IContractName and IContractNamer

I’ve updated the draft ENSIP for contract self-naming. Contract self-naming allows a contract to name “itself” or delegate to a “namer” address to name the contract. It defines two interfaces that allow contracts to control their own reverse names:

  • IContractName: the contract exposes its own ENS name via contractName() and emits ContractNameSet when the name changes.
  • IContractNamer: the contract exposes isContractNamer(address), which the reverse registrar consults to authorize a name change. A lighter alternative to Ownable for naming delegation.

The original Contract Self-Naming proposal has been updated in light of further discussions with @raffy and this thread, “Contract Naming”.

PR:

Feedback welcome.

2 Likes

Thanks to @Premm.eth for putting forward this highly creative draft. Introducing the IContractName and IContractNamer interfaces to solve the reverse resolution pain points for complex smart contracts (like multisigs or non-Ownable contracts) is indeed a very clever approach.

For ENS—a core piece of Web3 infrastructure—stability, security, simplicity, and ease of integration for the downstream ecosystem (like frontend libraries and data services) are the cornerstones of its long-term development.

After a cautious consideration for the overall system complexity, I have a few thoughts about this proposal.

1. Data Tracking Pressure and Spam Prevention

Currently, off-chain data tracking tools like The Graph only need to monitor a single central ENS contract to capture all name changes across the network. However, under the new draft, any smart contract on the network could trigger a name change event. This means tracking tools would have to constantly scan every corner of the entire Ethereum network to find these events.
I am a bit concerned: could this place a massive computational and storage burden on data service providers? Furthermore, could malicious actors deploy contracts at a very low cost to spam fake name-change events, thereby flooding our databases with garbage data?

2. Spoofing Prevention and Potential Resource Exhaustion Risks

To prevent a malicious contract from arbitrarily naming itself something like ”base.eth" (identity spoofing), our resolution system will inevitably need to double-check if the contract is actually the true owner of that name after reading it.
If this “two-way verification” happens on-chain, would it significantly increase the Gas cost of resolution? What worries me a bit more is: what if a malicious contract intentionally writes extremely resource-heavy code inside the function that provides the name? Could this cause frontend applications to crash due to running out of Gas when trying to read the name? Do we have any corresponding safeguards or limitation mechanisms in place?

3. The Trade-off Between Ecosystem Adaptation Complexity and Actual Adoption Rate

This is an ENS-specific improvement proposal, not a global Ethereum standard. Asking contract developers across the network to proactively implement these interfaces might require a very long adoption cycle.
My concern is that if only a small number of contracts end up implementing this interface in the future, our core resolvers, frontend base libraries (like viem/wagmi), and all data services will still be forced to permanently add a set of fallback query logic just to be compatible with them. Is the trade-off of permanently increasing the complexity of the entire ENS infrastructure worth the convenience it brings to a minority of contracts?

Hope that while we decentralize naming rights to contracts, we can ensure the ENS infrastructure remains lightweight and bulletproof.

There are two aspects of this proposal: IContractName and IContractNamer. For IContractNamer, the contract is simply delegating to an address that has the authority to name the contract, the same as Ownable, without needing to add admin control to the contract.

For IContractName, there are two different ways this can work. The first is the way the draft specification is now, where the reverse registry does not get updated and the event is simply indexed to discover the contract naming itself. The other possibility is that the contract naming itself authorizes “anyone” to set the name of the contract in the reverse registry. From the developer’s perspective, having a contract name itself and just emitting the event is easier. However, as you point out, there may be a higher level of complexity for indexing. I am not sure, however, that just because a historical indexing system like The Graph would struggle to index contract names this way, it is actually an issue for more sophisticated indexing systems. I would be interested to hear from @lightwalker.eth and get his thoughts on this.

1 Like

To quickly recap on the thought process: during design, IContractName seemed like the better candidate, since it’s incredibly simple, but during implementation, a problem surfaced: it’s harder for an indexer to implement, since it’s an alternative resolution path (unless you’re invoking the resolver for each query.)

When contract naming was added to ENSv2, IContractNamer was used for everything that wasn’t Ownable. IContractNamer works great with EAC (supports multiple namers via simple role check), it works great with delegation (just return another contract’s isContractNamer() response), and it doesn’t imply the same mutable connotations that Ownable does.

ENSv2 core contract naming overview:

  • Ownable contracts name as expected
  • There is a single ContractNamer for the DAO
  • Any contract w/EAC implements IContractNamer, has role ROLE_CAN_NAME, and grants it to the DAO (Example)
    • PermissionedRegistry (and UserRegistry and WrapperRegistry)
    • PermissionedResolver
    • PermissionedAddressSet
    • StandardRentPriceOracle
  • Any contract w/o EAC delegates to the shared ContractNamer via DelegatedContractNamer
    (Example)

Although IContractName isn’t used by the core contracts, it’s still a useful design. An improvement to the initial design would be a new event which should be emit anytime the underlying name changes to improve indexing efficiency.

We also want to be able to rename contracts, so we can version them if they get replaced. Although both techniques allow mutability, IContractNamer is less code if an existing authorization method already exists (the shared ContractNamer).

Lastly, there is a new library AccountNamerLib which codifies the authorization logic.


Other resources:

3 Likes