fix(log): match failed Scrypt deposits in financial log receiver set#3775
fix(log): match failed Scrypt deposits in financial log receiver set#3775TaprootFreak wants to merge 1 commit into
Conversation
The Scrypt DEPOSIT receiver filter narrowed to status === 'ok', which left bank_tx unmatched when Scrypt marked a deposit as failed even though the funds actually arrived (Scrypt FIX balance updated). The unmatched bank_tx kept counting in pending.toScrypt while the same amount also showed up in liquidity from the FIX stream — observed as a ~100k CHF overstatement in totalBalanceChf. Align the Scrypt filter with the existing Kraken filter (status !== 'pending', see PR #2929) and extract it into a public predicate so it is directly testable.
|
Closing in favor of a cleaner approach. WhyThis PR loosened the financial-log receiver filter ( The real cause is one layer up: The replacement PR removes that synthesis entirely (Scrypt is excluded from the cleanup, status comes solely from Scrypt-API via → Closing without merge. Branch left intact in case the discussion needs to be reopened. |
|
Superseded by #3778 which fixes the root cause: the 24h stale deposit cleanup was racing against Scrypt's reconciliation window (can take >24h). Scrypt deposits now get 7 days before cleanup, allowing the sync to pick up the completed version. |
Problem
Production FinancialDataLog has shown
totalBalanceChf~100k CHF too high since 2026-05-27 08:46 UTC. Root cause traced to the Scrypt DEPOSIT receiver-filter inlog-job.service.ts:Scrypt marks a deposit
failedwhen its initial reconciliation attempt does not complete, even if the funds later arrive on the account (manual reconciliation at Scrypt, FIX BALANCE stream updates without flipping the deposit row back took). Withstatus === 'ok', thosefailedrows are excluded from the receiver set, the matchingbank_tx(e.g.OlkyPay → ScryptSEPA) stays unmatched, and is kept inpending.toScrypt— while the same amount is already reflected inliquidityviaAsset.balance.amount.Concrete trace (observed)
LU11606…DFX Payout 81090DEPOSIT-81090)LU11606…DFX Payout 81111DEPOSIT-81111)LU11606…DFX Payout 81147DEPOSIT-81147)The first two never match →
pending.toScrypt = 110'013.47 EUReven though Scrypt's FIX stream reports the corresponding 110k EUR as live balance. At 0.9152 CHF/EUR that is 100'680.78 CHF doubled, matching the observed +100'900.59 CHF jump (residual ~220 CHF explained by USDT price drift across the comparison window).Fix
Change Scrypt DEPOSIT receiver filter from
status === 'ok'tostatus !== 'pending'— accept bothokandfailed. This mirrors the existing Kraken DEPOSIT filters (Lines 372 and 384), which were historically tightened to the same predicate in PR fix: exclude pending deposits from Kraken balance calculation #2929 / commit cd8afc0. After the change, all four cross-system DEPOSIT receiver filters use the same predicate.Extract the predicate into a public method
isMatchableScryptDeposit(currency)so the production code path is directly testable.Add regression tests pinning the predicate semantics (failed → matchable, pending → excluded, for both EUR and CHF).
Trade-off
A failed deposit where the funds did not arrive (true reject) will now briefly disappear from
pending.toScryptuntil the correspondingbank_tx_returnis recorded —pendingBankTxReturnthen accounts for it viaminusBalance.pending.bankTxReturn. Net: a short-lived under-count instead of a persistent over-count, which is preferable for the safety-mode threshold.Risk
status !== 'failed', Lines 429/437) are intentionally not changed — different semantics (a failed withdrawal never left the account).status !== 'pending'— untouched.Test plan
npm run lintnpm run format:checknpx tsc --noEmitnpx jest --testPathPattern="log-job.service.spec"— 20/20 (17 existing + 3 new regression tests)pending.toScryptforassetId=401no longer contains funds already reflected inliquiditytotalBalanceChfshould drop by ~100k CHF on the next cron run