Skip to content

Conversation

@adraffy
Copy link
Member

@adraffy adraffy commented Sep 9, 2025

  • added ReverseNamer.sol and tests
    1. NamedOnce for simple immutable name on constructor
    2. NameableBy for delegated naming
    3. ReverseNamer.setName("<name>") for custom implementation

Usage:

// 1
import {NamedOnce} from "@ensdomains/ens-contracts/contracts/reverseRegistrar/ReverseNamer.sol";
contract C is NamedOnce("mycontract.eth") { ... }

// 2
import {NameableBy} from "@ensdomains/ens-contracts/contracts/reverseRegistrar/ReverseNamer.sol";
contract C is NameableBy {
    constructor(address namer) NameableBy(namer, "") { ... }
}

// 3
import {ReverseNamer} from "@ensdomains/ens-contracts/contracts/reverseRegistrar/ReverseNamer.sol";
contract C {
    function f() external {
        ReverseNamer.setName("mycontract.eth");
    }
}

Alternative ideas:

  • NamedOnceemit Named(string) → generate proof of log
  • code snippet: address(<registrar>).call(abi.encodeWithSignature("setName(string)", "<name>"))

@gskril
Copy link
Member

gskril commented Sep 10, 2025

I like it! Should this PR also delete ReverseClaimer.sol, or maybe more safely just add a natspec comment indicating to use ReverseNamer.sol for wider support (rollups)?

@NickSneo
Copy link

NickSneo commented Sep 16, 2025

@adraffy Whats the difference between case 2 and case 3
isn't it indirectly doing same thing delegating someone to name the contract either by directly delegating in case 2 or indirectly (via some access control on who can call function f()) in case 3

Would it makes sense to just have 2 cases?

Copy link

@NickSneo NickSneo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR looks good, thanks for this. We as Enscribe team also need to push more on awareness so developers include this in their contracts before deploying.

Added a few comments


/// @notice https://docs.ens.domains/ensip/19/
library ReverseNamer {
address constant MAINNET = address(0); // TODO: ENSv2 addr.reverse registrar

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to add TESTNET or is it same as MAINNET address? since we have distinct MAINNET_ROLLUP and TESTNET_ROLLUP

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will mean all mainnets (mainnet/sepolia/...).

I speculatively designed ETHReverseResolver as the v2 replacement for addr.reverse that uses the same tech as the rollups (independent registry + wildcard resolver) but I think we're going with a proper claimable {addr}.addr.reverse that uses the v2 design, but it should be a fixed address deployment and the same on those chains. And If not, you're correct.

return MAINNET_ROLLUP;
} else if (isTestnetRollup(chainId)) {
return TESTNET_ROLLUP;
} else {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on line 10 - MAINNET = address(0) so is the else case

}

/// @notice Mixin for delegated contract naming.
contract NameableBy is NotOwnable {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NotOwnable in case of NamedOnce makes sense as no one can later name the contract but in case of NameableBy doesnt make much sense to it.

NameableBy can be seen in a contract with Ownable as an extra delegate who can name contract but still if contract has Owner he can revoke the delegation. I might be wrong but limiting NameableBy to only non ownable contracts doesn't make much sense to me

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I wasn't sure about this design. NameableBy could be removed. My thinking was you want something like Ownable but without implementing Ownable which at a glance implies the contract is mutable.

NameableBy + Ownable would give you 2 accounts that can change the name, but maybe that should be allowed.

I was thinking of it more like a trust curve:

  1. NamedOnce — set once
  2. NameableBy — set later, revoke it / delegate to someone to name it
  3. NameableBy — delegate to someone, change whenever
  4. Ownable — change whenever, but shares with other Ownable responsibilities

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants