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 ofsizeMatched/sizeLapsed/sizeCancelled. Populated from Betfairsv/betStatus = VOIDED; for Bifrost, set to the full matched stake on aVOIDoutcome, else 0.voidedStake Decimal? @map("voided_stake") @db.Decimal(18, 4)— user-currency equivalent, ratio-derived exactly likecancelledStake/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/|| 0banned — 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()). voidedStakeis derived by the same ratio used forcancelledStake/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 → throwFINANCIAL_INTEGRITY.