* fix: publish transaction events only after the database transaction commits
markTransactionSettled and markPaymentFailed published nwc_payment_sent /
nwc_payment_received / nwc_payment_failed (and checkBudgetUsage published
nwc_budget_warning) while still inside the caller's database transaction, so
connected apps and the Alby API could be notified of a payment whose row was
never committed, and subscribers reading the database in response to an event
could race with the commit.
Every function that writes transaction state now owns its own database
transaction and publishes its events only after the commit succeeds:
- markTransactionSettled and markPaymentFailed open their own transaction;
callers no longer wrap them in db.Transaction
- new createSettledTransactionFromNotification inserts transactions reported
by LNClient notifications for payments the hub has no record of (external
payments, received keysends) directly in their settled state, removing the
transient PENDING row and the zombie row left behind on duplicate events
- markPaymentFailed now refuses to mark a settled transaction as failed,
replacing CancelHoldInvoice's in-transaction ACCEPTED re-check and also
protecting the SendPaymentSync error path from a racing settle
- checkBudgetUsage returns the budget warning event instead of publishing it
Closes#2506
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: serialize payment failure with settlement and propagate lock errors
Address review findings on the previous commit:
- markPaymentFailed now takes the same payment-hash row lock as settlement
(postgres), so the settled-state guard cannot be bypassed by a concurrent
settle between the state check and the update; it also returns not-found
instead of publishing an event when the transaction row no longer exists,
and reports whether this call transitioned the row so CancelHoldInvoice
only publishes nwc_hold_invoice_canceled when it performed the cancellation
- findSettledTransaction propagates errors from the lock query and the
settled-transaction lookup instead of treating a failed lookup as
"no settled transaction exists", which could defeat the dedup guard
- TestMarkSettled_Twice no longer shares one transaction struct between
concurrent goroutines and collects errors instead of asserting inside them
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: mark failed keysend payments via markPaymentFailed
The SendKeysend failure path updated the transaction directly, which never
zeroed the fee reserve, recorded no failure reason, published no
nwc_payment_failed event, and had no guard against overwriting a
concurrently settled payment. Route it through markPaymentFailed like
SendPaymentSync, and allow MockLn keysends to fail so the path is testable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: use scope constant in get_budget permission query
The get_budget controller filtered the app_permissions scope column with
models.PAY_INVOICE_METHOD, which only matched because the method and
scope constants share the same string value. Use
constants.PAY_INVOICE_SCOPE like every other scope lookup, and document
why the unchecked First result is safe.
Fixes#2503
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: return error from get_budget on unexpected permission query failure
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The avatar overlay made the QR code hard to scan, especially for
short lightning addresses. Without center content the QR also drops
back to a lower error correction level, improving scannability.
Fixes#2507
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: filter transactions
* fix: harden transaction filters
* refactor: use explicit nullable transaction filters with HideFailed polarity
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat: set transaction filters in a dialog from wallet actions menu
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat: filter transactions by search term and type
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: reject invalid transaction filters and reset page synchronously
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: parse complete minimum amount value in transactions filter dialog
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Roland Bewick <roland.bewick@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: fallback to outgoing payments in Phoenixd LookupInvoice
LookupInvoice only queried /payments/incoming/{hash}, returning 404 for
outgoing payments. This caused all outgoing Lightning payments to remain
permanently stuck as PENDING in Alby Hub.
The fix tries incoming first (preserving existing behavior), then falls
back to listing outgoing payments and matching by paymentHash.
Fixes#2442
* fix: amount and fees in phoenix payment to transaction
---------
Co-authored-by: Roland Bewick <roland.bewick@gmail.com>
chore: update bark bindings to v0.15.0
Moves from bark 0.4.0 to 0.6.0. The Ark server now requires protocol version 5
(hashlock clauses) to start a lightning receive, which only bark 0.6.0 sends, so
older clients are refused outright and cannot generate invoices.
No client changes needed: v0.15.0 only adds to the surface we use.
Creating a developer token in the Wails build failed with a confusing
"Unhandled route: POST /api/unlock" error, because the desktop app does
not expose an HTTP API for the token to be used against. Hide the token
creation form in the desktop build and show an explanatory message
instead.
Fixes#2471
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Picks up getAlby/go-nostr#6, which shares relay connections in
SimplePool when dials fail, closes relay websockets on pool close,
and closes previous subscriptions before re-subscribing on CLOSED.
The shared per-relay-URL connect backoff is now enabled by default
in the fork, so no hub-side pool option is needed
(nostr.WithPenaltyBox is deprecated).
Fixes#2481
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Switch from polling node.NextEvent() every second to node.NextEventAsync(),
which parks the goroutine until an event arrives without blocking an OS
thread or an LDK thread, as LDK is migrating to async event handling.
Guard event handling with a mutex held by Shutdown() so in-flight handlers
finish before the node is stopped and destroyed, and drop events that
arrive after shutdown starts (LDK redelivers unhandled events on startup).
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: refresh payment QR and status components
* fix: align payment success button spacing
* fix: invert payment QR colors in dark mode
* fix: address payment QR review feedback
* fix: flatten nested cards in payment review FixedFloat tiles
* chore: remove internal payment component review screen
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: keep QR codes dark-on-light in dark mode
Inverted QR codes are unreadable by many scanner apps (e.g. Phoenix).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: René Aaron <rene@getalby.com>
Co-authored-by: Roland Bewick <roland.bewick@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Moves from bark 0.2.3 to 0.4.0, which changed the FFI surface:
- WalletOpen takes the network and a WalletOpenArgs, replacing WalletCreate
and the separate RunDaemon call.
- Bolt11Invoice takes an optional anti-DoS token, unused here.
- LightningReceiveStatus is now LightningReceiveState, reporting progress
via State rather than a PreimageRevealed bool.
Movements expose PaymentHash and sends expose a typed terminal state, so both
are read from those instead of the movement metadata JSON. A send movement that
is neither pending nor successful now resolves the SendPaymentSync waiter
instead of being ignored.
the mnemonic could be considered a non read-only route because the
mnemonic could be used.
This moves this route to the full access group to require a full access
api key.
* fix: avoid mempool api failures during swaps by using boltz for fee and tx lookup
* fix: ensure swap payment isn't made twice on refresh
---------
Co-authored-by: Roland Bewick <roland.bewick@gmail.com>
* feat: just in time channels with lsps2
* fix: clarify JIT receive channel fee
* fix: fees
* fix: fees 2
* fix: don't show low inbound when LSPS2 is active
* fix: remove the receive limit below the input if LSPS2 is being used
* fix: simplify
* fix: bring back fee % for outgoing
* fix: remove unneeded changes
* fix: typo
* fix: unneeded
* fix: don't show open first channel is LSPS2
* feat: clearer JIT channel fee copy on receive screen
* fix: add LSPS2 var info
* fix: don't duplicate JIT fee hint on create invoice form
* fix: make paymentDone a standard boolean
* fix: update to golang:1.26 in Dockerfile
* feat: read LSPS2 sources from channel suggestions, set minimum receive amount, update guide link
* docs: update LDK_LSPS2_ADDRESSES to be used as an override
* fix: only show minimum jit receive amount on validation error
* fix: add more detail to receive error when receiving low amounts with jit
* fix: do not use JIT when user has public channels
* feat: add option to disable JIT
* fix: isTrusted check, add jit property to event
* fix: do not require node restart for toggling JIT
* chore: simplify JIT alert
* chore: add guide link on node settings JIT description
* feat: fetch the lsp2info to have access to params like minimum/maximum payment size
* refactor: share single learn-more link across JIT fee hint branches
* fix: remove variable amount invoice support
* fix: use lsps2info for min payment size and remove channelPeerSuggestion usage of minimumChannelSize
* fix: only do amount validation according to lsps2Info values if jit is enabled in settings
* feat: add jit first payment fee alert on receive via lightning address
* fix: remove unnecessary conditional
* fix: ensure at least one sat is left over when opening JIT channel
* chore: remove hardcoded suggestions
* chore: rename JIT enabled config variable
* fix: ui checks when JIT is disabled
* fix: amount input validation message
* fix: formatting
---------
Co-authored-by: anon <anon@anon.com>
Co-authored-by: saunter <68239231+stackingsaunter@users.noreply.github.com>
Co-authored-by: fmar <fmar@fmar>
Co-authored-by: René Aaron <rene@twentyuno.net>
Co-authored-by: Roland Bewick <roland.bewick@gmail.com>
* feat: pass selected provider to card topup app
The Bitcoin Card Topup app (card.albylabs.com) now supports configuration
presets selected via a `provider` query param. Pass the provider chosen on
the Cards page through to the topup app's install link so its preset is
pre-applied, simplifying setup.
Closes#2384
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: move bitcoin card topup install guide component to a new file
* chore: remove accidentally committed worktree gitlinks
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: use more general copy for card topup app install guide
* fix: remove subtree commits
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>