fix: recover hw transfer after re-pairing - #1133
Merged
Merged
Conversation
Greptile SummaryRestores transfer metadata when a removed hardware wallet is re-paired by matching rediscovered funding transaction IDs against retained transfer records.
Confidence Score: 5/5The PR appears safe to merge, with no concrete blocking or independently actionable non-blocking issues identified. The recovery is constrained to exact funding transaction IDs, fills only missing metadata, preserves existing values, and retains snapshot persistence when the auxiliary lookup fails.
|
| Filename | Overview |
|---|---|
| app/src/main/java/to/bitkit/repositories/ActivityRepo.kt | Loads retained transfer mappings before persisting hardware snapshots and intentionally continues with an empty map if lookup fails. |
| app/src/main/java/to/bitkit/repositories/TransferRepo.kt | Adds funding-transaction-to-channel lookup across retained transfer records and documents why settled records remain necessary. |
| app/src/main/java/to/bitkit/services/CoreService.kt | Extends hardware snapshot merging to recover missing transfer metadata without overwriting incoming or stored channel metadata. |
| app/src/test/java/to/bitkit/repositories/ActivityRepoTest.kt | Verifies transfer mappings are forwarded and snapshot persistence survives lookup failure. |
| app/src/test/java/to/bitkit/repositories/TransferRepoTest.kt | Covers settled-record retention, lookup filtering, duplicate behavior, and database failures. |
| app/src/test/java/to/bitkit/services/CoreServiceTest.kt | Covers transfer recovery, transaction-ID matching, metadata precedence, unrelated and Lightning activities. |
| changelog.d/next/1130.fixed.md | Accurately describes the user-visible hardware-wallet transfer-label restoration. |
Sequence Diagram
sequenceDiagram
participant Watcher as Hardware Wallet Watcher
participant ActivityRepo
participant TransferRepo
participant Core as ActivityService
participant DB as Activity Database
Watcher->>ActivityRepo: persistHwSnapshot(walletId, activities)
ActivityRepo->>TransferRepo: getChannelIdsByFundingTxId()
TransferRepo-->>ActivityRepo: fundingTxId → channelId
ActivityRepo->>Core: replaceHwSnapshot(..., transfer map)
Core->>Core: Merge stored metadata
Core->>Core: Recover missing transfer metadata by txid
Core->>DB: Delete stale and upsert merged activities
Core-->>ActivityRepo: Persisted activities
Reviews (1): Last reviewed commit: "fix: recover hw transfer after re-pairin..." | Re-trigger Greptile
jvsena42
enabled auto-merge
August 5, 2026 12:15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1130
This PR restores the transfer label on a hardware wallet's funding transaction after the device is removed and re-paired.
Description
A transfer to spending from a paired hardware wallet settles once its channel becomes usable. Removing the device deletes that wallet's activities, and on re-pair the watcher rediscovers the funding transaction from scratch with no stored row left to carry the transfer metadata forward, so it came back looking like an ordinary send. Only settled transfers were affected: one whose channel had not opened yet is still being tracked and gets re-marked on its own.
Bitkit's own record of the transfer survives removal untouched and still holds the funding transaction id and the channel id, so the flag is now recovered from there while the rediscovered snapshot is merged.
The match runs in the safe direction only, from a rediscovered transaction id to an existing local transfer record. Nothing hardware-specific is retained past removal: the transaction id is re-supplied by the device's own watcher on re-pair, and the transfer record belongs to the Lightning channel that is still open, which the user never asked to delete. Removing a device and never re-pairing leaves no trace.
Recovery only ever fills gaps. Anything the app already knows wins, an existing channel id is never overwritten, and transactions with no matching transfer record are left alone.
This mirrors the iOS fix in synonymdev/bitkit-ios#648, with two deliberate differences. Its partial-snapshot handling is not ported, because a wallet here reports through a single watcher and callers already merge everything before persisting. And the new value is required rather than defaulted, since a default is what allowed the equivalent iOS tests to pass while silently skipping the recovery path entirely.
One consequence worth flagging for future work: settled transfers are now load-bearing for this recovery. The note suggesting they could be deleted once settled has been rewritten to say so, and a test pins the behaviour so acting on it fails loudly instead of quietly reintroducing this bug.
Preview
Before remove transfer row
Bug - After repair, transfer row replaced with send row
Fixed - After repair, transfer flow displayed
QA Notes
Requires the Trezor Bridge emulator from
bitkit-dockerand a Bridge-enabled build, seejourneys/hardware-wallet/README.md.Manual Tests
regression:Transfer to spending while the channel is still opening → remove and re-pair before it settles: row still reads Transfer.Automated Checks
CoreServiceTest.kt— recovery when no stored row remains, stored metadata winning over a recovered value, matching on transaction id rather than activity id since re-paired rows are rebuilt under new ids, unrelated transactions left unmarked, and Lightning activities passing straight through.ActivityRepoTest.kt— known channel ids actually reach the merge, and a failed lookup still persists the snapshot instead of dropping a wallet's activity list. The equivalent iOS change has no coverage here.TransferRepoTest.kt— settled transfers are included, records missing a funding transaction or channel are skipped, duplicates keep the first entry, and a database failure surfaces.TransferRepoTest.ktasserts that settling a transfer never deletes its record, so a future cleanup of settled transfers cannot silently reintroduce this bug.masteragainst a Trezor Bridge emulator, then confirmed the row returns as a transfer after a fresh remove and re-pair on this branch.