fix(wallet): stop double-deducting balance on outgoing payments #109

Merged
padreug merged 1 commit from fix/wallet-double-deduct-balance into dev 2026-06-17 08:38:06 +00:00
Owner

Problem

Sending a payment deducts the displayed balance twice: with 100 sats, sending 10 shows 80. A page refresh corrects it to the right value (90), so the bug is purely in the live in-memory balance, not the backend.

Root cause

WalletWebSocketService.handleMessage assumed LNbits sends the pre-payment balance for outgoing payments and subtracted the amount again:

if (data.payment && data.payment.amount < 0) {
  const paymentSats = Math.abs(data.payment.amount) / 1000
  finalBalance = data.wallet_balance - paymentSats   // ← extra deduction
}

But LNbits emits the post-payment balance for both directions. It re-fetches the wallet after the payment settles before sending the notification:

  • core/services/payments.py _send_payment_notification_in_background# fetch balance againget_wallet(...)
  • core/services/notifications.py send_ws_payment_notification"wallet_balance": wallet.balance

So wallet_balance is already 90 for our example, and subtracting 10 again yields 80. The refresh reads the authoritative /api/v1/wallet balance (90), which is why it self-corrects.

Fix

Use wallet_balance as-is for all messages — no per-direction adjustment. This matches the polling fallback in the same file, which already trusts the /api/v1/wallet balance directly.

Test notes

  • vue-tsc --noEmit clean for the changed file.
  • Smoke after dev deploy: with a known balance, send a payment → live balance should drop by exactly the sent amount and match a manual refresh (no transient double-deduct). Re-verify an incoming payment still lands on the correct post-payment balance.

🤖 Generated with Claude Code

## Problem Sending a payment deducts the displayed balance **twice**: with 100 sats, sending 10 shows **80**. A page refresh corrects it to the right value (**90**), so the bug is purely in the live in-memory balance, not the backend. ## Root cause `WalletWebSocketService.handleMessage` assumed LNbits sends the **pre-payment** balance for outgoing payments and subtracted the amount again: ```ts if (data.payment && data.payment.amount < 0) { const paymentSats = Math.abs(data.payment.amount) / 1000 finalBalance = data.wallet_balance - paymentSats // ← extra deduction } ``` But LNbits emits the **post-payment** balance for *both* directions. It re-fetches the wallet *after* the payment settles before sending the notification: - `core/services/payments.py` `_send_payment_notification_in_background` → `# fetch balance again` → `get_wallet(...)` - → `core/services/notifications.py` `send_ws_payment_notification` → `"wallet_balance": wallet.balance` So `wallet_balance` is already `90` for our example, and subtracting `10` again yields `80`. The refresh reads the authoritative `/api/v1/wallet` balance (`90`), which is why it self-corrects. ## Fix Use `wallet_balance` as-is for all messages — no per-direction adjustment. This matches the polling fallback in the same file, which already trusts the `/api/v1/wallet` balance directly. ## Test notes - `vue-tsc --noEmit` clean for the changed file. - Smoke after dev deploy: with a known balance, **send** a payment → live balance should drop by exactly the sent amount and **match a manual refresh** (no transient double-deduct). Re-verify an **incoming** payment still lands on the correct post-payment balance. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
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) <noreply@anthropic.com>
padreug force-pushed fix/wallet-double-deduct-balance from be3ac55f1d to fddc26387e 2026-06-17 08:37:48 +00:00 Compare
padreug deleted branch fix/wallet-double-deduct-balance 2026-06-17 08:38:06 +00:00
Sign in to join this conversation.
No description provided.