From be3ac55f1d2f09792af4251579801fe022a80e8d Mon Sep 17 00:00:00 2001 From: Padreug Date: Wed, 17 Jun 2026 00:04:02 +0200 Subject: [PATCH] fix(wallet): stop double-deducting balance on outgoing payments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wallet WebSocket handler assumed LNbits sends the PRE-payment balance for outgoing payments and subtracted the amount again. LNbits actually re-fetches the wallet AFTER the payment settles before emitting the notification (core payments.py `_send_payment_notification_in_background` → "fetch balance again" → notifications.py `send_ws_payment_notification` → `wallet.balance`), so `wallet_balance` is already POST-payment for both directions. The extra subtraction double-deducted: 100 sats, send 10 → balance showed 80, then a refresh (which reads the authoritative /api/v1/wallet balance) corrected it to 90. Use `wallet_balance` as-is for all messages, matching the polling fallback which already trusts the API balance directly. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../wallet/services/WalletWebSocketService.ts | 42 +++++-------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/src/modules/wallet/services/WalletWebSocketService.ts b/src/modules/wallet/services/WalletWebSocketService.ts index 0969a33..5b332d0 100644 --- a/src/modules/wallet/services/WalletWebSocketService.ts +++ b/src/modules/wallet/services/WalletWebSocketService.ts @@ -231,41 +231,21 @@ export class WalletWebSocketService extends BaseService { this.handlePaymentNotification(data.payment) } - // Handle wallet balance update + // Handle wallet balance update. + // `wallet_balance` is authoritative and already POST-payment for BOTH + // directions: LNbits re-fetches the wallet AFTER the payment settles + // before emitting the notification (core services/payments.py + // `_send_payment_notification_in_background` → "fetch balance again" → + // services/notifications.py `send_ws_payment_notification` → + // `wallet.balance`). Use it as-is. The previous code subtracted the + // outgoing amount on top, double-deducting (100 → send 10 → showed 80, + // refresh corrected to 90). if (data.wallet_balance !== undefined) { - console.log('WalletWebSocketService: Processing balance update', { - newBalance: data.wallet_balance, + console.log('WalletWebSocketService: Updating balance to', data.wallet_balance, 'sats', { hasPayment: !!data.payment, paymentAmount: data.payment?.amount }) - - let finalBalance = data.wallet_balance - - // For outgoing payments, LNbits sends pre-payment balance, so we need to adjust - // For incoming payments, LNbits sends post-payment balance, so use as-is - if (data.payment && data.payment.amount < 0) { - // Outgoing payment - subtract the payment amount from the balance - const paymentSats = Math.abs(data.payment.amount) / 1000 - finalBalance = data.wallet_balance - paymentSats - console.log('WalletWebSocketService: Adjusting balance for outgoing payment', { - originalBalance: data.wallet_balance, - paymentSats: paymentSats, - finalBalance: finalBalance - }) - } else if (data.payment && data.payment.amount > 0) { - // Incoming payment - use balance as-is (already post-payment) - console.log('WalletWebSocketService: Using balance as-is for incoming payment', { - balance: data.wallet_balance - }) - } else { - // No payment in message - use balance as-is - console.log('WalletWebSocketService: Using balance as-is (no payment)', { - balance: data.wallet_balance - }) - } - - console.log('WalletWebSocketService: Updating balance to', finalBalance, 'sats') - this.updateWalletBalance(finalBalance) + this.updateWalletBalance(data.wallet_balance) } } catch (error) {