Skip to content

resolution api: support contenthash, pubkey, abi, interfaces, dnszonehash, version#1967

Merged
shrugs merged 21 commits intomainfrom
feat/extend-protocol-resolution
Apr 21, 2026
Merged

resolution api: support contenthash, pubkey, abi, interfaces, dnszonehash, version#1967
shrugs merged 21 commits intomainfrom
feat/extend-protocol-resolution

Conversation

@shrugs
Copy link
Copy Markdown
Member

@shrugs shrugs commented Apr 20, 2026

closes #1505

Reviewer Focus (Read This First)

  • the linear Operation[] pipeline in forward-resolution.ts — each acceleration strategy is a pass; unresolved ops flow to a single final RPC callsite
  • the Operation discriminated union in operations.ts — per-variant result typing drives the rest of the pipeline (executeOperations, makeRecordsResponse, acceleration passes).
  • handleResolverVersionChange uses raw context.ensDb.sql.delete(...) to bulk-delete child records on VersionChanged — this forces a ponder cache flush. accepted because the event is rare, but worth a sanity check.

Problem & Motivation

  • resolution api only supported name, addresses, texts. callers need contenthash, pubkey, abi, interfaces, dnszonehash, version to support Portal app features
  • protocol acceleration needed to extend to index these new record types — where possible. ABIChanged omits data (would require a follow-up readContract per event), and interfaceImplementer has an ERC-165 fallback that can't be replicated offline. both remain selectable but are always resolved via RPC. support for indexing could be trivially added in the future if desired
  • VersionChanged semantics weren't handled: prior records stayed queryable after a version bump.

What Changed (Concrete)

  1. new ContentType, InterfaceId, RecordVersion types in packages/enssdk/src/lib/types/resolver.ts. eip-165.ts + subgraph handleInterfaceChanged migrated to InterfaceId.
  2. new interpreters in @ensnode/ensnode-sdk/internal: interpretContenthashValue, interpretPubkeyValue, interpretDnszonehashValue (empty-bytes / zero-pair → null).
  3. protocol-acceleration.schema.ts#resolverRecords extended with contenthash, pubkeyX, pubkeyY, dnszonehash, version (defaults to 0n).
  4. single ensureResolverAndRecords(context, event) helper, plus 4 new per-record update helpers (handleResolverContenthashUpdate, handleResolverPubkeyUpdate, handleResolverDnszonehashUpdate, handleResolverVersionChange).
  5. protocol-acceleration handlers registered for ContenthashChanged, PubkeyChanged, DNSZonehashChanged, VersionChanged. ABIChanged + InterfaceChanged intentionally unregistered (comment explains).
  6. ResolverRecordsSelection + ResolverRecordsResponseBase extended with contenthash, pubkey, abi, interfaces, dnszonehash, version.
  7. new Operation discriminated union in apps/ensapi/src/lib/resolution/operations.ts, driven by an OperationMap {functionName → {args, result}}. each variant's result is typed per-variant (e.g. nameInterpretedName | null | undefined).
  8. execute-operations.tsexecuteOperations (was executeResolveCalls) + interpretOperationWithRawResult. one readContract call in the direct-resolve path, with as unknown as … cast to bypass viem's narrowing.
  9. execute-operations-with-universal-resolver.ts (was resolve-with-universal-resolver.ts) — returns resolved Operations<SELECTION> directly, no separate interpret pass.
  10. forward-resolution.ts restructured: linear pipeline over Operation[], each acceleration strategy a pass, single final RPC execution.
  11. new accelerate-ensip19-reverse-resolver.ts and accelerate-known-onchain-static-resolver.ts. resolveOperationWithIndex is colocated with the static-resolver accelerator.
  12. make-records-response.tsmakeRecordsResponse<SELECTION>(operations). single-pass reduce, lazy map init. SELECTION is a type-only generic. makeEmptyResolverRecordsResponse deleted (empty ops + empty selection collapses to {}, which matches ResolverRecordsResponse<{}>).
  13. safeStringifyDrizzleSchema patched to handle bigint defaults (schema's version.default(0n) crashed JSON.stringify at startup).
  14. new helpers in operations.ts: isOperationResolved, logOperations, tablifyOperations.
  15. changeset added.

Design & Planning

  • spec lives at SPEC-resolver-records.md on original commit on this branch — drove the architecture (hybrid acceleration, linear Operation passes, ABI/interfaces as RPC-only).
  • alternatives considered and rejected:
    • indexing ABI — low usage and possibly high data storage
    • indexing interfaceImplementer — ERC-165 fallback was annoying to implement offline, + low usage
  • co-planned with claude

Planning artifacts: SPEC-resolver-records.md in first commit on this branch


Self-Review

A lot changed after the initial pass via the /simplify review cycle.

Bugs caught:

  • safeStringifyDrizzleSchema crashed on version: bigint default at startup — patched to serialize bigints.
  • type-unsafe op.result as X | null casts in make-records-response.ts — replaced with a typed reduce.

Naming / terminology improved:

  • executeResolveCalls → executeOperations, makeResolveCalls → makeOperations, resolveCallByIndex → resolveOperationWithIndex, interpretRawRpcCallAndResult → interpretOperationWithRawResult.
  • file renames: resolve-calls-and-results.ts → operations.ts, resolve-with-universal-resolver.ts → execute-operations-with-universal-resolver.ts, resolve-call-by-index.ts (deleted; inlined into accelerate-known-onchain-static-resolver.ts).

Dead code removed:

  • interpretRawCallsAndResults, tablifyCallResults, ResolveCallsAndRawResults, ResolveCallsAndResults, makeEmptyResolverRecordsResponse, findOp, ResolveCall (absorbed into Operation), IndexedResolverRecords.

Cross-Codebase Alignment

  • search terms used: InterfaceId, interfaceID, Resolver:ContenthashChanged, newVersion: bigint, interpretNameRecordValue, ResolverRecordsSelection, makeEmptyResolverRecordsResponse.
  • reviewed but unchanged: subgraph plugin's Resolver handlers (explicitly out of scope per spec) and subgraph.schema.ts. the subgraph plugin indexes its own subgraph_* tables; that surface is untouched.
  • deferred alignment: ENSv2 acceleration — the bailout path in forward-resolution.ts still short-circuits to executeOperationsWithUniversalResolver instead of flowing through the linear Operation[] pipeline. follow-up once ENSv2 acceleration is implemented.

Search terms used: as above.
Reviewed but unchanged: subgraph plugin's Resolver handlers, subgraph.schema.ts.
Deferred alignment: ENSv2 linear-pipeline integration.


Downstream & Consumer Impact

  • public APIs: ResolverRecordsSelection + ResolverRecordsResponse<T> gain 6 new optional fields. existing callers are unaffected; response shape only grows.
  • naming worth calling out:
    • Operation (formerly conceptually ResolveCall + result) is the single discriminated union that drives the resolution pipeline. internal consumers will see this rename.
    • ensureResolverAndRecords replaces the three-step setup handlers used to call manually.
    • new semantic types: ContentType, InterfaceId, RecordVersion.

Public APIs affected: ResolverRecordsSelection, ResolverRecordsResponse<T>, new enssdk types.
Docs updated: yes
Naming decisions worth calling out: Operation as the unified pipeline type; ensureResolverAndRecords.


Testing Evidence

  • unit and integration
  • added some unit

Risk Analysis

  • risk areas:
    • `handleResolverVersionChange` uses raw `ensDb.sql.delete(...)` twice, which flushes ponder's cache to postgres. accepted because VersionChanged is rare; but if it fires frequently on an unexpected contract, indexing perf degrades.
    • `safeStringifyDrizzleSchema` bigint handler — changed the checksum input format for bigint defaults. all existing schemas get a new checksum once; not a correctness issue.
  • mitigations / rollback: revert. schema change is additive; rolling back only loses data in the new columns. no existing queries break.
  • named owner if this causes problems: @shrugs.

Pre-Review Checklist (Blocking)

  • I reviewed every line of this diff and understand it end-to-end
  • I'm prepared to defend this PR line-by-line in review
  • I'm comfortable being the on-call owner for this change
  • Relevant changesets are included (or explicitly not required)

shrugs and others added 7 commits April 20, 2026 10:59
- operations array with optional `result` sentinel; passes layer transforms
- split ENSIP-19 and static-indexed accelerators into dedicated pass helpers
- abi becomes a bitmask (contract-equivalent), single `{ contentType, data } | null` response
- ContentType + InterfaceId land in enssdk
- resolveCallByIndex returns `unknown | undefined` (undefined = not accelerable)
- executeResolveCalls becomes terminal pass over operations, per-call interpret

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 20, 2026 20:15
@shrugs shrugs requested a review from a team as a code owner April 20, 2026 20:15
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 20, 2026

🦋 Changeset detected

Latest commit: 6dd481d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 23 packages
Name Type
@ensnode/ensdb-sdk Major
@ensnode/ensnode-sdk Major
ensindexer Major
ensapi Major
enssdk Major
@ensnode/integration-test-env Patch
ensadmin Major
ensrainbow Major
fallback-ensapi Major
@namehash/ens-referrals Major
@ensnode/ensnode-react Major
@ensnode/ensrainbow-sdk Major
@namehash/namehash-ui Major
@ensnode/enskit-react-example Patch
enskit Major
@docs/ensnode Major
@docs/ensrainbow Major
enscli Major
ensskills Major
@ensnode/datasources Major
@ensnode/ponder-sdk Major
@ensnode/ponder-subgraph Major
@ensnode/shared-configs Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
admin.ensnode.io Ready Ready Preview, Comment Apr 21, 2026 8:46pm
ensnode.io Ready Ready Preview, Comment Apr 21, 2026 8:46pm
ensrainbow.io Ready Ready Preview, Comment Apr 21, 2026 8:46pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

This PR extends ENS resolver to support resolving additional record types (contenthash, pubkey, ABI, interfaces, dnszonehash, version) through acceleration and RPC pathways. It refactors the resolution pipeline from call-based to operation-based architecture, updates database schemas to store indexed resolver values, and introduces new semantic types.

Changes

Cohort / File(s) Summary
Changeset & Versioning
.changeset/extend-resolver-records.md
Marks packages for minor release with changelog describing new resolver record selections and protocol-acceleration indexing support.
Resolution Architecture (Operations-Based)
apps/ensapi/src/lib/resolution/operations.ts, execute-operations.ts, make-records-response.ts, forward-resolution.ts
Introduces new operation-discriminated union type replacing call-based representation; exports makeOperations, executeOperations, interpretOperationWithRawResult, and refactored makeRecordsResponse to fold operations into typed resolver records.
Protocol Acceleration (Operation Routing)
apps/ensapi/src/lib/resolution/accelerate-ensip19-reverse-resolver.ts, accelerate-known-onchain-static-resolver.ts, apps/ensapi/src/lib/protocol-acceleration/get-records-from-index.ts, get-primary-name-from-index.ts
New acceleration modules that pre-resolve specific operation types using indexed database records; extend queries to fetch contenthash, pubkeyX, pubkeyY, dnszonehash, version; return type changed to InterpretedName.
Removed Legacy Call Architecture
apps/ensapi/src/lib/resolution/resolve-calls-and-results.ts
Deleted entire module containing call construction and execution logic; functionality migrated to operation-based system.
Resolution Tests & Integration
apps/ensapi/src/lib/resolution/make-records-response.test.ts, execute-operations.integration.test.ts, apps/ensapi/src/handlers/api/resolution/resolution-api.ts
Test coverage migrated from indexed-records model to operations model; integration test targets new executeOperations; API handler adds BigInt serialization via replaceBigInts.
Indexer Protocol Acceleration
apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts, apps/ensindexer/src/plugins/protocol-acceleration/handlers/Resolver.ts
Refactors resolver-record setup to unified ensureResolverAndRecords; adds handlers for ContenthashChanged, PubkeyChanged, DNSZonehashChanged; implements VersionChanged with bulk row deletion and version bump.
Subgraph Handler Types
apps/ensindexer/src/plugins/subgraph/shared-handlers/Resolver.ts
Updates event argument types to use semantic aliases (InterfaceId, RecordVersion).
Database Schema Extensions
packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts, packages/ensdb-sdk/src/lib/drizzle.ts
Adds contenthash, pubkeyX, pubkeyY, dnszonehash, version columns to resolverRecords table; updates BigInt stringification in drizzle schema helper.
New Semantic Types
packages/enssdk/src/lib/types/resolver.ts, packages/enssdk/src/lib/types/index.ts
Introduces ContentType (bigint), InterfaceId (Hex), RecordVersion (bigint) type aliases; re-exported through main SDK entry.
Resolver Value Interpretation
packages/ensnode-sdk/src/shared/interpretation/interpret-resolver-values.ts, .../interpret-resolver-values.test.ts, .../index.ts
New interpreters for contenthash, pubkey, and dnszonehash that treat zero-length/zero-pair as deletion; added comprehensive tests; re-exported through interpretation module.
Selection & Response Types
packages/ensnode-sdk/src/resolution/resolver-records-selection.ts, resolver-records-response.ts
Extended selection interface with boolean/array flags for new record types; broadened response generic mapping to include new fields; specialized handling for interfaces record map.
EIP-165 Interface Typing
packages/ensnode-sdk/src/rpc/eip-165.ts
Parameter type updated from Hex to InterfaceId for interface selector consistency.
Interface ID Validation
packages/enssdk/src/lib/interface-id.ts, packages/enssdk/src/lib/index.ts
New isInterfaceId predicate validating 4-byte hex selectors; re-exported at top level.
API Parameter Schema & OpenAPI
apps/ensapi/src/lib/handlers/params.schema.ts, docs/ensnode.io/ensapi-openapi.json
Extended params parsing to accept contenthash, pubkey, dnszonehash, version, abi (ContentType), interfaces (InterfaceId[]); OpenAPI schema documents new query parameters and response fields with proper typing.
Client-Side Integration
packages/ensnode-sdk/src/ensnode/client.ts, zod-schemas.ts
Client constructs query parameters for new selections; post-processes response to coerce BigInt fields from JSON strings; Zod schema documents wire format and conversion needs.
Miscellaneous
packages/ensnode-sdk/src/internal.ts, packages/enskit/src/react/omnigraph/provider.tsx
Added interpretation module exports; added explicit return type annotation to OmnigraphProvider.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • ENSv2 Plugin Events #1744: Both PRs modify resolver event indexing—adding/handling new resolver events (ContenthashChanged, PubkeyChanged, DNSZonehashChanged, VersionChanged) and updating related indexing helpers and schemas for protocol acceleration.
  • Replace ponder.on with addOnchainEventListener #1839: Both PRs refactor resolver-related indexing helpers and event handlers (apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts, Resolver.ts), consolidating setup flows and adding new field update handlers.
  • feat: add ensapi openapi examples #1872: Both PRs modify the ENS API resolution parameter schema and OpenAPI surface (adding new query selections and response fields for resolver records).

Suggested labels

ensnode-sdk, ensapi, ensindexer, enssdk, resolver-records

Poem

🐰 A Rabbit's Ode to Resolver Records

Oh, what a grand refactor swift and clean,
From calls to operations—pristine!
With pubkeys, hashes, versions stored with care,
The resolver now supports what's rare.
Through indexing lanes and RPC streams,
We fetch the records of our dreams! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main feature: adding support for resolver record types (contenthash, pubkey, abi, interfaces, dnszonehash, version) to the resolution API.
Description check ✅ Passed The PR description is comprehensive and follows the template structure with Summary, Why (linked issue #1505), Testing, Notes for Reviewer, and Pre-Review Checklist sections completed.
Linked Issues check ✅ Passed The PR successfully addresses issue #1505 by implementing support for contentHash (and related) record resolution through protocol acceleration and the resolution API pipeline.
Out of Scope Changes check ✅ Passed All code changes are directly aligned with the objective of extending resolver record support; no out-of-scope modifications were introduced beyond the stated scope.
Docstring Coverage ✅ Passed Docstring coverage is 81.48% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/extend-protocol-resolution

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 20, 2026

Greptile Summary

This PR extends the Resolution API from name/addresses/texts to the full resolver record set: contenthash, pubkey, abi, interfaces, dnszonehash, and version. The implementation follows a clean linear Operation[] pipeline in forward-resolution.ts, with each acceleration strategy as a pass and a single terminal RPC callsite. Protocol-acceleration indexing is wired for the new record types (with ABIChanged/InterfaceChanged intentionally left as RPC-only), and VersionChanged correctly bulk-clears all child records before setting the new version. All prior review concerns (ENSIP-19 reverse-resolver 500 on non-name selection, mixed raw-SQL/ORM semantics) have been addressed.

Confidence Score: 5/5

Safe to merge; all prior P0/P1 issues addressed, remaining finding is a P2 style suggestion.

The pipeline architecture is sound, the Operation discriminated union is exhaustive, interpreter functions are minimal and correct, the VersionChanged cache-flush semantics are confirmed, and all previous review concerns have been resolved. The only open finding is a P2 style suggestion on the pubkey null check.

No files require special attention; the VersionChanged raw-SQL path in resolver-db-helpers.ts is the highest-risk area but is well-documented and accepted per spec.

Important Files Changed

Filename Overview
apps/ensapi/src/lib/resolution/operations.ts Clean discriminated union driven by OperationMap; makeOperations correctly handles all selection fields including abi !== undefined guard for bigint-typed field.
apps/ensapi/src/lib/resolution/forward-resolution.ts Linear Operation[] pipeline is clean; acceleration passes are correctly composed; ENSIP-19 no-op guard and ENSv2 bailout are both well-handled.
apps/ensapi/src/lib/resolution/execute-operations.ts ENSIP-10 decode path correctly handles multi-output (ABI, pubkey) vs single-output functions; interpretOperationWithRawResult switch is exhaustive and type-safe.
apps/ensapi/src/lib/resolution/make-records-response.ts Single-pass reduce correctly folds all Operation variants into the response; unresolved ops (result: undefined) correctly map to null via ?? null.
apps/ensindexer/src/plugins/protocol-acceleration/handlers/Resolver.ts New handlers for ContenthashChanged, PubkeyChanged, DNSZonehashChanged, VersionChanged registered; ABIChanged/InterfaceChanged intentionally omitted with clear comment.
apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts VersionChanged handler correctly bulk-deletes address and text child records via raw SQL, then resets all scalar columns; DRY'd with ensureResolverAndRecords.
apps/ensapi/src/lib/resolution/accelerate-known-onchain-static-resolver.ts Correctly accelerates indexable operations; ABI/interfaceImplementer pass-through to RPC tail is well-documented; minor style suggestion on pubkey null check.
apps/ensapi/src/lib/resolution/accelerate-ensip19-reverse-resolver.ts No-op guard (selection.name !== true) now correctly prevents 500 for non-name selections; other operations flow unchanged to RPC tail.
packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts Additive schema additions (contenthash, pubkeyX/Y, dnszonehash, version) are nullable; version has no default to distinguish 'never seen' from explicit 0n.
packages/ensdb-sdk/src/lib/drizzle.ts safeStringifyDrizzleSchema bigint handler correctly serializes bigint values; acknowledged one-time checksum change for existing schemas.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[resolveForward] --> B{ENSv2 active?}
    B -- yes --> C[executeOperations via UniversalResolver]
    B -- no --> D[findResolver]
    D --> E{activeResolver found?}
    E -- no --> Z[makeRecordsResponse - empty]
    E -- yes --> F{isBridgedResolver?}
    F -- yes --> G[_resolveForward recursive]
    F -- no --> H{accelerate and canAccelerate?}
    H -- yes --> I{isKnownENSIP19ReverseResolver?}
    I -- yes and name selected --> J[accelerateENSIP19ReverseResolver]
    I -- no or name not selected --> K[skip pass]
    J --> L{isStaticResolver + records indexed?}
    K --> L
    L -- yes --> M[accelerateKnownOnchainStaticResolver\nname addr text contenthash pubkey zonehash recordVersions\nABI + interfaceImplementer pass-through to RPC]
    L -- no --> N[skip pass]
    M --> O{all ops resolved?}
    N --> O
    H -- no --> O
    O -- yes --> Z2[makeRecordsResponse]
    O -- no --> P[isExtendedResolver?]
    P --> Q[executeOperations via RPC\nsingle readContract per op multicalled by viem]
    Q --> R[invariant: all resolved]
    R --> Z2
Loading

Reviews (3): Last reviewed commit: "accelerate-ensip19: no-op on non-name se..." | Re-trigger Greptile

Comment thread apps/ensapi/src/lib/resolution/forward-resolution.ts
Comment thread apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Extends the Resolution API and protocol-acceleration/indexing pipeline to support additional resolver record types (contenthash, pubkey, abi, interfaces, dnszonehash, version) by introducing a typed Operation[] resolution pipeline, new interpretation helpers, and additive schema/indexing changes (including proper handling of VersionChanged).

Changes:

  • Add new resolver record selection/response fields and new semantic types (ContentType, InterfaceId, RecordVersion).
  • Restructure ENSAPI forward resolution into a linear Operation[] pipeline with acceleration passes and a single RPC tail (executeOperations).
  • Extend protocol-acceleration schema + handlers to index additional scalar resolver records and clear records on VersionChanged.

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/enssdk/src/lib/types/resolver.ts Adds new semantic types for resolver records (ABI bitmask, ERC-165 interface id, record version).
packages/enssdk/src/lib/types/index.ts Re-exports new resolver types from the enssdk types barrel.
packages/ensnode-sdk/src/shared/interpretation/interpret-resolver-values.ts Adds interpreters for contenthash/pubkey/dnszonehash deletion sentinels.
packages/ensnode-sdk/src/shared/interpretation/interpret-resolver-values.test.ts Unit tests for the new resolver value interpreters.
packages/ensnode-sdk/src/shared/interpretation/index.ts Exposes new interpretation utilities via the shared barrel.
packages/ensnode-sdk/src/rpc/eip-165.ts Migrates EIP-165 reader types to InterfaceId.
packages/ensnode-sdk/src/resolution/resolver-records-selection.ts Extends selection surface to include new record types.
packages/ensnode-sdk/src/resolution/resolver-records-response.ts Extends response surface and selection→response typing (abi/interfaces/version/etc.).
packages/ensnode-sdk/src/internal.ts Re-exports new internal interpretation helpers for ENSAPI/Indexer use.
packages/ensdb-sdk/src/lib/drizzle.ts Makes schema checksum stringification bigint-safe.
packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts Adds new indexed resolver scalar columns + version default.
apps/ensindexer/src/plugins/subgraph/shared-handlers/Resolver.ts Updates subgraph handler event arg types to new semantic types.
apps/ensindexer/src/plugins/protocol-acceleration/handlers/Resolver.ts Registers new resolver event handlers and consolidates setup via ensureResolverAndRecords.
apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts Adds helpers to update new records and handles VersionChanged bulk delete/reset.
apps/ensapi/src/lib/resolution/resolve-with-universal-resolver.integration.test.ts Removes old integration test (related logic moved/renamed).
apps/ensapi/src/lib/resolution/resolve-calls-and-results.ts Deletes old call/result model in favor of Operation[].
apps/ensapi/src/lib/resolution/operations.ts Introduces typed Operation discriminated union + selection→ops builder + logging helpers.
apps/ensapi/src/lib/resolution/make-records-response.ts Replaces multiple response builders with a single fold over Operation[].
apps/ensapi/src/lib/resolution/make-records-response.test.ts Rewrites unit tests around Operation[] folding + defaults for unresolved ops.
apps/ensapi/src/lib/resolution/forward-resolution.ts Refactors forward resolution into linear Operation[] pipeline + acceleration passes + single RPC tail.
apps/ensapi/src/lib/resolution/execute-operations.ts Adds core RPC executor for unresolved operations + per-op interpretation.
apps/ensapi/src/lib/resolution/execute-operations-with-universal-resolver.ts Updates ENSv2 bailout universal-resolver path to operate on Operation[].
apps/ensapi/src/lib/resolution/accelerate-known-onchain-static-resolver.ts Adds index-backed acceleration pass for static resolvers (fills indexable ops only).
apps/ensapi/src/lib/resolution/accelerate-ensip19-reverse-resolver.ts Adds ENSIP-19 reverse-resolver acceleration pass (fills name op from index).
apps/ensapi/src/lib/protocol-acceleration/get-records-from-index.ts Returns full resolverRecords row shape (now includes new scalar columns) and preserves address-defaulting behavior.
apps/ensapi/src/lib/protocol-acceleration/get-primary-name-from-index.ts Tightens reverse-name return type to `InterpretedName
.changeset/extend-resolver-records.md Adds changeset documenting the expanded resolution surface + indexing behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/ensnode-sdk/src/resolution/resolver-records-selection.ts Outdated
Comment thread apps/ensapi/src/lib/resolution/forward-resolution.ts Outdated
Comment thread apps/ensapi/src/lib/resolution/forward-resolution.ts Outdated
Comment thread apps/ensapi/src/lib/resolution/accelerate-ensip19-reverse-resolver.ts Outdated
Comment thread apps/ensapi/src/lib/resolution/forward-resolution.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ensapi/src/lib/protocol-acceleration/get-records-from-index.ts`:
- Around line 40-41: The comment above the null-check in
get-records-from-index.ts no longer matches the code; update or remove the
comment that currently reads "coalesce undefined to null" sitting above the line
"if (!row) return null;". Replace it with a concise, accurate note such as
"findFirst returns undefined when no row matches; return null" or simply drop
the comment so the null-guard stands alone; apply this change in the
get-records-from-index file near the if (!row) return null check.

In `@apps/ensapi/src/lib/resolution/accelerate-ensip19-reverse-resolver.ts`:
- Around line 29-44: The loop calls parseReverseName(name) and
getENSIP19ReverseNameRecordFromIndex for each operation, causing redundant work
and repeated invariant errors; hoist parsing and the index lookup out of the
operations.map() so they run once before Promise.all: call
parseReverseName(name) once, validate and throw the invariant if invalid, then
(if valid) call getENSIP19ReverseNameRecordFromIndex(parsed.address,
parsed.coinType) once to get the result, and inside the map (used with
isOperationResolved and op.functionName checks) simply reuse that parsed/result
when returning the updated op.

In `@apps/ensapi/src/lib/resolution/accelerate-known-onchain-static-resolver.ts`:
- Around line 51-55: The addr branch currently converts both sides with
bigintToCoinType and compares the results, which can throw for non-standard coin
types; change the predicate in the records?.addressRecords.find call to compare
the bigints directly (r.coinType === op.args[1]) and return found?.value ?? null
as before, and remove the bigintToCoinType import if it becomes unused; update
any references in the case "addr" block to rely on op.args[1] (bigint) and
r.coinType (bigint) without conversion.

In `@apps/ensapi/src/lib/resolution/operations.ts`:
- Around line 14-18: The JSDoc in operations.ts refers to a stale symbol name
interpretRawRpcCallAndResult; update that comment to reference the actual
exported interpreter interpretOperationWithRawResult so maintainers can find the
implementation; ensure the comment still mentions Operation and makeOperations
to preserve context about the canonical mapping contract.

In `@apps/ensindexer/src/plugins/protocol-acceleration/handlers/Resolver.ts`:
- Around line 172-177: Rename the handler function handleResolverVersionChange
to handleResolverVersionUpdate to match the existing *Update naming convention;
update the call site in addOnchainEventListener (where
handleResolverVersionChange is invoked), rename the actual function
declaration/definition to handleResolverVersionUpdate, and adjust any
exports/imports or references (e.g., tests or other modules) that mention
handleResolverVersionChange so they point to handleResolverVersionUpdate.

In `@packages/ensnode-sdk/src/resolution/resolver-records-selection.ts`:
- Around line 57-66: isSelectionEmpty incorrectly treats selection.abi (a
ContentType bigint) as falsy (so 0n is "empty") while makeOperations uses the
predicate selection.abi !== undefined; update isSelectionEmpty in
resolver-records-selection.ts to check abi using selection.abi !== undefined
(not !selection.abi) so the ResolverRecordsSelection/abi semantics match
makeOperations and a selection with abi: 0n is not considered empty.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ff5bc5da-3288-45d9-998b-742f1c6f0881

📥 Commits

Reviewing files that changed from the base of the PR and between fc88ee5 and f859e39.

📒 Files selected for processing (27)
  • .changeset/extend-resolver-records.md
  • apps/ensapi/src/lib/protocol-acceleration/get-primary-name-from-index.ts
  • apps/ensapi/src/lib/protocol-acceleration/get-records-from-index.ts
  • apps/ensapi/src/lib/resolution/accelerate-ensip19-reverse-resolver.ts
  • apps/ensapi/src/lib/resolution/accelerate-known-onchain-static-resolver.ts
  • apps/ensapi/src/lib/resolution/execute-operations-with-universal-resolver.ts
  • apps/ensapi/src/lib/resolution/execute-operations.ts
  • apps/ensapi/src/lib/resolution/forward-resolution.ts
  • apps/ensapi/src/lib/resolution/make-records-response.test.ts
  • apps/ensapi/src/lib/resolution/make-records-response.ts
  • apps/ensapi/src/lib/resolution/operations.ts
  • apps/ensapi/src/lib/resolution/resolve-calls-and-results.ts
  • apps/ensapi/src/lib/resolution/resolve-with-universal-resolver.integration.test.ts
  • apps/ensindexer/src/lib/protocol-acceleration/resolver-db-helpers.ts
  • apps/ensindexer/src/plugins/protocol-acceleration/handlers/Resolver.ts
  • apps/ensindexer/src/plugins/subgraph/shared-handlers/Resolver.ts
  • packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts
  • packages/ensdb-sdk/src/lib/drizzle.ts
  • packages/ensnode-sdk/src/internal.ts
  • packages/ensnode-sdk/src/resolution/resolver-records-response.ts
  • packages/ensnode-sdk/src/resolution/resolver-records-selection.ts
  • packages/ensnode-sdk/src/rpc/eip-165.ts
  • packages/ensnode-sdk/src/shared/interpretation/index.ts
  • packages/ensnode-sdk/src/shared/interpretation/interpret-resolver-values.test.ts
  • packages/ensnode-sdk/src/shared/interpretation/interpret-resolver-values.ts
  • packages/enssdk/src/lib/types/index.ts
  • packages/enssdk/src/lib/types/resolver.ts
💤 Files with no reviewable changes (2)
  • apps/ensapi/src/lib/resolution/resolve-with-universal-resolver.integration.test.ts
  • apps/ensapi/src/lib/resolution/resolve-calls-and-results.ts

Comment thread apps/ensapi/src/lib/protocol-acceleration/get-records-from-index.ts
Comment thread apps/ensapi/src/lib/resolution/accelerate-ensip19-reverse-resolver.ts Outdated
Comment thread apps/ensapi/src/lib/resolution/operations.ts
Comment thread packages/ensnode-sdk/src/resolution/resolver-records-selection.ts
- params.schema.ts: parse contenthash/pubkey/dnszonehash/version/abi/interfaces from query
- zod-schemas.ts: describe wire shape (bigints serialized as strings)
- client.ts: encode new selection fields into URL
- resolution-api.ts: replaceBigInts on response to avoid JSON.stringify crash

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- forward-resolution: typo foward→forward, bigint-safe stringify in invariant
  error message and tracing selectionString
- accelerate-ensip19: bigint-safe stringify on selection; hoist parseReverseName
  out of the per-op loop
- isSelectionEmpty: abi uses === undefined to match makeOperations
- accelerate-known-onchain-static-resolver: compare addr coinType bigints
  directly (bigintToCoinType throws on non-standard coinTypes stored in the
  index, would crash the accelerator)
- operations.ts: fix stale JSDoc reference to interpretRawRpcCallAndResult

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

apps/ensapi/src/lib/resolution/execute-operations-with-universal-resolver.ts:50

  • The previous integration test for UniversalResolver resolution was deleted, and there doesn't appear to be a replacement covering executeOperationsWithUniversalResolver (used in the ENSv2 bailout path). Please add an integration test that exercises at least one successful resolution and one unresolvable/empty-bytes case to avoid regressions in this critical fallback path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

single call site — the helper didn't pull its weight. scalar reset + raw sql
bulk deletes now live directly next to the event registration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io April 20, 2026 22:18 Inactive
@shrugs
Copy link
Copy Markdown
Member Author

shrugs commented Apr 20, 2026

@greptile please re-review — addressed the P1 on the ENSIP-19 accelerator (5cd5444).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ensapi/src/lib/handlers/params.schema.ts`:
- Around line 73-99: The interfaces pipeline currently allows case-variants to
pass because interfaceId lowercases during transform, so deduplicate the array
after normalization: update the selectionFields.interfaces schema (the branch
using stringarray.pipe(z.array(interfaceId))) to apply a transform that removes
duplicate InterfaceId values (e.g., Array.from(new Set(...)) or equivalent)
after the z.array(interfaceId) normalization so only unique lowercased interface
IDs remain; keep the rest of the pipeline intact and ensure the transformed type
stays InterfaceId[].

In `@apps/ensapi/src/lib/resolution/accelerate-ensip19-reverse-resolver.ts`:
- Around line 29-35: The code currently throws when parseReverseName(name)
returns falsy; change this to treat non-reverse names as a cache-miss by
returning the unchanged operations instead of throwing. Locate the
parseReverseName(name) call and the falsy check (the parsed variable) in
accelerate-ensip19-reverse-resolver and replace the throw block with a simple
return of the existing operations (preserving the original operations
array/object), so non-reverse names fall back to the unaccelerated RPC path.

In `@packages/ensnode-sdk/src/resolution/resolver-records-response.ts`:
- Around line 90-104: The mapped type key predicate in ResolverRecordsResponse
currently checks T[K] extends true | any[] | bigint which fails for readonly
tuple selections; update that predicate to include readonly arrays (e.g. change
to T[K] extends true | readonly any[] | bigint) so readonly selections like as
const tuples are accepted; modify the condition in the ResolverRecordsResponse
mapped type (the key remapping that uses T[K] extends ...) to use readonly any[]
instead of any[] and keep the existing branch logic (addresses/texts/interfaces)
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2752c441-08c3-48bc-97fb-dbbf677768db

📥 Commits

Reviewing files that changed from the base of the PR and between a552d3d and 3fa7b15.

📒 Files selected for processing (17)
  • apps/ensapi/src/handlers/api/resolution/resolution-api.ts
  • apps/ensapi/src/lib/handlers/params.schema.ts
  • apps/ensapi/src/lib/resolution/accelerate-ensip19-reverse-resolver.ts
  • apps/ensapi/src/lib/resolution/accelerate-known-onchain-static-resolver.ts
  • apps/ensapi/src/lib/resolution/execute-operations.ts
  • apps/ensapi/src/lib/resolution/forward-resolution.ts
  • apps/ensapi/src/lib/resolution/make-records-response.test.ts
  • apps/ensapi/src/lib/resolution/make-records-response.ts
  • apps/ensapi/src/lib/resolution/operations.ts
  • docs/ensnode.io/ensapi-openapi.json
  • packages/ensdb-sdk/src/ensindexer-abstract/protocol-acceleration.schema.ts
  • packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts
  • packages/ensnode-sdk/src/ensapi/client.ts
  • packages/ensnode-sdk/src/resolution/resolver-records-response.ts
  • packages/enssdk/src/lib/index.ts
  • packages/enssdk/src/lib/interface-id.ts
  • packages/enssdk/src/lib/types/resolver.ts

Comment thread apps/ensapi/src/lib/handlers/params.schema.ts
Comment thread packages/ensnode-sdk/src/resolution/resolver-records-response.ts
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 34 out of 34 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/ensnode-sdk/src/resolution/resolver-records-response.ts
Comment thread apps/ensapi/src/lib/resolution/execute-operations.ts
tsup's dts rollup can't portably name the inferred ReactElement return type
on OmnigraphProvider — the @types/react symlink path in pnpm is non-deterministic,
so the build fails intermittently depending on link-resolution order. explicit
return type makes it deterministic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io April 21, 2026 14:52 Inactive
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io April 21, 2026 14:52 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensnode.io April 21, 2026 14:52 Inactive
the key-remap predicate checked \`T[K] extends true | any[] | bigint\`, which
excluded \`readonly\` tuples. \`as const satisfies ResolverRecordsSelection\`
selections with \`addresses: readonly [60, 1001]\` got their keys dropped from
the mapped type. widen to \`readonly any[]\`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 35 out of 35 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/ensapi/src/lib/resolution/forward-resolution.ts
Comment thread apps/ensapi/src/lib/protocol-acceleration/get-records-from-index.ts
Copy link
Copy Markdown
Member

@lightwalker-eth lightwalker-eth left a comment

Choose a reason for hiding this comment

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

@shrugs Love the abstractions introduced here. Looks super! Some very small comments please take the lead to merge when ready 👍

Comment thread .changeset/extend-resolver-records.md
Comment thread apps/ensapi/src/handlers/api/resolution/resolution-api.ts
Comment thread apps/ensapi/src/lib/resolution/forward-resolution.ts
shrugs added 2 commits April 21, 2026 15:19
…resolution

# Conflicts:
#	apps/ensapi/src/handlers/api/resolution/resolution-api.ts
#	apps/ensapi/src/lib/handlers/params.schema.ts
#	docs/ensnode.io/ensapi-openapi.json
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
apps/ensapi/src/lib/handlers/params.schema.ts (1)

103-106: ⚠️ Potential issue | 🟡 Minor

Reject duplicate interface IDs after normalization.

stringarray checks uniqueness before interfaceId lowercases, so 0x01FFC9A7,0x01ffc9a7 passes validation and becomes duplicate InterfaceId entries.

🛡️ Proposed fix
 const interfaceId = z
   .string()
   .refine(isInterfaceId, "Must be a 4-byte hex (0x + 8 hex chars)")
   .transform((val) => val.toLowerCase() as InterfaceId);
+
+const interfaceIds = stringarray
+  .pipe(z.array(interfaceId))
+  .refine((values) => new Set(values).size === values.length, {
+    message: "Must be a set of unique entries.",
+  });
 
 const rawSelectionParams = z.object({
@@
   version: z.optional(boolstring),
   abi: z.optional(contentTypeBitmask),
-  interfaces: z.optional(stringarray.pipe(z.array(interfaceId))),
+  interfaces: z.optional(interfaceIds),
 });

Also applies to: 145-145

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ensapi/src/lib/handlers/params.schema.ts` around lines 103 - 106, The
current schema lowercases values in the interfaceId transform (interfaceId)
after uniqueness was already enforced by stringarray, allowing duplicates like
"0x01FFC9A7,0x01ffc9a7"; fix by performing uniqueness checking after
normalization: update the array schema (stringarray) to map/transform each entry
to the normalized InterfaceId (use interfaceId.parse/transform or a .transform
on the array elements) before enforcing uniqueness, or add a .superRefine on the
array that lowercases all entries and rejects duplicates (compare normalized
values) so duplicate InterfaceId entries are rejected post-normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@apps/ensapi/src/lib/handlers/params.schema.ts`:
- Around line 103-106: The current schema lowercases values in the interfaceId
transform (interfaceId) after uniqueness was already enforced by stringarray,
allowing duplicates like "0x01FFC9A7,0x01ffc9a7"; fix by performing uniqueness
checking after normalization: update the array schema (stringarray) to
map/transform each entry to the normalized InterfaceId (use
interfaceId.parse/transform or a .transform on the array elements) before
enforcing uniqueness, or add a .superRefine on the array that lowercases all
entries and rejects duplicates (compare normalized values) so duplicate
InterfaceId entries are rejected post-normalization.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e773a47f-cadc-45fe-8172-c3ab9430af3c

📥 Commits

Reviewing files that changed from the base of the PR and between 3fa7b15 and 6dd481d.

📒 Files selected for processing (9)
  • apps/ensapi/src/handlers/api/resolution/resolution-api.ts
  • apps/ensapi/src/lib/handlers/params.schema.ts
  • apps/ensapi/src/lib/resolution/execute-operations.integration.test.ts
  • docs/ensnode.io/ensapi-openapi.json
  • packages/enskit/src/react/omnigraph/provider.tsx
  • packages/ensnode-sdk/src/ensnode/api/resolution/zod-schemas.ts
  • packages/ensnode-sdk/src/ensnode/client.ts
  • packages/ensnode-sdk/src/internal.ts
  • packages/ensnode-sdk/src/resolution/resolver-records-response.ts

@shrugs shrugs merged commit 5f341e1 into main Apr 21, 2026
20 checks passed
@shrugs shrugs deleted the feat/extend-protocol-resolution branch April 21, 2026 20:55
@github-actions github-actions Bot mentioned this pull request Apr 21, 2026
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.

Support resolution of contentHash records

3 participants