Skip to content

Conversation

@makoto
Copy link
Member

@makoto makoto commented Oct 6, 2025

ENSIP-16: Metadata Event Discovery

This PR significantly refactors ENSIP-16 to focus on event discovery and metadata standardization for offchain ENS names, shifting away from the previous GraphQL-centric approach to a more flexible JSON-RPC based system.

  • Replaced single graphqlUrl return value with rpcURLs, chainId, and baseRegistry
  • Supports both EVM-compatible chains and non-EVM sources (chainId = 0)
  • Change Grqphql schema API from compulsory to recommendation.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Oct 7, 2025

Deploying ensips with  Cloudflare Pages  Cloudflare Pages

Latest commit: bd8f929
Status: ✅  Deploy successful!
Preview URL: https://d218331f.ensips.pages.dev
Branch Preview URL: https://jsonrpc.ensips.pages.dev

View logs

## Abstract

This ENSIP specifies APIs for querying metadata directly on the resolver for EIP-3668 (CCIP Read: Secure offchain data retrieval) enabled names. EIP-3668 will power many of the domains in the future, however since the retrieval mechanism uses wildcard + offchain resolver, there is no standardised way to retrieve important metadata information such as the owner (who can change the records), or which L2/offchain database the records are stored on.
This ENSIP specifies APIs for querying metadata directly on the resolver for EIP-3668 (CCIP Read: Secure offchain data retrieval) enabled names. EIP-3668 will power many domains in the future, however since the retrieval mechanism uses wildcard + offchain resolver, there is no standardised way to retrieve important metadata information such as which L2/offchain database the records are stored on and where JSON RPC endpoint is to find event log information.
Copy link
Member

Choose a reason for hiding this comment

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

This will need a rewrite, but we can wait for feedback first.

Copy link
Member Author

Choose a reason for hiding this comment

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

One question about the practicality of creating synthetic events is that (non EVM chain/dbms) has to create not just events but also synthetic smart contract address and blocknumber so that filtering paramater also works

event MetadataChanged(
string name,
string graphqlUrl,
bytes name, // DNS-encoded name
Copy link
Member

Choose a reason for hiding this comment

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

We should specify that all names that are suffixed with this name are considered to be covered by this event.

Copy link
Member

Choose a reason for hiding this comment

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

We'll also need a way for an event to signify removing this association, such as emitting it with default arguments.

Copy link
Member Author

Choose a reason for hiding this comment

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

We should specify that all names that are suffixed with this name are considered to be covered by this event I remember we had conversation about this but didn't fully understand. Can you elaborate?

uint256[] values
);
// Standard ERC721 transfer event for name ownership changes
Copy link
Member

Choose a reason for hiding this comment

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

I don't believe we're using 721 anywhere in v2.

Copy link
Member Author

Choose a reason for hiding this comment

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

Please see my comment below.

resolver: Resolver!
expiryDate: BigInt
}
NOTE: Even though ENS v2 registry contract is ERC1155 (TransferSingle, TransferBatch), ERC721 events(Transfer) are also accepted if name owner choose to build their own registry with an NFT capability.
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we can support it that simply; registries have to implement 1155 IIRC.

Copy link
Member Author

Choose a reason for hiding this comment

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

In V1, we support wrapped name (1155) and non wrapped (721) and so is many NFT market places, so don't see why not.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is to allow compatibility with other contracts like Durin which uses 721. Even though we could enforce 1155, there isn't technical issue supporting both

```

## Backwards Compatibility
NOTE: In ENS v1, a resolver has a node property which is derived by the hash of subname and node of its parent name using namehash algorithm. In ENS v2 system, a resolver is used by a single registry which may have multiple parent registries. For example, a registry has a label called `foo` that has parent registry of `eth` and `xyz`, providing name for both `foo.eth` and `foo.xyz`. For a resolver to represent records for multiple names, the node of the v2 resolver is kept as 0x indicating that the node needs to be derived by combining the label information of the registry traversing from the subname all the way to the base/root registry. If a name owner choose to use their own contract with single registry and resolver, the node can be the namehash of the name as in v1.
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is true?

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you mean for If a name owner choose to use their own contract with single registry and resolver, the node can be the namehash of the name as in v1? This is the case to support compatibility with simpler registry/resolver like Durin

bytes name, // DNS-encoded name
string[] rpcURLs, // JSON RPC endpoint
uint256 chainId, // Chain identifier (optional)
address baseRegistry // Base registry address

Choose a reason for hiding this comment

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

Can we please document exactly what interface(s) baseRegistry is expected to implement?

Copy link
Member

@gskril gskril left a comment

Choose a reason for hiding this comment

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

This feels simpler than the GraphQL version! I'm missing how it's intended to be used though. Seems like indexers such as ENSNode are intended to get events from their own RPC URLs for any chain which makes sense, but how do they then expose that to apps?

In other words: I'm building an app the wants to load all available records for a given name. I get the resolver of a name, then check if that contract has a metadata() method. If it does, I get the RPC URL. What request do I make to it in order to get the list of available records?

I think what I described above is actually the most common case - more so than being interested in the full history of a name. And if that's true, having to encode and decode data in an eth_getLogs format seems overkill to me. Not to mention, it assumes that offchain subname providers keep a log of every database operation and can trivially expose that data in a new endpoint.

Perhaps a simple REST API standard that returns the current state of a name is sufficient? Like CCIP Read, a metadata URL could accept requests via https://api.example.com/lookup/{name} and return:

{
  "name": "ens.eth",
  "texts": {
    "description": "hi"
  },
  "coins": {
    "60": "0x0000000000000000000000000000000000000000"
  },
  "contenthash": "0x",
  "resolver": "0x0000000000000000000000000000000000000000"
}

Or if we don't want to include values for concerns around freshness:

{
  "name": "ens.eth",
  "texts": ["description"],
  "contenthash": true,
  "coins": [60]
}

New items could be added for additional metadata like expires, owner, etc.

I could be misunderstanding the eth_getLogs mention, but I think it's worth clarifying this type of thing in the spec.

}
```solidity
// Emitted when a new subname is registered
event NameRegistered(uint256 indexed tokenId, string label, uint64 expiration, address registeredBy);
Copy link
Member

Choose a reason for hiding this comment

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

For subnames that don't expire, is it safe to assume that expiration should be type(uint256).max?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes. I will mention that at comment

gskril added a commit to namestonehq/durin that referenced this pull request Oct 29, 2025
@makoto
Copy link
Member Author

makoto commented Oct 29, 2025

@gskril this PR is the version to provide consistent way to discover event input for indexers. Unlike my previous PR #41 which aim to provide consistent way to discover api for apps, apps is expected to query via their preferred indexing service or index on your own. We are currently waiting from namehash team about the expected api for apps

@gskril
Copy link
Member

gskril commented Oct 30, 2025

Hmm since most RPC providers don't return all logs in a single request, how do we expect apps to use this directly to do something like get a list of all text record keys set for a name?

I thought one design goal was for apps to be able to use ENSIP-16 directly without relying on a larger indexer, but could be misunderstanding.

@makoto
Copy link
Member Author

makoto commented Oct 30, 2025

I thought one design goal was for apps to be able to use ENSIP-16 directly without relying on a larger indexer, but could be misunderstanding. again, that was the intention of the previous PR #41 but we proposed this version as namehash opposed to the previous version that had the API defined within the ENSIP. This PR is blocked until they come up with PoC indexing with API draft. To avoid the confusion, I will close this PR

@makoto makoto closed this Oct 30, 2025
@makoto makoto mentioned this pull request Nov 3, 2025
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.

5 participants