Conversation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Regtest APKDownload bitkit-dev-debug universal APK (expires in 30 days). |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jvsena42
left a comment
There was a problem hiding this comment.
Approved — no HIGH/MEDIUM findings at head 05e18eabe. (Posted as a comment because GitHub does not allow approving your own PR.)
Inline: LOW — Description-hash invoice paid without a comment still shows the 64-hex hash as the Invoice note
Checked: Traced the comment from SendUiState.comment through savePendingLnurlComment (AppViewModel.kt:4050-4056) to CacheStore.pendingLightningMessages and back out via ActivityService.setLightningMessageIfEmpty and processBolt11. The key is decodedInvoice.paymentHash.toHex(), which equals ldk-node's PaymentId/event paymentHash for bolt11 (sendLightning already matches events on it), so the entry cannot attach to another payment; a retry re-fetches a new LNURL invoice, so it cannot inherit a stale hash. The description gate is correct: bitkit-core v0.5.14 scanner returns description=None for h-tagged invoices while ldk-node reports the hash hex as PaymentKind.Bolt11.description, so withPendingMessage replaces exactly the hash-hex placeholder and never a real description or user note; withPaymentUpdate from the base branch never touches message. Concurrency between setLightningMessageIfEmpty and processBolt11 (full sync, handlePaymentEvent, async chunks) is safe: both run on the single-threaded CORE queue and for outbound payments processBolt11 has no suspension point between reading the row and writing it (the contact resolver returns synchronously for OUTBOUND), so every interleaving ends with the comment on the row or still in the cache. Upgrade from the released build reads app_cache.json without the new key into the default empty map (kotlinx defaults, ignoreUnknownKeys=true for downgrade); the comment is persisted on the activity row, which ActivityBackupV1 serializes whole, and restoreFromBackup upserts it back with the message intact. Definite-failure, pending (10s timeout / held HTLC), process-death-while-pending and dismissed-sheet paths all leave the comment either applied or in the cache for the next sync. iOS twin absent: bitkit-ios LnurlPayConfirm.swift sends the comment but nothing stores it, as the PR body already notes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Approved — no blocking HIGH/MEDIUM findings at head 2a28e7575. (Posted as a comment because GitHub does not allow approving your own PR.)
Inline: MEDIUM (journey, non-blocking) — The example endpoint, the bitkit-docker lnurl-server, returns plain-description invoices, so the journey never exercises the fix
Checked: Round 3 (2a28e75, new journey): Round 3 delta is the new journey and two README rows. Every testTag the journey names exists at head: SendNumberField and ContinueAmount (SendAmountScreen.kt:260, :334), CommentInput (SendConfirmScreen.kt:456, rendered only when commentAllowed > 0 at :850), GRAB (SwipeToConfirm.kt:171), SendSuccess (SendSheet.kt:348), ActivityShort-N (ActivityListSimple.kt:52) and InvoiceNote (ActivityDetailScreen.kt:588). The flow order matches the code: a variable-amount LNURL-pay goes to SendRoute.Amount (AppViewModel.kt:3523), onAmountContinue does not apply QuickPay, the pending screen title is "Payment Pending" and has no tag, and InvoiceNote is the Invoice note block on Activity Detail shown for any Lightning activity with a non-empty message. lightning:lnurl1... is accepted by the bitkit-core scanner's LNURL regex. No bitkit-ios twin exists, and the journey is recorded as not ported in the cross-platform table.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jvsena42
left a comment
There was a problem hiding this comment.
Approved — no blocking HIGH/MEDIUM findings at head 7a011ab52. (Posted as a comment because GitHub does not allow approving your own PR.)
Checked: Round 4 (7a011ab): the journey MEDIUM is fixed. Round 4 covers 7a011ab, which only edits journeys/lnurl/lnurl-pay-comment-note.xml in answer to the memo-only endpoint finding. The journey now points at an lnurl-node LNURL.createServer backed by LND, as bitkit-e2e-tests test/specs/lnurl.e2e.ts sets up. lnurl@0.26.2 (the version in that repo's lockfile) passes descriptionHash = sha256(metadata) to the backend, and lightning-backends@1.6.5 lnd.js sets description_hash on POST /v1/invoices, so those invoices are description-hash invoices with no comment in them. The journey also says the bitkit-docker lnurl-server cannot be used, and that is correct: lnurl-server/routes/pay.js builds the invoice memo as LNURL Payment <id> - <comment>. It requires minSendable < maxSendable with 1,000,000 msat in range and states that the e2e suite's payRequest1 range (149,500-200,999 msat) does not cover it, so the runner has to generate its own payRequest. The InvoiceNote assertions now require the note to equal "thanks" exactly, which fails on a memo-shaped note or the description hash. Since the comment cannot reach the note through the invoice, a pass can only come from the persisted comment. testTags and step order are unchanged from the approved round.
…ed-channel-transfers # Conflicts: # journeys/README.md
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pull Request is not mergeable
Pull Request is not mergeable
fix: keep date grid visible on rapid taps
…l-transfers fix: settle transfers for closed channels
…-on-wipe fix: clear migration data on wipe
…lure fix: flag session restore on pubky init fail
…e-tests test: use in-memory cache store in tests
…unt' into HEAD # Conflicts: # journeys/README.md
|
The red Merged current master in; the file now carries the fix and |
There was a problem hiding this comment.
Verdict: ✅ Approve
Reaudit: diff 0 files.
Findings:
N/A
Audit:
Already done in comment.
QA: redroid Android 15 emulator
-
✅ passed: LNURL-pay with comment reached payment success.
-
✅ passed: The newest activity note was exactly
thanks. -
✅ passed: The note survived force-stop and relaunch.
-
✅ passed: A pending hold payment kept
thanksafter settlement. -
✅ passed: Empty-comment LNURL-pay preserved the description-hash note.
-
✅ passed: A regular invoice preserved its description note.
-
✅ passed: A failed LNURL comment did not leak into the next payment.
Coverage:
QA: 7 of 7 manual tests passed
Reviewed by gpt-5.6-sol-high via gh-pr-review-loop skill
Commands: @ovi-reviewer review · test · retest · audit (author or owner)










Fixes #417
Related to #1275
This PR keeps the comment typed on an LNURL-pay payment as the note of the sent Lightning activity.
Description
Out of Scope
AppViewModel: the comment is stored only for description-hash invoices (LUD-06). LNURL-pay servers that return a plain-description invoice still send the comment without showing it in the activity, to protect invoice descriptions.CacheStore: pending comments have no pruning. An entry is left behind only if the app dies or the send coroutine is cancelled between saving and completing the send.CoreService: the pending comments are read once per outbound Bolt11 payment during sync rather than once per sync. DataStore caches the value, so the cost is small.Design
The comment appears in the existing Invoice note slot of the Lightning transaction detail. No layout changes.
Preview
Recorded on a simulation build: staging regtest has no LNURL-pay endpoint that allows comments. The comment "Thanks for the channel" was hardcoded in place of the LNURL checks, and a Blocktank order invoice with a plain description stood in for the LDK description hash. Everything after that (saving, sending, applying on pending and on sync) ran the branch code.
QA Notes
Manual Tests
Needs an LNURL-pay endpoint that issues description-hash invoices (LUD-06) and allows comments, on the same Lightning network as the app: an lnurl-node
LNURL.createServerbacked by a local LND, as the bitkit-e2e-tests lnurl suite sets up intest/specs/lnurl.e2e.ts. It needs minSendable below maxSendable with 1,000 sats in range, since a fixed amount skips the amount screen. The bitkit-docker lnurl-server does not work for this: it builds the invoice with a plain memo containing the comment, so the note readsLNURL Payment <id> - thankson this branch and on master alike. The comment input and the LNURL and invoice-description checks were not driven on a device; they are covered by unit tests. The bitkit-e2e-tests lnurl suite has a commented-out InvoiceComment assertion that could be re-enabled against theInvoiceNotetag.regression:Pay a regular LN invoice with a description: Invoice note shows the invoice description.regression:LNURL-pay with comment → payment fails (e.g. no route): no stale comment applied to later payments.A new journey covers flow 1, committed at
journeys/lnurl/lnurl-pay-comment-note.xmlandlisted in
journeys/README.md(suites table and cross-platform table). It was not run as writtenbecause staging has no LNURL-pay endpoint; the simulated run above covered its payment, note and
relaunch steps.
lnurl-pay-comment-note.xml
Automated Checks
CoreServiceTest.ktcovers filling an empty message, replacing the LDK description hash, keeping a different stored message, and ignoring a null or blank comment.AppViewModelSendFlowTest.ktcovers saving the comment before paying and applying it on success and on pending, skipping invoices with their own description, and clearing it on failure.ActivityRepoTest.ktcovers the new repository methods passing through to the cache and activity service, and a service failure returning a failure result.ActivityServiceLightningMessageTest.ktruns the real activity service with mocked bitkit-core calls. It covers the stale-row race with the payment sync, the no-row case, andprocessBolt11creating or updating a row with the comment, including a comment saved mid-read. The two race tests fail against the previous implementation.just compile,just test(2613 passed),just lint.