Wallet receive: external transaction table and checks#3121
Conversation
b204a0c to
bdd5c6b
Compare
b03fca8 to
6a4c970
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b54e160. Configure here.
| if (transaction?.direction !== 'RECEIVE') return | ||
| if (externalTransactionFinal(transaction) && !externalTransactionResolvesLocally(transaction)) return | ||
| // debounce to roughly one check per page poll | ||
| if (new Date(transaction.updatedAt).getTime() > Date.now() - 10_000) return |
There was a problem hiding this comment.
Poke debounce skips new checks
Medium Severity
pokeExternalTransactionCheck skips enqueueing a worker check whenever updatedAt is within the last ten seconds. A receive row is created with a fresh updatedAt, and the make-invoice flow immediately opens its transaction page, so the first reads that are meant to drive verification never queue a check until that window passes.
Reviewed by Cursor Bugbot for commit b54e160. Configure here.
|
The fixups I pushed are back ported from work on #3125:
There's still some weirdness in how we surface metadata we store from |


I'm happy with the shape of this now. I still need to:
checkInvoiceimplementationThis contains the core logic/relations for external transactions (ie payments that SN is not party to) + the receive side of external txs. Send side will be its own PR.
Vaguely:
/satisticsand/wallets/[id]/activity/wallets/[wid]/transactions/[id]for viewing external txs, sharing components/design with payins/transactions/[id]make invoicewe navigate to this transaction page (we'll do this for send too)checkInvoiceto all wallets that have some means of checking invoice statuscheckInvoice, or if an invoice expires and we don't have a definite settled/failed reported by the wallet, external tx statuses are marked asunknownand we attempt to report why it's unknownPunted to other PRs:
Note
Medium Risk
Touches wallet receive flows, activity pagination, and background settlement polling against external providers; receive-only in this PR but incorrect status or union ordering could mislead users about funds.
Overview
Adds
ExternalTransactionpersistence for wallet Lightning activity SN does not route as a PayIn, starting with receive:createWalletInvoicenow creates a row (with optionalverificationContext, e.g. LNURL verify) and returnstransaction; the receive flow navigates to/wallets/transactions/[id]instead of showing a QR inline.Settlement is polled server-side via new
checkInvoicehooks on supported protocols (Blink, CLN REST, LNbits, LND gRPC, NWC, Phoenixd, LN Addr), withclassifyExternalTransactionCheckmapping results to PENDING / SETTLED / FAILED / UNKNOWN (including expiry and permission/verification reasons). pg-boss jobscheckExternalTransactionandcheckPendingExternalTransactionsdrive checks; reading a live receive can poke a debounced job.Activity feeds change:
satisticsreturnstxs: [WalletActivityItem!]!(PayIn ∪ ExternalTransaction) using a sort-key union plushydrateWalletActivity, with deterministic pagination tiebreaks. Wallet activity tables and Apollo cache policies followtxs.UI shares
TransactionDetail*layout between PayIn and external pages (QR for payable receives, status, invoice details,WalletLogsfiltered byexternalTransactionId). Scheduled bolt11 retention also clears sensitive fields on old external rows.Reviewed by Cursor Bugbot for commit b54e160. Bugbot is set up for automated code reviews on this repo. Configure here.