Skip to content

feat(ensv2): HCA-aware Event.sender + filter + docs#2014

Merged
shrugs merged 11 commits intomainfrom
feat/hca-aware-events
Apr 29, 2026
Merged

feat(ensv2): HCA-aware Event.sender + filter + docs#2014
shrugs merged 11 commits intomainfrom
feat/hca-aware-events

Conversation

@shrugs
Copy link
Copy Markdown
Member

@shrugs shrugs commented Apr 29, 2026

closes #1813

Reviewer Focus (Read This First)

primary review surface:

  1. Account.events semantics flip (apps/ensapi/src/omnigraph-api/schema/account.ts): now filters by sender (HCA-aware) instead of from (tx.from). this is a quiet behavior change — anyone relying on the old "all txs this EOA submitted" semantics will see different results once HCA traffic exists.
  2. handler sender plumbing (apps/ensindexer/src/plugins/ensv2/handlers/ensv2/*, apps/ensindexer/src/lib/ensv2/event-db-helpers.ts): the override path is what makes Event.sender HCA-aware. confirm each ENSv2 ensureEvent call site passes the right HCA-candidate arg (registrant / unregistrant / sender / operator) and not, e.g., the wrong field.
  3. schema column + index: new events.sender column (NOT NULL) and events_sender_index. requires reindex.

Problem & Motivation

ENSv2 contracts route writes through HCAs (Hybrid Custody Accounts / smart accounts) via IHCAFactoryBasic. on-chain events emit an explicit sender/owner/account argument that is HCA-aware — the HCA address rather than the controlling EOA. previously the indexed events table only stored tx.from, which is the EOA/relayer that submitted the transaction and is never HCA-aware. omnigraph consumers asking "which events did this account trigger" had no way to query by the HCA actor.

a sender column already existed on the events table and ensureEvent already accepted an optional override, but the handlers weren't passing it through, the GraphQL layer didn't expose it, no filter existed, and the schema didn't document HCA semantics anywhere.


What Changed (Concrete)

  1. packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts: documented HCA-awareness on event.sender, event.from (explicit "never HCA-aware"), domain.ownerId, registration.registrantId/unregistrantId, permissionsUser.user. added bySender index on the events table.
  2. apps/ensindexer/src/lib/ensv2/event-db-helpers.ts: ensureEvent(context, event, sender?) already accepted an HCA-aware override; verified handler audit covered all call sites.
  3. ENSv2 handlers (ETHRegistrar.ts, ENSv2Registry.ts): pass HCA-candidate arg as the sender override on NameRegistered (owner), LabelRegistered/Reserved (sender), LabelUnregistered (sender), ExpiryUpdated (sender), SubregistryUpdated (sender), TransferSingle/Batch (operator). gaps (no actor in args, falls back to tx.from): EACRolesChanged granter, NameRenewed, TokenRegenerated, all shared Resolver:* events. accepted.
  4. apps/ensapi/src/omnigraph-api/schema/event.ts: exposed Event.sender field; updated Event.from description to call out non-HCA semantics; added sender filter to EventsWhereInput; updated from filter description; updated AccountEventsWhereInput to mark sender as implied.
  5. apps/ensapi/src/omnigraph-api/lib/find-events/find-events-resolver.ts: extended EventsWhere interface and eventsWhereConditions to apply the new sender filter.
  6. apps/ensapi/src/omnigraph-api/schema/account.ts: Account.events now resolves with sender = parent.id (HCA-aware) instead of from = parent.id.
  7. omnigraph schema doc updates: Domain.owner (polymorphic ENSv1/v2 wording), Registration.registrant/unregistrant (HCA-aware in v2), PermissionsUser.user, RegistryPermissionsUser.user, ResolverPermissionsUser.user.

Design & Planning

spec'd inline with @shrugs over two passes (initial proposal + re-proposal after the user clarified that event.sender already existed as an override mechanism and that they wanted it surfaced via filter). no separate design doc.

alternatives considered:

  • exposing only the schema column and skipping the GraphQL filter — rejected because consumers need to query by HCA actor for this to be useful.

  • keeping Account.events on from and adding a parallel Account.txs for the tx.from view — rejected as YAGNI; the HCA-aware sender is the more useful default and from filter remains available via EventsWhereInput.

  • reverse: rename event.senderevent.actor to avoid confusion with tx.from colloquially being "the sender" — rejected to minimize churn; docs clarify the distinction.

  • Planning artifacts: conversation transcript only.

  • Reviewed / approved by: @shrugs (live).


Self-Review

reviewed every changed file end-to-end after implementation.

  • Bugs caught: none new in this pass; the override plumbing was already in place from prior commits on this branch.
  • Logic simplified: docstring template unified to ..., the HCA account address, if used. for non-polymorphic fields and the explicit ENSv1/ENSv2 two-clause wording for Domain.owner and Registration.registrant/unregistrant.
  • Naming / terminology improved: Event.from description explicitly disclaims HCA-awareness; Event.sender describes fallback semantics; filter docs cross-reference each other.
  • Dead or unnecessary code removed: none — this PR is additive.

Cross-Codebase Alignment

  • Search terms used: HCA, IHCAFactoryBasic, ensureEvent, event.sender, event.from, _msgSender, sender:.
  • Reviewed but unchanged: ENSv1 handlers in apps/ensindexer/src/plugins/ensv2/handlers/ensv1/ (intentionally not HCA-aware per project decision); ENSv1Domain.rootRegistryOwner; Event.address and Event.to; AccountId.address; registry/registrar contract address columns.
  • Deferred alignment: no audit of EACRolesChanged granter (gap accepted; would require an upstream contract change to emit the granter).

Downstream & Consumer Impact

  • Public APIs affected: GraphQL schema gains Event.sender: Address! field and a sender filter on EventsWhereInput. Account.events semantics changes from tx.from-based to sender-based filtering.
  • Docs updated: schema doc comments + GraphQL field descriptions throughout. no separate docs site changes (descriptions ship via the GraphQL schema).
  • Naming decisions worth calling out: sender is overloaded — tx.from is colloquially "the sender" but in this schema "sender" is reserved for the HCA-aware actor. descriptions on both Event.from and Event.sender explicitly cross-link to disambiguate.

Testing Evidence

  • Testing performed:
    • pnpm typecheck clean across all 24 workspace projects.
    • devnet (feat/hca-aware-events branch) reindexed against the running anvil; verified the events.sender column is populated for all 762 indexed events.
    • 24 events have sender != from — exactly the Registry events routed through ETHRegistrar (LabelRegistered, ExpiryUpdated, TransferSingle). spot-checked tx 0x1c8a1a5c…b0 via cast tx: tx.from = 0x7099…79C8 (user EOA), tx.to = 0x4C4a…5584 (ETHRegistrar), event emitted from registry 0x8f86…fe4cf, indexed event.sender = 0x4C4a…5584 (ETHRegistrar — the registry's _msgSender()).
    • confirmed events_sender_index exists on the table after reindex.
  • Known gaps:
    • devnet test fixtures don't actually deploy + use an HCA, so we can't differentiate "HCA actor" from "intermediary contract caller". the override mechanism is identical for both paths, so the user→HCA→Registry case will produce the HCA address by the same code path; not a separate code path under test.
    • no integration test covers Account.events returning HCA-aware results.
  • What reviewers have to reason about manually: that each handler's chosen override arg is the right HCA-candidate (e.g., TransferSingle uses operator rather than from/to).

Scope Reductions

  • Follow-ups:
    • extend devnet fixtures to deploy an HCA via HCAFactory and route at least one register/transfer through it for a true HCA-vs-EOA differentiation test.
    • integration test for Account.events HCA-aware filtering.
    • upstream contract change to emit the granter address on EACRolesChanged.
  • Why deferred: each is a stand-alone improvement; this PR's surface is already the doc + plumbing + filter triad and shouldn't grow.

Risk Analysis

  • Risk areas:
    • Account.events behavior change is silent. callers expecting old semantics will see different results once HCA traffic exists. today the devnet has no HCAs so the practical delta is zero, but staging/prod consumers should be informed.
    • new NOT NULL events.sender column requires reindex. existing deployments will need to drop and rebuild the events table (or run a backfill that defaults sender to from).
    • new index events_sender_index is a write-path cost; negligible relative to existing indexes on the same table.
  • Mitigations or rollback options: revert is clean — schema column and index can be dropped, Account.events resolver reverts to from = parent.id, GraphQL schema removes one field and one filter argument.
  • 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)

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings April 29, 2026 17:41
@shrugs shrugs requested a review from a team as a code owner April 29, 2026 17:41
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 29, 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 29, 2026 11:06pm
ensnode.io Ready Ready Preview, Comment Apr 29, 2026 11:06pm
ensrainbow.io Ready Ready Preview, Comment Apr 29, 2026 11:06pm

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 29, 2026

🦋 Changeset detected

Latest commit: 21e87e0

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

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

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

Warning

Rate limit exceeded

@shrugs has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 55 minutes and 48 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a84d0701-0cf5-4ec0-8ae7-644f578aef5c

📥 Commits

Reviewing files that changed from the base of the PR and between ca35d93 and 21e87e0.

⛔ Files ignored due to path filters (2)
  • packages/enssdk/src/omnigraph/generated/introspection.ts is excluded by !**/generated/**
  • packages/enssdk/src/omnigraph/generated/schema.graphql is excluded by !**/generated/**
📒 Files selected for processing (14)
  • apps/ensapi/src/lib/resolution/execute-operations.ts
  • apps/ensapi/src/omnigraph-api/schema/account.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.ts
  • apps/ensapi/src/omnigraph-api/schema/event.ts
  • apps/ensapi/src/omnigraph-api/schema/permissions.ts
  • apps/ensapi/src/omnigraph-api/schema/registration.ts
  • apps/ensapi/src/omnigraph-api/schema/registry-permissions-user.ts
  • apps/ensapi/src/omnigraph-api/schema/resolver-permissions-user.ts
  • apps/ensapi/src/test/integration/find-events/event-pagination-queries.ts
  • apps/ensindexer/src/lib/ensv2/account-db-helpers.ts
  • apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ETHRegistrar.ts
  • docs/ensnode.io/src/content/docs/ensdb/concepts/database-schemas.mdx
  • packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts
  • packages/ensnode-sdk/src/shared/interpretation/interpret-address.ts
📝 Walkthrough

Walkthrough

This PR introduces HCA-aware event support to the Omnigraph API and ENS indexer. It adds a new Event.sender field, updates event filtering to use the HCA-aware sender, modifies the database schema to track sender and normalize address types, and adjusts ENS event handlers to ensure account identifiers before storing events.

Changes

Cohort / File(s) Summary
Changeset Documentation
.changeset/hca-aware-events.md
Documents the minor release introducing HCA-aware event support, including Event.sender, EventsWhereInput.sender, and updated semantics for ownership/registration fields.
GraphQL Event Schema
apps/ensapi/src/omnigraph-api/schema/event.ts, apps/ensapi/src/omnigraph-api/lib/find-events/find-events-resolver.ts
Adds Event.sender field (HCA-aware), EventsWhereInput.sender filter, updates from field documentation to clarify it refers to tx.from, and implements SQL condition builder for sender equality predicate.
GraphQL Account/Domain Schema
apps/ensapi/src/omnigraph-api/schema/account.ts, apps/ensapi/src/omnigraph-api/schema/domain.ts
Updates Account.events resolver to filter by HCA-aware sender instead of tx.from, and clarifies Domain.owner documentation to distinguish ENSv1 vs. ENSv2 ownership semantics.
GraphQL Permission Schema
apps/ensapi/src/omnigraph-api/schema/permissions.ts, apps/ensapi/src/omnigraph-api/schema/registry-permissions-user.ts, apps/ensapi/src/omnigraph-api/schema/resolver-permissions-user.ts
Updates field descriptions for PermissionsUser.user, RegistryPermissionsUser.user, and ResolverPermissionsUser.user to note HCA account address inclusion when applicable.
GraphQL Registration Schema
apps/ensapi/src/omnigraph-api/schema/registration.ts
Updates registrant and unregistrant field descriptions to clarify HCA-aware semantics and correspondence to HCA account address for ENSv2.
ENS Indexer Account/Event Helpers
apps/ensindexer/src/lib/ensv2/account-db-helpers.ts, apps/ensindexer/src/lib/ensv2/event-db-helpers.ts
Modifies ensureAccount to return the normalized account identifier or null, and extends ensureEvent with an optional sender parameter that overrides the default transaction sender when provided.
ENS Event Handlers
apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ENSv2Registry.ts, apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ETHRegistrar.ts
Updates handlers to derive account identifiers via ensureAccount and pass sender/registrant IDs to ensureEvent for proper HCA context; extends handler argument typings to include sender and operator fields.
Database Schema
packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts
Adds non-null events.sender column with bySender index, switches multiple address-typed columns (events.from/to/address, accounts.id, registrations.registrantId/unregistrantId, permissions*.address/user) from Address to NormalizedAddress, and updates schema comments to clarify HCA-aware distinctions.
Docker & Environment Config
docker/docker-compose.devnet.yml, docker/envs/.env.docker.devnet
Removes RPC_URL_1 and default version environment variables from Docker devnet config; adds LABEL_SET_VERSION: 0 and DB_SCHEMA_VERSION: 3 to service configurations.

Sequence Diagram

sequenceDiagram
    participant ENSv2Event as ENSv2 Event
    participant Handler as Event Handler
    participant AcctHelper as ensureAccount
    participant EventHelper as ensureEvent
    participant Database as Database
    participant GraphQLAPI as GraphQL API
    participant Client as Client

    ENSv2Event->>Handler: Event triggered (e.g., Transfer)
    Handler->>Handler: Extract HCA-aware sender<br/>(from event args or tx.from)
    Handler->>AcctHelper: ensureAccount(address)
    AcctHelper->>Database: INSERT account if needed
    AcctHelper-->>Handler: NormalizedAddress or null
    Handler->>EventHelper: ensureEvent(event, sender)
    EventHelper->>Database: INSERT event with sender override
    EventHelper-->>Handler: Confirmation
    Client->>GraphQLAPI: Query events (sender filter)
    GraphQLAPI->>Database: SELECT from events WHERE sender = ?
    Database-->>GraphQLAPI: Events matching HCA sender
    GraphQLAPI-->>Client: Return Event with sender field
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰✨ A sender emerges from the HCA glow,
No longer just tx.from to know—
Events now track their rightful source,
With filtering set on proper course.
Hopping through schemas, old and new,
The indexer dances, addresses true! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(ensv2): HCA-aware Event.sender + filter + docs' clearly and concisely summarizes the main changes: adding HCA-aware event sender support with filtering and documentation updates.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description is comprehensive and well-structured, covering all required template sections with substantial detail on motivation, changes, testing, and risk analysis.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/hca-aware-events

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
Review rate limit: 0/1 reviews remaining, refill in 55 minutes and 48 seconds.

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 29, 2026

Greptile Summary

This PR surfaces the pre-existing events.sender column through the full stack: schema docs, a new sender filter on EventsWhereInput, and a behavior change on Account.events (now filters by HCA-aware sender instead of tx.from). ENSv2 handlers are updated to pass the correct HCA-candidate argument (registrant, unregistrant, sender, or ERC-1155 operator) to ensureEvent, with an explicit fallback to tx.from where no actor arg exists. The new NOT NULL column and bySender index require a full reindex on existing deployments.

Confidence Score: 5/5

Safe to merge; only P2 style findings, no logic or security issues.

All handler call sites pass the right HCA-candidate arg, the ensureAccount return-value reuse is correct and backward-compatible, and the sender ?? tx.from fallback is sound. The only finding is a P2 doc description that's misleading on concrete types due to Pothos interface inheritance.

No files require special attention.

Important Files Changed

Filename Overview
packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts Adds events.sender NOT NULL column + bySender index; replaces Address with NormalizedAddress across multiple columns; adds HCA-aware doc comments throughout. Logic and types look correct.
apps/ensindexer/src/lib/ensv2/event-db-helpers.ts Accepts optional sender override; uses sender ?? event.transaction.from fallback. Plumbing is correct.
apps/ensindexer/src/lib/ensv2/account-db-helpers.ts ensureAccount now returns `NormalizedAddress
apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ENSv2Registry.ts All updated handlers pass the right HCA-candidate arg: registrant for LabelRegistered/Reserved, unregistrant for LabelUnregistered, sender for ExpiryUpdated/SubregistryUpdated, operator for TransferSingle/Batch. SubregistryUpdated's TypeScript type was extended to include sender.
apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ETHRegistrar.ts NameRegistered handler now passes registrantId (from ensureAccount) to both the registration update and ensureEvent. Removes the inline interpretAddress call by reusing ensureAccount's return value.
apps/ensapi/src/omnigraph-api/schema/account.ts Semantics flip: Account.events now resolves with sender = parent.id instead of from = parent.id. Breaking change for callers relying on old EOA-based filtering, but intentional and documented.
apps/ensapi/src/omnigraph-api/lib/find-events/find-events-resolver.ts Adds sender to EventsWhere interface and eventsWhereConditions; straightforward eq filter mirroring the existing from filter.
apps/ensapi/src/omnigraph-api/schema/event.ts Exposes Event.sender field; adds sender filter to EventsWhereInput; updates AccountEventsWhereInput comment to say sender is implied. All correct.
apps/ensapi/src/omnigraph-api/schema/account.integration.test.ts Test updated to check event.sender instead of event.from for DEVNET_DEPLOYER events — correct given the semantics change.
packages/ensnode-sdk/src/shared/interpretation/interpret-address.ts Type narrowed from Address to NormalizedAddress with explicit return type annotation. Behavior unchanged.
apps/ensapi/src/lib/resolution/execute-operations.ts Wraps the raw interfaceImplementer result in toNormalizedAddress before passing to interpretAddress, satisfying the tightened NormalizedAddress type requirement.

Sequence Diagram

sequenceDiagram
    participant Chain as On-Chain Event
    participant Handler as ENSv2 Handler
    participant EA as ensureAccount()
    participant EE as ensureEvent()
    participant DB as events table

    Chain->>Handler: e.g. LabelRegistered(sender, ...)
    Handler->>EA: ensureAccount(context, sender)
    EA-->>Handler: senderId (NormalizedAddress | null)
    Handler->>EE: ensureEvent(context, event, senderId)
    EE->>EE: sender = senderId ?? tx.from
    EE->>DB: INSERT events SET sender=...
    DB-->>EE: eventId
    EE-->>Handler: eventId

    note over DB: bySender index on events.sender

    participant API as GraphQL API
    participant Resolver as eventsWhereConditions()

    API->>Resolver: EventsWhereInput { sender: "0x..." }
    Resolver->>DB: WHERE events.sender = ?
    DB-->>API: matching events

    note over API: Account.events uses sender=parent.id (HCA-aware)
Loading

Reviews (6): Last reviewed commit: "fix: address Copilot/Vercel review notes..." | Re-trigger Greptile

Comment thread apps/ensapi/src/omnigraph-api/schema/permissions.ts Outdated
# Conflicts:
#	docker/docker-compose.devnet.yml
#	docker/envs/.env.docker.devnet
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/ensindexer/src/lib/ensv2/event-db-helpers.ts (1)

23-27: 🛠️ Refactor suggestion | 🟠 Major

Remove redundant @returns JSDoc line.

Line 26 restates the summary and should be dropped for consistency.

Suggested cleanup
 /**
  * Ensures that an Event entity exists for the given `context` and `event`, returning the Event's
  * unique id.
- *
- * `@returns` event.id
  */

As per coding guidelines: **/*.{ts,tsx}: Do not add JSDoc @returns tags that merely restate the method summary; remove such redundancy during PR review.

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

In `@apps/ensindexer/src/lib/ensv2/event-db-helpers.ts` around lines 23 - 27,
Remove the redundant JSDoc "@returns event.id" line from the comment block that
begins "Ensures that an Event entity exists for the given `context` and `event`"
(the JSDoc describing the function that returns the Event's unique id); keep the
summary and any meaningful tags but delete the `@returns` tag that merely restates
the summary so the JSDoc follows the project's guideline against redundant
return tags.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/ensindexer/src/lib/ensv2/event-db-helpers.ts`:
- Around line 23-27: Remove the redundant JSDoc "@returns event.id" line from
the comment block that begins "Ensures that an Event entity exists for the given
`context` and `event`" (the JSDoc describing the function that returns the
Event's unique id); keep the summary and any meaningful tags but delete the
`@returns` tag that merely restates the summary so the JSDoc follows the project's
guideline against redundant return tags.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5b0814f5-f20c-4286-99b8-9816b57990a1

📥 Commits

Reviewing files that changed from the base of the PR and between a51990a and ca35d93.

📒 Files selected for processing (16)
  • .changeset/hca-aware-events.md
  • apps/ensapi/src/omnigraph-api/lib/find-events/find-events-resolver.ts
  • apps/ensapi/src/omnigraph-api/schema/account.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.ts
  • apps/ensapi/src/omnigraph-api/schema/event.ts
  • apps/ensapi/src/omnigraph-api/schema/permissions.ts
  • apps/ensapi/src/omnigraph-api/schema/registration.ts
  • apps/ensapi/src/omnigraph-api/schema/registry-permissions-user.ts
  • apps/ensapi/src/omnigraph-api/schema/resolver-permissions-user.ts
  • apps/ensindexer/src/lib/ensv2/account-db-helpers.ts
  • apps/ensindexer/src/lib/ensv2/event-db-helpers.ts
  • apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ENSv2Registry.ts
  • apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ETHRegistrar.ts
  • docker/docker-compose.devnet.yml
  • docker/envs/.env.docker.devnet
  • packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts
💤 Files with no reviewable changes (1)
  • docker/envs/.env.docker.devnet

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

This PR makes ENSv2 event indexing and Omnigraph querying HCA-aware by introducing/using an events.sender actor field (distinct from tx.from) and switching Account.events to filter by that actor.

Changes:

  • Adds an events.sender column + index and documents HCA-aware semantics across ENSv2 schema fields.
  • Plumbs “sender override” through ENSv2 indexer handlers so Event.sender reflects event-level actor args when available.
  • Exposes Event.sender + a sender filter in Omnigraph, and flips Account.events to filter by sender instead of from.

Reviewed changes

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

Show a summary per file
File Description
packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts Adds events.sender + bySender index; updates address typing/docs to emphasize HCA-aware vs tx.from.
apps/ensindexer/src/lib/ensv2/event-db-helpers.ts Extends ensureEvent to persist the new sender field with override/fallback behavior.
apps/ensindexer/src/lib/ensv2/account-db-helpers.ts Updates ensureAccount to return the inserted account id for reuse by handlers.
apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ETHRegistrar.ts Passes registrant-derived sender override into ensureEvent for NameRegistered.
apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ENSv2Registry.ts Passes registrant/unregistrant/sender/operator overrides into ensureEvent for key ENSv2 events.
apps/ensapi/src/omnigraph-api/schema/event.ts Adds Event.sender, updates docs for Event.from, adds sender filter, updates AccountEventsWhereInput semantics.
apps/ensapi/src/omnigraph-api/lib/find-events/find-events-resolver.ts Implements SQL condition for where.sender.
apps/ensapi/src/omnigraph-api/schema/account.ts Flips Account.events resolver to filter by sender instead of from.
apps/ensapi/src/omnigraph-api/schema/domain.ts Updates Domain.owner description for ENSv1 vs ENSv2 HCA semantics.
apps/ensapi/src/omnigraph-api/schema/registration.ts Documents ENSv2 registrant/unregistrant HCA-aware semantics.
apps/ensapi/src/omnigraph-api/schema/permissions.ts Documents PermissionsUser.user as HCA-aware when applicable.
apps/ensapi/src/omnigraph-api/schema/registry-permissions-user.ts Updates user field docs for HCA awareness.
apps/ensapi/src/omnigraph-api/schema/resolver-permissions-user.ts Updates user field docs for HCA awareness.
docker/envs/.env.docker.devnet Removes label-set/schema version env vars from this env file.
docker/docker-compose.devnet.yml Moves label-set/schema version configuration into compose env blocks; removes RPC_URL_1 for devnet services.
.changeset/hca-aware-events.md Changeset describing new Omnigraph Event.sender and Account.events behavior change.
Comments suppressed due to low confidence (1)

apps/ensindexer/src/lib/ensv2/event-db-helpers.ts:66

  • ensureEvent now persists event.sender (and already persisted from/to/address) into columns typed/documented as NormalizedAddress, but the values are written directly from event.transaction.from / event.transaction.to / event.log.address without any normalization or assertion. If Ponder ever provides checksummed/mixed-case addresses here, Postgres equality comparisons will become case-sensitive mismatches (notably GraphQL’s Address scalar parses inputs to lowercase), and sender/from/address filters will silently return no results.

Recommend normalizing (or at least asserting normalization) for sender, from, to, and address at the write boundary in ensureEvent to guarantee the NormalizedAddress invariant.

    .values({
      id: event.id,

      // sender override if provided, otherwise transaction.from
      sender: sender ?? event.transaction.from,

      // chain
      chainId: context.chain.id,

      // block
      blockNumber: event.block.number,
      blockHash: event.block.hash,
      timestamp: event.block.timestamp,

      // transaction
      transactionHash: event.transaction.hash,
      transactionIndex: event.transaction.transactionIndex,
      from: event.transaction.from,
      to: event.transaction.to,

      // log
      address: event.log.address,
      logIndex: event.log.logIndex,

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

Comment thread apps/ensindexer/src/lib/ensv2/account-db-helpers.ts
…dAddress

Update HCA-aware Address descriptions across schema and GraphQL to a
unified pattern: "the HCA account address if used, otherwise
Transaction.from". Tighten interpretAddress and ensureAccount inputs
to NormalizedAddress. Regenerate omnigraph schema.graphql and
introspection.ts.

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 16 out of 18 changed files in this pull request and generated 8 comments.

Comments suppressed due to low confidence (2)

apps/ensapi/src/omnigraph-api/schema/permissions.ts:268

  • PermissionsUser.user description says it falls back to Transaction.from, but this field is the account being granted roles (from the permissions event args) and is not tied to the tx submitter. This wording will mislead API consumers when tx.from is a relayer or when roles are granted to an address other than the submitter. Suggest rewording to describe it as the role grantee address (HCA address if applicable) without referencing Transaction.from.
    user: t.field({
      description:
        "The User for whom these Roles are granted: the HCA account address if used, otherwise Transaction.from.",
      type: AccountRef,
      nullable: false,
      resolve: (parent) => parent.user,
    }),

apps/ensapi/src/omnigraph-api/schema/event.ts:224

  • AccountEventsWhereInput is documented as "like EventsWhereInput but without sender", but it currently also omits the from filter. With Account.events now implying sender, it may be useful (and less surprising) to allow from in AccountEventsWhereInput so callers can still filter by tx.from within an account’s sender-scoped events; otherwise, consider updating the docstring/description to explicitly state which filters are available.
/**
 * Shared filter for events connections. Used by Domain.events, Resolver.events, Permissions.events,
 * and Account.events (which excludes `sender` since it's implied).
 */
export const EventsWhereInput = builder.inputType("EventsWhereInput", {
  description: "Filter conditions for an events connection.",
  fields: (t) => ({
    selector_in: t.field({
      type: ["Hex"],
      description:
        "Filter to events whose selector (event signature) is one of the provided values.",
    }),
    timestamp_gte: t.field({
      type: "BigInt",
      description: "Filter to events at or after this UnixTimestamp.",
    }),
    timestamp_lte: t.field({
      type: "BigInt",
      description: "Filter to events at or before this UnixTimestamp.",
    }),
    from: t.field({
      type: "Address",
      description:
        "Filter to events whose `tx.from` matches. Not HCA-aware — use `sender` to filter by the HCA account address.",
    }),
    sender: t.field({
      type: "Address",
      description:
        "Filter to events whose `sender` matches: the HCA account address if used, otherwise Transaction.from.",
    }),
  }),
});

/**
 * Like EventsWhereInput but without `sender` (used where `sender` is implied, e.g. Account.events).
 */
export const AccountEventsWhereInput = builder.inputType("AccountEventsWhereInput", {
  description: "Filter conditions for Account.events (where `sender` is implied by the Account).",
  fields: (t) => ({
    selector_in: t.field({
      type: ["Hex"],
      description:
        "Filter to events whose selector (event signature) is one of the provided values.",
    }),
    timestamp_gte: t.field({
      type: "BigInt",
      description: "Filter to events at or after this UnixTimestamp.",
    }),
    timestamp_lte: t.field({
      type: "BigInt",
      description: "Filter to events at or before this UnixTimestamp.",
    }),
  }),

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

Comment thread apps/ensapi/src/omnigraph-api/schema/account.ts
Comment thread apps/ensapi/src/omnigraph-api/schema/domain.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/registry-permissions-user.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/resolver-permissions-user.ts Outdated
Comment thread packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts Outdated
Comment thread packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/registration.ts
Comment thread packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/account.ts
Comment thread apps/ensindexer/src/plugins/ensv2/handlers/ensv2/ENSv2Registry.ts
@shrugs
Copy link
Copy Markdown
Member Author

shrugs commented Apr 29, 2026

@greptile review

Reword HCA-aware Address descriptions for fields that aren't actually
populated from tx.from (Domain.owner, Registration.registrant,
Registration.unregistrant, PermissionsUser.user). These read from
protocol event args (TransferSingle.to, LabelRegistered.sender,
EACRolesChanged.account), not Transaction.from. Keep "otherwise
Transaction.from" only on Event.sender and the sender filter, where it
is literally accurate.

Update Account.events integration test to assert event.sender (now
HCA-aware) instead of event.from. Add sender to the shared EventFragment
and EventResult type.

Regenerate omnigraph schema.graphql.

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

shrugs commented Apr 29, 2026

@greptile review

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 Nice 🚀 1 small comment please merge when ready 👍

Comment thread packages/ensdb-sdk/src/ensindexer-abstract/ensv2.schema.ts
- events: add sender column row, update from description to flag never
  HCA-aware, add sender to indexes list
- permissions_user_events: document join table (was missing from initial
  ENSDb docs in #2007)
- domains.ownerId: polymorphic ENSv1 effective-owner / ENSv2 on-chain
  owner (HCA-aware) wording
- registrations.registrantId / unregistrantId: ENSv2 HCA-aware note
- permissions_users.user: HCA-aware grantee description

Per #2014 (comment) review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 29, 2026 22:49
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io April 29, 2026 22:49 Inactive
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io April 29, 2026 22:49 Inactive
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 19 out of 21 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/omnigraph-api/schema/event.ts
Per Copilot review: the description says "without sender" but the input
omitted both sender and from. Add a from filter so callers can narrow
by tx.from while sender is implied by the Account.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

Omnigraph: Smart Account Handling

3 participants