Skip to content

[WIP] Integration of Indexing Status Builder into ENSIndexer API#1614

Draft
tk-o wants to merge 1 commit intofeat/indexing-status-builder-2from
feat/indexing-status-builder-3
Draft

[WIP] Integration of Indexing Status Builder into ENSIndexer API#1614
tk-o wants to merge 1 commit intofeat/indexing-status-builder-2from
feat/indexing-status-builder-3

Conversation

@tk-o
Copy link
Contributor

@tk-o tk-o commented Feb 6, 2026

Lite PR

Tip: Review docs on the ENSNode PR process

Summary

  • This PR presents an initial integration of Indexing Status Builder with ENSIndexer API

Why

  • We need to properly contain layers of abstraction when it comes to integrating Ponder SDK into ENSIndexer. Three layers apply:
    • Layer 1: Ponder SDK which has 0 external dependencies (apart from the Prometheus Metrics parser dependency).
    • Layer 2: Indexing Status Builder which can build OmnichainIndexingStatusSnapshot based on abstractions from viem and @ensnode/ponder-sdk (and if really needed, for the time being, from @ensnode/ensnode-sdk ).
    • Layer 3: ENSIndexer powering Layer 2 with Ponder APIs.

Testing

  • How this was tested.
  • If you didn't test it, say why.

Notes for Reviewer (Optional)


Pre-Review Checklist (Blocking)

  • This PR does not introduce significant changes and is low-risk to review quickly.
  • Relevant changesets are included (or are not required)

Copilot AI review requested due to automatic review settings February 6, 2026 19:31
@vercel
Copy link
Contributor

vercel bot commented Feb 6, 2026

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

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
admin.ensnode.io Skipped Skipped Feb 6, 2026 7:31pm
ensnode.io Skipped Skipped Feb 6, 2026 7:31pm
ensrainbow.io Skipped Skipped Feb 6, 2026 7:31pm

@changeset-bot
Copy link

changeset-bot bot commented Feb 6, 2026

⚠️ No Changeset found

Latest commit: 17e224c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai
Copy link

coderabbitai bot commented Feb 6, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/indexing-status-builder-3

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.

// otherwise, proceed with creating IndexingStatusResponseOk
const crossChainSnapshot = createCrossChainIndexingStatusSnapshotOmnichain(
omnichainSnapshot,
const crossChainIndexingSnapshot = await fetchAndBuildCrossChainIndexingStatusSnapshot(
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing error handling in /indexing-status endpoint causes uncaught errors when fetchAndBuildCrossChainIndexingStatusSnapshot fails

Fix on Vercel

Comment on lines +15 to +17
} from "@/lib/indexing-status-builder/chain-block-refs";
import { buildCrossChainIndexingStatusSnapshotOmnichain } from "@/lib/indexing-status-builder/corss-chain-indexing-status-snapshot";
import { buildOmnichainIndexingStatusSnapshot } from "@/lib/indexing-status-builder/omnichain-indexing-status-snapshot";
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
} from "@/lib/indexing-status-builder/chain-block-refs";
import { buildCrossChainIndexingStatusSnapshotOmnichain } from "@/lib/indexing-status-builder/corss-chain-indexing-status-snapshot";
import { buildOmnichainIndexingStatusSnapshot } from "@/lib/indexing-status-builder/omnichain-indexing-status-snapshot";
} from "@/../lib/indexing-status-builder/chain-block-refs";
import { buildCrossChainIndexingStatusSnapshotOmnichain } from "@/../lib/indexing-status-builder/corss-chain-indexing-status-snapshot";
import { buildOmnichainIndexingStatusSnapshot } from "@/../lib/indexing-status-builder/omnichain-indexing-status-snapshot";

Incorrect import paths prevent resolution of shared library files from parent ensindexer app

Fix on Vercel

type ChainBlockRefs,
getChainsBlockRefs,
} from "@/lib/indexing-status-builder/chain-block-refs";
import { buildCrossChainIndexingStatusSnapshotOmnichain } from "@/lib/indexing-status-builder/corss-chain-indexing-status-snapshot";
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
import { buildCrossChainIndexingStatusSnapshotOmnichain } from "@/lib/indexing-status-builder/corss-chain-indexing-status-snapshot";
import { buildCrossChainIndexingStatusSnapshotOmnichain } from "@/lib/indexing-status-builder/cross-chain-indexing-status-snapshot";

Typo in import path and filename - "corss-chain" should be "cross-chain" (extra 's')

Fix on Vercel

Copy link
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

Integrates the new “Indexing Status Builder” layer into the ENSIndexer (Ponder) HTTP API by moving /indexing-status snapshot construction onto builder + PonderClient-fetched metadata.

Changes:

  • Added fetchAndBuildCrossChainIndexingStatusSnapshot() to fetch Ponder /metrics + /status, compute chain block refs, and build an omnichain cross-chain snapshot.
  • Added a Ponder-config parsing helper to derive per-chain blockranges from datasource start/end blocks.
  • Updated /indexing-status handler to use the new snapshot builder flow.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

File Description
apps/ensindexer/ponder/src/lib/cross-chain-indexing-status-snapshot.ts New builder integration: fetch Ponder metadata, compute block refs, build cross-chain snapshot.
apps/ensindexer/ponder/src/lib/chains-config-blockrange.ts New helper to derive per-chain blockranges from ponder.config.ts datasources.
apps/ensindexer/ponder/src/api/handlers/ensnode-api.ts Switches /indexing-status to the new fetch+build snapshot function.

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

* Get a {@link Blockrange} for each indexed chain.
*
* Invariants:
* - every chain include a startBlock,
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

Grammar in the invariants list: “every chain include a startBlock” should be “every chain includes a startBlock”.

Suggested change
* - every chain include a startBlock,
* - every chain includes a startBlock,

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +54
/**
* Chain Name
*
* Often use as type for object keys expressing Ponder ideas, such as
* chain status, or chain metrics.
*/
export type ChainName = string;

/**
* Ponder config datasource with a flat `chain` value.
*/
export type PonderConfigDatasourceFlat = {
chain: ChainName;
} & AddressConfig &
Blockrange;

/**
* Ponder config datasource with a nested `chain` value.
*/
export type PonderConfigDatasourceNested = {
chain: Record<ChainName, AddressConfig & Blockrange>;
};

/**
* Ponder config datasource
*/
export type PonderConfigDatasource = PonderConfigDatasourceFlat | PonderConfigDatasourceNested;

/**
* Ponder config datasource
*/
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

This file appears to duplicate the existing Ponder-config parsing logic in apps/ensindexer/src/lib/indexing-status/ponder-metadata/config.ts (including identical types and error messages). Duplicating this logic across two locations increases the risk of them drifting apart; consider re-exporting/reusing the existing implementation (or moving it to a shared module) instead of maintaining two copies.

Suggested change
/**
* Chain Name
*
* Often use as type for object keys expressing Ponder ideas, such as
* chain status, or chain metrics.
*/
export type ChainName = string;
/**
* Ponder config datasource with a flat `chain` value.
*/
export type PonderConfigDatasourceFlat = {
chain: ChainName;
} & AddressConfig &
Blockrange;
/**
* Ponder config datasource with a nested `chain` value.
*/
export type PonderConfigDatasourceNested = {
chain: Record<ChainName, AddressConfig & Blockrange>;
};
/**
* Ponder config datasource
*/
export type PonderConfigDatasource = PonderConfigDatasourceFlat | PonderConfigDatasourceNested;
/**
* Ponder config datasource
*/
export type {
ChainName,
PonderConfigDatasourceFlat,
PonderConfigDatasourceNested,
PonderConfigDatasource,
} from "../../../src/lib/indexing-status/ponder-metadata/config";
/**
* Ponder config datasource
*/

Copilot uses AI. Check for mistakes.
type ChainBlockRefs,
getChainsBlockRefs,
} from "@/lib/indexing-status-builder/chain-block-refs";
import { buildCrossChainIndexingStatusSnapshotOmnichain } from "@/lib/indexing-status-builder/corss-chain-indexing-status-snapshot";
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

Import path contains a typo (corss-chain-indexing-status-snapshot). Even if the underlying file currently uses that spelling, propagating the typo into new code makes it harder to discover/maintain. Consider renaming the module to cross-chain-indexing-status-snapshot (and updating imports) or adding a correctly spelled re-export to avoid baking in the misspelling.

Suggested change
import { buildCrossChainIndexingStatusSnapshotOmnichain } from "@/lib/indexing-status-builder/corss-chain-indexing-status-snapshot";
import { buildCrossChainIndexingStatusSnapshotOmnichain } from "@/lib/indexing-status-builder/cross-chain-indexing-status-snapshot";

Copilot uses AI. Check for mistakes.
Comment on lines +33 to 36
const crossChainIndexingSnapshot = await fetchAndBuildCrossChainIndexingStatusSnapshot(
publicClients,
snapshotTime,
);
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

/indexing-status no longer handles failures from fetchAndBuildCrossChainIndexingStatusSnapshot(). Any thrown error will be caught by the global app.onError handler and returned as { message: "Internal Server Error" }, which breaks the ENSNode API contract that callers can always discriminate on responseCode (should return IndexingStatusResponseCodes.Error with HTTP 500). Wrap this call in a try/catch and return a serialized error response on failure (optionally log the underlying error).

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +46
// TODO: make it a cached call, so the RPC requests are performed just once, at the application startup
const chainsBlockRefs: Map<number, ChainBlockRefs> = await getChainsBlockRefs(
indexedChainIds,
chainsConfigBlockrange,
ponderIndexingMetrics.chains,
publicClients,
);
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

This implementation performs RPC calls on every /indexing-status request via getChainsBlockRefs(...) (which fetches multiple block refs per chain). Previously this endpoint used a cached block-ref lookup; without caching this can add significant latency/load. Consider memoizing the computed chainsBlockRefs (and/or the chainsConfigBlockrange) similarly to the existing cached approach so the RPC calls happen once per process/startup, not per request.

Copilot uses AI. Check for mistakes.
]);

// TODO: make it a cached call, so the RPC requests are performed just once, at the application startup
const chainsBlockRefs: Map<number, ChainBlockRefs> = await getChainsBlockRefs(
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

chainsBlockRefs is typed as Map<number, ChainBlockRefs>, but getChainsBlockRefs() returns Map<ChainId, ChainBlockRefs>. Using number here weakens type safety and can hide key-type mismatches; prefer Map<ChainId, ChainBlockRefs> to keep the type consistent end-to-end.

Suggested change
const chainsBlockRefs: Map<number, ChainBlockRefs> = await getChainsBlockRefs(
const chainsBlockRefs: Map<ChainId, ChainBlockRefs> = await getChainsBlockRefs(

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +31
/**
* Chain Name
*
* Often use as type for object keys expressing Ponder ideas, such as
* chain status, or chain metrics.
*/
export type ChainName = string;

Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

The code/documentation refers to ChainName, but in this codebase ponderConfig.chains keys are chain IDs stringified (see chainsConnectionConfig() using [chainId.toString()]). Using ChainName = string here is misleading and makes it easier to accidentally pass non-chain-id keys. Consider renaming this to something like ChainIdString (or reusing the SDK’s ChainIdString type) and updating the related comments accordingly.

Copilot uses AI. Check for mistakes.
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.

1 participant