Skip to content
This repository was archived by the owner on Aug 5, 2026. It is now read-only.
This repository was archived by the owner on Aug 5, 2026. It is now read-only.

Omnigraph: names pointing to this address #1962

Description

@shrugs

Problem

Portal's /addr/$addr/resolution view ("names pointing to this address") today is served by ensjs subgraph's getResolvedNamesForAddress. As Portal migrates off subgraph stitching, Omnigraph needs to cover this query.

Proposal

Expose forward-resolution lookup on Account as a Relay connection over a new NameReference type, with an optional coinType filter:

type Account {
  nameReferences(
    where: AccountNameReferencesWhereInput
    first: Int, last: Int, before: String, after: String
  ): NameReferenceConnection!
}

input AccountNameReferencesWhereInput {
  coinType: CoinType!
}

type NameReference {
  name: String!                    # InterpretedName of the Domain whose addr() points here
  coinType: CoinType!              # the CoinType of the matching addr() record
  match: Boolean!                  # ENSIP-19 reverse(address, coinType) === name (indexed-only)
  normalized: Boolean!             # isNormalizedName(name)
  resolverAddress: Address!        # the Resolver holding the matching addr() record
  resolverChainId: ChainId!        # chain where that Resolver lives
}

Notes

  • where is optional — when omitted, return matches across all coinTypes; when supplied, scope to a single coinType. Default-coinType records (coinType = DEFAULT_EVM_COIN_TYPE) are returned as ordinary rows, not specially expanded.
  • v1 reflects literally-indexed records only: no Forward Resolution / CCIP-Read, no ENSIP-19 default address record expansion, no *.addr.reverse-based primary name walk for match. match uses the indexed StandaloneReverseRegistrar shortcut (default.reverse / [coinType].reverse).
  • v1 does NOT enforce active-resolver consistency — records on resolvers no longer assigned to the Domain may surface. (Tracked separately.)
  • New (value, coinType) index on resolver_address_records for the access pattern.

Blocker / Open question: node → Domain reverse mapping

The natural query reads resolver_address_records (keyed by (chainId, resolver, node, coinType)) and joins to a Domain to attach a Name. In ENSv1, subgraph_domain.id = node (and domain.node is set), so the join is trivial. In ENSv2, node is no longer a functional reference to a Domain — it's only knowable when you start from the Name and namehash forward. The corresponding Domain entities exist conceptually but their namehash is not materialized in the database.

Confirmed empirically against ens-test-env (v2-native, default SUBGRAPH_COMPAT=false): 15 records for (value=DEVNET_OWNER, coinType=60), 0 join matches.

To support reverse lookup natively, we'd need to materialize a canonicalNode for every Domain (the namehash of its full canonical path) and maintain it as the canonical path changes. It is not obvious this is feasible in Ponder at ENS scale: every parent canonical-path mutation cascades to all descendants' canonicalNode values — potentially a very large fan-out write per event, hot in the indexer critical path. Designs to consider: incremental/lazy recompute, deferred recompute jobs, cap-and-warn on deep subtrees, etc. This needs its own investigation before this PR can ship its intended shape.

Consumers

  • apps/portal/ /addr/$addr/resolution

Alternative shapes if canonicalNode materialization is infeasible

If the reverse mapping can't be made sustainable, the endpoint can still be useful in narrower forms — these are not interchangeable with Portal's current discovery UX, but each has real callers:

  1. Records-only primitive. Drop name from the response; return (resolverChainId, resolverAddress, node, coinType) and let the caller hydrate names via their own index. Useless for Portal's specific UI; useful as a building block for tools that already have a name index.
  2. Filter-by-candidates. Flip the direction: Account.nameReferences(where: { coinType, names: [InterpretedName!]! }). Caller supplies candidate names; we namehash each and check the records. Solves "verify these names point at this address"; does not solve discovery ("find names I don't already know about").
  3. Owned-and-pointing intersection. Extend Account.domains with where: { resolvesTo: AccountAddressInput }. Filters owned Domains down to those whose addr record points to a given address. Limited to names the user owns, but covers the common case for an address page.
  4. Subgraph-compat-only. Ship the field gated on SUBGRAPH_COMPAT=true; document that v2-native deployments return empty until canonicalNode materialization lands. Useful for deployments running the legacy compat plugin; silent footgun in v2-native deployments unless we error visibly when not compat-enabled.

Open question: which of these (or which combination) actually serves Portal — and is it worth shipping any of them before the canonicalNode work, or do we wait?

Prior context

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    ensapiENSApi related

    Projects

    • Status
      Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions