Skip to content

fix(twap): alias executed-totals aggregates so additionalData stores all three fields - #122

Merged
yvesfracari merged 1 commit into
mainfrom
fix/twap-additional-data-aliases
Jul 23, 2026
Merged

fix(twap): alias executed-totals aggregates so additionalData stores all three fields#122
yvesfracari merged 1 commit into
mainfrom
fix/twap-additional-data-aliases

Conversation

@yvesfracari

Copy link
Copy Markdown
Contributor

Problem

TWAP parents' additionalData on the deployed indexer is wrong: 9,830 of 9,834 TWAP generators store a one-key JSON like {"executedSellAmount":"0"}executedBuyAmount and executedFee are missing, and the value stored under executedSellAmount is actually the children's fee sum (verified against the production DB: the stored value matches SUM(executed_fee) exactly on every non-zero row).

Root cause

The aggregate select in refreshTwapExecutedTotals used unaliased raw sql fragments:

executedSellAmount: sql`coalesce(sum(...), 0)::text`,
executedBuyAmount:  sql`coalesce(sum(...), 0)::text`,
executedFee:        sql`coalesce(sum(...), 0)::text`,

drizzle does not auto-alias raw fragments, so Postgres names all three result columns coalesce. Ponder's context.db.sql proxy (ponder 0.16, indexing-store/index.js) executes raw queries in object row mode and feeds drizzle's positional mapper via rows.map((row) => Object.values(row)) — the duplicate keys collapse into one, leaving [generatorId, feeSum]. Positionally that assigns the fee sum to executedSellAmount and leaves the other two undefined, which JSON.stringify then drops.

This is invisible to the unit tests (they mock the DB) and to vanilla drizzle drivers (node-postgres/pglite use array row mode) — I reproduced it only through Ponder's wrapper, which is why a warning comment now sits on the query.

Fix

Give each aggregate a unique .as() alias so the column names stay distinct and the positional mapping is stable.

No data repair is needed: the deploy flow drops the app schema and reindexes, and every reindex recomputes additionalData from the discrete orders.

Verification

  • Reproduced the buggy vs fixed shape against a real Postgres (PGlite) and confirmed the collapse mechanism in Ponder's dist source.
  • pnpm typecheck, pnpm lint, pnpm test green.

…res all three fields

Ponder's context.db.sql maps raw-SQL result rows positionally via
Object.values(row). The three unaliased coalesce(sum(...)) columns all
came back named "coalesce", collapsed into one key in the row object,
and the values shifted: the executedFee sum was stored under
executedSellAmount and the other two fields were dropped from the JSON
entirely (9,830 of 9,834 TWAP parents on the deployed DB show the
one-key shape, and the stored value matches the children's fee sum
exactly).

Unique .as() aliases keep the column names distinct so the positional
mapping is stable. Unit tests can't catch this (they mock the DB and
vanilla drizzle drivers use array row mode, which is immune), hence the
warning comment.
@yvesfracari

Copy link
Copy Markdown
Contributor Author

Smoke test — indexer run from a 1-day-old start block

Ran pnpm dev on the full stack (#122 + #123 + #124) with temporary start blocks of mainnet 25588637 / gnosis 47333828 (~24h ago), fresh cow_cache, isolated DB schema. Historical sync completed with zero error log lines; 16 ConditionalOrderCreated events, 9 TWAP generators (8 mainnet, 1 gnosis).

Every TWAP parent's stored additionalData was compared against sums recomputed from its discrete_order children:

chain children fulfilled sell_ok buy_ok fee_ok fulfilled w/ null fee
1 (×8 generators) 1–64 1–64 ✅ all ✅ all ✅ all 0
100 (×1 generator) 2 2 0

All 9 parents carry the full three-key JSON (before the fix, production had 9,830 one-key rows), fee totals are non-zero wherever children were fulfilled, and executed_* columns are numeric in Postgres.

Sample GraphQL output (same query shape as the original bug report):

{
  "executedFee": "3458674081352794806",
  "executedBuyAmount": "334666289225195989846",
  "executedSellAmount": "1652961917640625000000",
  "status": "fulfilled",
  "conditionalOrderGenerator": {
    "orderType": "TWAP",
    "additionalData": {
      "executedSellAmount": "105789562729000000000000",
      "executedBuyAmount": "21397996081206960401538",
      "executedFee": "354479378307462150268"
    }
  }
}

The start-block changes were test-only and are not part of any PR.

@yvesfracari
yvesfracari merged commit f8b6f1d into main Jul 23, 2026
2 checks passed
@yvesfracari
yvesfracari deleted the fix/twap-additional-data-aliases branch July 23, 2026 14:45
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