Skip to content

[indexer]: index the gateway's OrderCancelled event - #1185

Open
Wizdave97 wants to merge 3 commits into
mainfrom
feat/indexer-order-cancelled
Open

[indexer]: index the gateway's OrderCancelled event#1185
Wizdave97 wants to merge 3 commits into
mainfrom
feat/indexer-order-cancelled

Conversation

@Wizdave97

@Wizdave97 Wizdave97 commented Aug 28, 2026

Copy link
Copy Markdown
Member

Indexes Intent Gateway OrderCancelled(bytes32 indexed commitment, address canceller) events and exposes cancellation initiation through the order's cancellation relation and status metadata. Cancellation never writes IOrderV3.status: a locally guarded full-row save can still overwrite a refund committed by an independent chain indexer with a different cached snapshot.

Behavior

  • Adds IOrderV3Cancellation, the IOrderV3.cancellations relation, datasource wiring, and the event handler. Event records retain the initiating chain, caller, timestamp, block number, and transaction hash. The caller can differ from the order creator on the permissionless destination route.
  • Appends CANCELLED after existing enum values so the schema migration remains additive. The current gateway ABI already contains the event; it retains exactly one matching declaration.
  • Writes CANCELLED status metadata for existing orders, including already-settled orders. Missing parents use the established pending-metadata workflow. Cancellation alone leaves the parent status unchanged; parent filters for CANCELLED will not identify cancellation initiation.
  • Preserves EscrowRefunded as the REFUNDED transition. Existing lifecycle writers, pending-status flushing, and their accounting side effects remain unchanged.
  • Adds SDK OrderStatus.CANCELLED. The status stream keeps polling after cancellation, gives existing terminal metadata precedence over a later cancellation entry, and avoids repeated emission of the same status.

Validation

  • Eight indexer service tests pass: metadata-only writes, all existing terminal states, cancellation before placement, pending-metadata materialization, duplicate/repeated logs, and same-chain cancellation followed by refund.
  • Six SDK stream tests pass: cancellation stays intermediate, repeated polling emits it once, and a refund wins over cancellation with later or equal timestamps.
  • A checked-in runtime regression script uses two independent SubQuery caches and Postgres connections. It reproduces the stale whole-row regression, verifies the actual service preserves REFUNDED in both cache flush orders, and checks the missing-parent path with multichain timestamp history. Reproduction commands are in the metadata-only decision document.
  • Indexer ENV=mainnet npm run build:release and SDK browser/node/type builds pass.
  • The indexer cancellation ABI declaration matches the compiled current IntentGatewayV2 ABI.
  • The prior refresh validated current-main-to-PR additive schema migration against SubQuery/Postgres, including preservation of an existing order and an unchanged restart. This follow-up does not change the schema.

Known pre-existing SDK limitation

The order query requests orders, while its parser reads orderPlaceds; that legacy query shape also differs from IOrderV3. The focused stream tests supply the parser's expected response and do not establish live GraphQL compatibility. Migrating that query is separate from this cancellation persistence fix.

`09888bd1` added `OrderCancelled(bytes32 indexed commitment, address canceller)` to
IntentGatewayV2. It was the only contract event with no counterpart here — the ABI already
carried the other reshaped events from this cycle (`OrderFilled`/`PartialFill`/
`EscrowReleased`/`EscrowRefunded` with their token arrays, `DeploymentAdded`,
`DestinationProtocolFeeUpdated`), so cancellation was the whole gap.

Adds a `CANCELLED` status, an `IOrderV3Cancellation` entity, a handler, and the datasource
wiring. `canceller` is stored separately from the order's `user` because the
destination-side cancel route is permissionless once the order has expired, so the two are
not the same account in general.

`recordOrderCancellation` advances the status only from `PLACED`. `OrderCancelled` marks
the initiation of a cancellation, not its completion — `EscrowRefunded` stays terminal and
still owns `REFUNDED`. Since `updateOrderStatus` assigns without comparing against the
current value, and a cross-chain cancel is initiated on the destination chain while its
refund lands on the source chain via a separate datasource with no ordering guarantee
between them, an unguarded write would let a late-indexed cancellation move a settled order
back to `CANCELLED`. Guarding on `PLACED` makes it idempotent and order-independent.

The guard is local to the new method rather than a general never-regress rule in
`updateOrderStatus`: the broader change would alter every existing transition on a path
with no ordering test coverage, and deserves its own justification.

An order resting at `CANCELLED` is an expected steady state, not an indexing gap — the
source-side route re-emits on every call and only refunds when the GET response returns.
@royvardhan
royvardhan marked this pull request as ready for review September 12, 2026 08:25
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.

2 participants