From 1d59eb478f0d2b76c18502adfabbeaf66cedf582 Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Tue, 3 Mar 2026 10:28:48 +0100 Subject: [PATCH 1/2] Fix negative plus balance from unfiltered Scrypt pending amounts (#3330) Problem: - fromScryptUnfiltered and toScryptUnfiltered could be negative - These values were added to totalPlusPending without clamping - Result: totalPlus became negative, causing negative plusBalance for assets - Specifically affected Scrypt/EUR (Asset 401) with -201,499 EUR plusBalance Root Cause: - Filtered versions (fromScrypt, toScrypt) were clamped to 0 if negative - Unfiltered versions were NOT clamped, causing negative plus balances - When useUnfilteredTx=true, negative unfiltered values corrupted totalPlus Fix: - Changed fromScryptUnfiltered and toScryptUnfiltered from const to let - Added clamping logic to set negative unfiltered values to 0 - Log errors when unfiltered values are negative for debugging - Prevents negative plus balances while maintaining error visibility Impact: - Fixes critical bug where Scrypt assets could have negative plus balances - Prevents plusBalanceChf from being stored as NULL in financial logs - Maintains consistency with existing filtered value clamping logic --- .../supporting/log/log-job.service.ts | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/subdomains/supporting/log/log-job.service.ts b/src/subdomains/supporting/log/log-job.service.ts index 0ff2287301..b72cf809ae 100644 --- a/src/subdomains/supporting/log/log-job.service.ts +++ b/src/subdomains/supporting/log/log-job.service.ts @@ -716,11 +716,11 @@ export class LogJobService { let fromScrypt = pendingChfScryptBankPlusAmount + pendingEurScryptBankPlusAmount + pendingScryptBankMinusAmount; let toScrypt = pendingBankScryptPlusAmount + pendingChfBankScryptMinusAmount + pendingEurBankScryptMinusAmount; - const fromScryptUnfiltered = + let fromScryptUnfiltered = pendingChfScryptBankPlusAmountUnfiltered + pendingEurScryptBankPlusAmountUnfiltered + pendingScryptBankMinusAmountUnfiltered; - const toScryptUnfiltered = + let toScryptUnfiltered = pendingBankScryptPlusAmountUnfiltered + pendingChfBankScryptMinusAmountUnfiltered + pendingEurBankScryptMinusAmountUnfiltered; @@ -792,6 +792,23 @@ export class LogJobService { fromScrypt = 0; } + // Clamp unfiltered Scrypt values to prevent negative plus balances + if (fromScryptUnfiltered < 0) { + errors.push(`fromScryptUnfiltered < 0`); + this.logger.verbose( + `Error in financial log, fromScryptUnfiltered balance < 0 for asset: ${curr.id}, fromScryptUnfiltered: ${fromScryptUnfiltered}`, + ); + fromScryptUnfiltered = 0; + } + + if (toScryptUnfiltered < 0) { + errors.push(`toScryptUnfiltered < 0`); + this.logger.verbose( + `Error in financial log, toScryptUnfiltered balance < 0 for asset: ${curr.id}, toScryptUnfiltered: ${toScryptUnfiltered}`, + ); + toScryptUnfiltered = 0; + } + // total pending balance const totalPlusPending = cryptoInput + From 2bc3dccf1c5891ee1f9a293677929a5c7f2ca085 Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Tue, 3 Mar 2026 10:33:47 +0100 Subject: [PATCH 2/2] Improve fix: Clamp totalPlusPending instead of individual components (#3332) Previous Fix (PR #3330): - Clamped only fromScryptUnfiltered and toScryptUnfiltered individually - Left fromKrakenUnfiltered and toKrakenUnfiltered unclamped - Incomplete protection against negative plus balances This Fix: - Removed individual unfiltered component clamping - Added single clamp on totalPlusPending after calculation - Covers ALL negative sources: Kraken, Scrypt, and future exchanges - More robust and maintainable Rationale: - Simpler: One clamp instead of multiple - Complete: Catches negative values from any component - Better logging: Shows all component values when totalPlusPending is negative - Semantically correct: "Total pending plus balance cannot be negative" The filtered component clamps (fromKraken, toKraken, fromScrypt, toScrypt) remain in place for consistency and detailed error reporting. --- .../supporting/log/log-job.service.ts | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/subdomains/supporting/log/log-job.service.ts b/src/subdomains/supporting/log/log-job.service.ts index b72cf809ae..ec2a043176 100644 --- a/src/subdomains/supporting/log/log-job.service.ts +++ b/src/subdomains/supporting/log/log-job.service.ts @@ -716,11 +716,11 @@ export class LogJobService { let fromScrypt = pendingChfScryptBankPlusAmount + pendingEurScryptBankPlusAmount + pendingScryptBankMinusAmount; let toScrypt = pendingBankScryptPlusAmount + pendingChfBankScryptMinusAmount + pendingEurBankScryptMinusAmount; - let fromScryptUnfiltered = + const fromScryptUnfiltered = pendingChfScryptBankPlusAmountUnfiltered + pendingEurScryptBankPlusAmountUnfiltered + pendingScryptBankMinusAmountUnfiltered; - let toScryptUnfiltered = + const toScryptUnfiltered = pendingBankScryptPlusAmountUnfiltered + pendingChfBankScryptMinusAmountUnfiltered + pendingEurBankScryptMinusAmountUnfiltered; @@ -792,25 +792,8 @@ export class LogJobService { fromScrypt = 0; } - // Clamp unfiltered Scrypt values to prevent negative plus balances - if (fromScryptUnfiltered < 0) { - errors.push(`fromScryptUnfiltered < 0`); - this.logger.verbose( - `Error in financial log, fromScryptUnfiltered balance < 0 for asset: ${curr.id}, fromScryptUnfiltered: ${fromScryptUnfiltered}`, - ); - fromScryptUnfiltered = 0; - } - - if (toScryptUnfiltered < 0) { - errors.push(`toScryptUnfiltered < 0`); - this.logger.verbose( - `Error in financial log, toScryptUnfiltered balance < 0 for asset: ${curr.id}, toScryptUnfiltered: ${toScryptUnfiltered}`, - ); - toScryptUnfiltered = 0; - } - // total pending balance - const totalPlusPending = + let totalPlusPending = cryptoInput + exchangeOrder + bridgeOrder + @@ -820,6 +803,19 @@ export class LogJobService { (useUnfilteredTx ? fromScryptUnfiltered : fromScrypt) + (useUnfilteredTx ? toScryptUnfiltered : toScrypt); + // Clamp totalPlusPending to prevent negative plus balances + // This catches any negative values from unfiltered Kraken/Scrypt or other components + if (totalPlusPending < 0) { + errors.push(`totalPlusPending < 0`); + this.logger.verbose( + `Error in financial log, totalPlusPending < 0 for asset: ${curr.id}, totalPlusPending: ${totalPlusPending}. ` + + `Components: cryptoInput=${cryptoInput}, exchangeOrder=${exchangeOrder}, bridgeOrder=${bridgeOrder}, ` + + `olky=${pendingOlkyYapealAmount}, kraken=${useUnfilteredTx ? fromKrakenUnfiltered : fromKraken}+${useUnfilteredTx ? toKrakenUnfiltered : toKraken}, ` + + `scrypt=${useUnfilteredTx ? fromScryptUnfiltered : fromScrypt}+${useUnfilteredTx ? toScryptUnfiltered : toScrypt}`, + ); + totalPlusPending = 0; + } + const totalPlus = liquidity + totalPlusPending + (totalCustomBalance ?? 0); // minus