Skip to main content

Persist voided stake — sizeVoided (provider ccy) + voidedStake (user ccy)

To represent partial matched-stake voids losslessly (Betfair reduction factors on non-runners and VAR reversals can void part of a matched order while the rest settles win/lose — see the runner- removal example, exchange-stream-api.md:1154), we add two money columns to Order, mirroring the existing lapsed/cancelled pair:

  • sizeVoided Decimal? @map("size_voided") @db.Decimal(18, 2) — provider-account-currency voided amount, peer of sizeMatched / sizeLapsed / sizeCancelled. Populated from Betfair sv / betStatus = VOIDED; for Bifrost, set to the full matched stake on a VOID outcome, else 0.
  • voidedStake Decimal? @map("voided_stake") @db.Decimal(18, 4) — user-currency equivalent, ratio-derived exactly like cancelledStake / lapsedStake.

Why this does not contradict ADR-0001

ADR-0001's "no new column" was about the display status (a derived label). sizeVoided / voidedStake are settlement/ledger money data — the same category as sizeMatched/sizeLapsed, consumed by the settlement-outcome function (function 2), not by the display-status derivation. The display status stays derived; only the money breakdown gains a column.

Financial-security constraints (non-negotiable)

  • Both columns nullable; never defaulted or coerced (?? 0 / || 0 banned — financial-security §1). A missing provider void amount is null, not zero.
  • Decimal.js for every derivation; convert Prisma Decimals via new Decimal(v.toString()).
  • voidedStake is derived by the same ratio used for cancelledStake/lapsedStake — one shared helper, not a re-implemented conversion.
  • Reconciliation invariant (ADR-0003) now formally includes voided: matched + remaining + lapsed + cancelled + voided == requested; non-reconciling → throw FINANCIAL_INTEGRITY.