fix: notify on-chain receives that skip mempool#588
Conversation
When a transaction is confirmed before the wallet sees it unconfirmed, only onchainTransactionConfirmed fires. The received sheet was wired solely to onchainTransactionReceived, so straight-to-confirmed receives showed no notification. Both handlers now share one check-and-show helper. Fixes synonymdev#455.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3df9c525b9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Routing both onchainTransactionReceived and onchainTransactionConfirmed through the shared presenter means two tasks can run for one txid. The seen-check and mark were not atomic across awaits, so both events could present the sheet. Reserve the txid synchronously on the MainActor before any await so only the first event presents it. Addresses the PR synonymdev#588 review.
|
Hint: As a general note, we expect PR authors to I know some teams might get some members flamey over this, not the case with us. |
|
Got failure from the e2e test. After CPFP boost and subsequent restoration of the wallet we got the notification of previously received transaction in UI, pls see recording: boost_-_Boost_boost_1_-_Can_do_CPFP-2026-06-10T21-22-29-359Z.mp4Attaching also all artifacts that include simulator logs. |
On a wallet restore the activity store is rebuilt without seenAt, so the initial on-chain sync replays onchainTransactionConfirmed for historical receives. The shared presenter then showed the "Received" sheet for an old transaction, which covered the activity list and timed out the CPFP restore e2e. Set a pendingRestoreActivitySeen flag on the restore success screen, have the presenter bail while it is set, and on the first post-restore on-chain syncCompleted mark all unseen activities as seen and clear the flag. New straight-to-confirmed receives still notify once the flag clears, so synonymdev#455 stays fixed. Addresses the PR synonymdev#588 review.
@piotr-iohk I did some more digging on this, and it definitely seems to be an issue. Root cause: on a wallet restore the activity store is rebuilt with no Fix: a short-lived suppression flag that mirrors the existing migration handling, scoped to seed restore.
After the flag clears, genuinely new straight-to-confirmed receives notify again, so #455 stays fixed. Verified on regtest:
The |
…ed-received-sheet
Fixes #455
Description
This PR fixes the missing "received" notification for on-chain transactions that confirm before the wallet ever sees them unconfirmed.
LDK Node fires
onchainTransactionReceivedwhen a transaction is first seen in the mempool, andonchainTransactionConfirmedwhen it confirms. The received sheet was only wired to the first event, so a transaction that goes straight to confirmed (a block is mined in the window between broadcast and the next sync) updated the balance and activity list but never showed the "Received Bitcoin" sheet. It is reliably reproducible on regtest, and theoretically possible on mainnet when the app is backgrounded or offline during that window.Both the received and confirmed handlers now run the same check-and-show flow, so the notification appears for a new incoming transaction whether it was first seen in the mempool or arrived already confirmed. The existing seen-tracking means a transaction already announced on receive is not shown a second time when it later confirms.
Same issue as synonymdev/bitkit-android#797.
Linked Issues/Tasks
#455
Related: synonymdev/bitkit-android#797
Screenshot / Video
bitkit-455-before-after.mp4
Verified on regtest by depositing on-chain and mining one block immediately, so the transaction goes straight to confirmed. App-log counts for the identical repro:
Zero
receivedevents on both runs confirms the transaction skipped the mempool, so the difference is purely the fix.QA Notes
Manual Tests
regression:Deposit → wait for the app to show the tx as unconfirmed → Mine Blocks (1): sheet shows once on receive and does not reappear on confirm.regression:Send on-chain → Mine Blocks (1): no Received sheet (outgoing, negative amount).regression:Channel open/close or same-value RBF: still no Received sheet. Not driven live; covered by the unchangedshouldShowReceivedSheettransfer/channel filters that the receive path already exercised.Automated Checks
handleLdkNodeEvent(LDKEventtypes plus shared service singletons), so verification is the manual regtest repro.