Skip to content

Fix: balance log race condition (negative totalBalance)#3345

Merged
TaprootFreak merged 2 commits intodevelopfrom
fix/balance-log-race-condition
Mar 4, 2026
Merged

Fix: balance log race condition (negative totalBalance)#3345
TaprootFreak merged 2 commits intodevelopfrom
fix/balance-log-race-condition

Conversation

@TaprootFreak
Copy link
Collaborator

@TaprootFreak TaprootFreak commented Mar 4, 2026

Summary

Filter payout-sent BuyCrypto from pending obligations in the balance log to fix race condition causing negative totalBalance.

Problem

Separate cron jobs update wallet balance, BuyCrypto completion, and payout status at different intervals. When a payout is sent on-chain, the wallet balance drops immediately, but BuyCrypto.isComplete remains false until the next completion cycle — causing double-counting.

Observed today (2026-03-04):

  • PayoutOrder 98220 for BuyCrypto 115668 (1.25 BTC, ~69k CHF) created at 09:44
  • Wallet balance dropped immediately (BTC sent on-chain)
  • BuyCrypto.isComplete stayed false until 10:06 (~22min gap)
  • During 09:46–10:06: 20+ consecutive null totalBalance entries
  • plusChf: 742k, minusChf: 790k-48k CHF negative

Fix

When a PayoutOrder is in PAYOUT_PENDING or COMPLETE status, the crypto has already left the wallet. The corresponding BuyCrypto is excluded from pendingBuyCrypto since the obligation is already reflected in the reduced wallet balance.

  • PayoutService.getRecentPayoutSentCorrelationIds() — returns correlation IDs of payout-sent orders (scoped to last hour for performance; race condition window is ~20min max)
  • LogJobService.getAssetLog() — filters pendingBuyCrypto before calculating minusBalance

With fix applied: minusChf drops from 790k to ~721k → totalChf: +21k CHF (positive)

Edge cases

  • Network start fee PayoutOrders ({id}-network-start-fee) don't match BuyCrypto IDs → correctly not filtered
  • PAYOUT_DESIGNATED: tx not yet sent, wallet balance unaffected → correctly not filtered
  • PAYOUT_UNCERTAIN: conservative to keep in pending → correctly not filtered

Test plan

  • npm run build passes
  • npm run lint passes
  • Prettier check passes
  • Verify no more null/negative totalBalance entries after deploy

Exclude BuyCrypto entries from pending obligations when their
PayoutOrder is already in PAYOUT_PENDING or COMPLETE status,
preventing double-counting that caused negative totalBalance.
Rename to getRecentPayoutSentCorrelationIds and add MoreThan(1h)
filter. The race condition window is ~20min max, so 1h is sufficient.
@TaprootFreak TaprootFreak marked this pull request as ready for review March 4, 2026 10:45
@TaprootFreak TaprootFreak merged commit c73978b into develop Mar 4, 2026
8 checks passed
@TaprootFreak TaprootFreak deleted the fix/balance-log-race-condition branch March 4, 2026 12:52
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