fix(exchange-tx): exclude Scrypt deposits from stale-pending cleanup#3779
Closed
TaprootFreak wants to merge 1 commit into
Closed
fix(exchange-tx): exclude Scrypt deposits from stale-pending cleanup#3779TaprootFreak wants to merge 1 commit into
TaprootFreak wants to merge 1 commit into
Conversation
The hourly cleanupStalePendingDeposits cron flips every DEPOSIT row that stays pending for more than a day to 'failed' — exchange-agnostically. For Scrypt that synthesises a status our own DB has no authority over: Scrypt SEPA inbound funds historically can arrive days after the exchange_tx is created (no chargebacks observed), and any status change must come from Scrypt itself via syncExchanges. A wrong 'failed' here left the matching OlkyPay/Yapeal bank_tx unmatched in pending.toScrypt while the actual funds were already reflected in Asset.balance.amount via the Scrypt FIX stream — observed as the ~100k CHF overstatement in totalBalanceChf on 2026-05-27. Add `exchange: Not(ExchangeName.SCRYPT)` to the find query. Other exchanges (Kraken, Binance, MEXC, XT) keep the existing 'failed'-after- 24h default.
Member
|
Superseded by #3778 — the root cause was that Scrypt deposit requests were sent at bank transmission time, before money arrived. Moving the notification to after bank_tx confirmation eliminates the pending window entirely, making the cleanup cron unnecessary. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
ExchangeTxService.cleanupStalePendingDepositsis an hourly cron that flips every DEPOSIT withstatus='pending'older than one day to'failed'— exchange-agnostically. For Scrypt this synthesises a status our own DB has no authority over.Scrypt deposit semantics:
status='pending'when the SEPA inbound is announced.exchange_tx#138339was created 22.05 07:49, our cron flipped it to'failed'on 23.05 08:00, but the corresponding 30'006.71 EUR only landed inAsset.balance.amount(Scrypt FIX-stream BALANCE) on 27.05 08:46).bank_tx_returnrow that points at a Scrypt-typed bank_tx.syncExchanges(exchange-tx.service.ts:63). When Scrypt confirms receipt, it flips its own row to'ok'; ourObject.assign(entity, transaction)mirrors that on the next sync tick.Our synthetic
'failed'was therefore breaking the financial-log matching: the OlkyPay bank_tx (200493 / 200504, refs81090/81111) could not pair with their failed Scrypt counterparts (138339 / 138379), so 110'013.47 EUR kept counting inpending.toScrypteven though the FIX stream already reflected the funds inAsset.balance.amount— directly responsible for the ~100k CHF overstatement intotalBalanceChfsince 2026-05-27 08:46 UTC.Fix
Add
exchange: Not(ExchangeName.SCRYPT)to the find query so the cleanup leaves Scrypt rows alone:That is the entire production change. Other exchanges (Kraken, Binance, MEXC, XT) keep their existing
'failed'-after-24h default, which is appropriate for them — they do produce real rejects.Why this is the right place to fix it
Two earlier draft PRs explored aggregator-side workarounds (#3775 loosened the financial-log receiver filter; #3777 flipped stale Scrypt rows to
'ok'). Both were closed because they synthesised status from inside our API instead of letting Scrypt own its own truth.After this PR:
status='pending'means "Scrypt announced the inbound, money not confirmed received yet" — the matching bank_tx correctly stays inpending.toScrypt.status='ok'means "Scrypt confirmed receipt" — the bank_tx correctly leavespending.toScrypt.status='failed'means "Scrypt actively rejected" (in practice never observed, but legitimate) — the bank_tx correctly stays inpending.toScrypt(and abank_tx_returnwould eventually neutralise it).In all three cases the existing financial-log filter
status === 'ok'(log-job.service.ts:393, 423) is semantically correct — no aggregator-side change needed.Risk
'failed'Scrypt rows (#138339, #138379, plus ~10 older ones from May) will NOT auto-correct:syncExchangesonly re-fetches rows whose anchor isstatus='pending'(getSyncSinceDate, L209-L223). A one-time backfill is needed for those — out of scope for this PR; tracked separately.Test plan
npm run lintnpm run format:checknpx tsc --noEmitnpx jest --testPathPattern="exchange-tx.service.spec"— 4/4 (new spec file: find-query excludes Scrypt; non-Scrypt set to failed; early-return on empty;should be defined)pendingwhile Kraken/Binance go tofailedfailedrows (#138339, #138379, …) need a one-time backfill — separate operation