feat: back up hardware wallet names - #1173
Draft
jvsena42 wants to merge 10 commits into
Draft
Conversation
jvsena42
marked this pull request as ready for review
August 21, 2026 10:34
Greptile SummaryThis PR adds hardware-wallet names to metadata backups and lets users retain names and tags when removing a wallet.
Confidence Score: 4/5The pending-name durability bug should be fixed before merging because a storage failure during pairing can permanently discard a restored wallet name. The pairing path deletes the pending backup copy after calling a persistence helper that suppresses write failures, allowing the only durable copy of a restored name to be lost. Files Needing Attention: app/src/main/java/to/bitkit/repositories/TrezorRepo.kt
|
| Filename | Overview |
|---|---|
| app/src/main/java/to/bitkit/data/HwWalletStore.kt | Adds durable pending-name storage plus merged backup snapshots and non-destructive restore behavior. |
| app/src/main/java/to/bitkit/repositories/BackupRepo.kt | Adds hardware-wallet names to metadata backup/restore and observes effective name changes to schedule uploads. |
| app/src/main/java/to/bitkit/repositories/ActivityRepo.kt | Adds wallet-scoped tag snapshots combining stored and rendered pre-activity metadata. |
| app/src/main/java/to/bitkit/repositories/HwWalletRepo.kt | Preserves or clears names and tags according to the user’s removal choice while retaining wallet-identity scoping. |
| app/src/main/java/to/bitkit/repositories/TrezorRepo.kt | Adopts pending names during pairing, but can consume one after a swallowed device-store persistence failure. |
| app/src/main/java/to/bitkit/ui/screens/wallets/RemoveHwWalletDialog.kt | Introduces the shared removal confirmation UI and keep-name-and-tags toggle. |
| app/src/main/java/to/bitkit/ui/screens/wallets/HwWalletViewModel.kt | Tracks the removal retention choice, defaults it on each dialog opening, and forwards it to the repository. |
Sequence Diagram
sequenceDiagram
participant UI as Removal / Restore UI
participant Backup as BackupRepo
participant Store as HwWalletStore
participant Trezor as TrezorRepo
participant Core as Activity Metadata
UI->>Store: retain or restore name by walletId
UI->>Core: retain tag metadata by walletId
Backup->>Store: snapshot names
Backup->>Core: snapshot tags
Trezor->>Store: read pending name during pairing
Trezor->>Store: persist KnownDevice with customLabel
Trezor->>Store: consume pending name
Note over Trezor,Store: Pending name must be consumed only after durable device persistence
Reviews (1): Last reviewed commit: "doc: changelog" | Re-trigger Greptile
Comment on lines
1163
to
+1167
| saveKnownDevices(updated) | ||
| // Consumed, so the name lives on the entry alone: leaving it would resurrect a name the user | ||
| // later clears, since the entry would then fall back to the pending one again. | ||
| if (pendingName != null) { | ||
| hwWalletStore.setPendingName(resolvedWalletId, null) |
There was a problem hiding this comment.
jvsena42
marked this pull request as draft
August 21, 2026 10:37
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.
This PR:
Follow-up to #1163, which closed #1046 by making hardware wallet tags survive backup and restore.
Description
#1163 made hardware wallet tags survive a restore: they ride the metadata backup as pre-activity metadata keyed by the Core-derived wallet id, and Core re-attaches them once the device watcher recreates the activities. Two gaps were left behind.
The name itself was never backed up. It lives only in the local device store, so restoring on a new phone and pairing the Trezor again brought the tags back but not the name the user chose. Nothing even marked a backup as required when a name changed, so a rename was invisible to the backup system entirely.
The second gap is the more damaging one. Removing a hardware wallet destroyed its tags in the backup, silently. Core deletes a wallet's activities, its activity tags and its pre-activity metadata in one cascade, which is both of the sources the metadata envelope draws hardware tags from, and the deletion then signals that tags changed, so a metadata envelope without them was uploaded within seconds. The dialog said only that funds are safe and coins will not be deleted; it never mentioned the tags. A full wallet wipe was never affected, because wiping suppresses uploads and leaves the stored backup intact.
The name travels on the same key the tags already use. Core's wallet id derives from a device's account extended public keys, is stable across installs and platforms, and does not depend on the order of those keys, so a name keyed by it survives a restore exactly as well as the tags do.
The name of a paired wallet still lives on its device entry, which is untouched. What is new is a small pending map for the two moments when no device entry exists: a name restored from a backup before the device has been paired again, and a name kept when a wallet was removed. Pairing takes the entry over and consumes it, which bounds the map and prevents a cleared name from being resurrected from a stale entry later.
Removal now takes the name and tag snapshot before the cascade, writes the tags back after it, and stores the name before the device entries are forgotten, so the backed-up set never dips during the removal. Turning the toggle off is the current behaviour made explicit: the tags go, and any name kept from an earlier removal of the same wallet is dropped too. If writing the tags back fails after the cascade has run there is nothing left to roll back to and the wallet is already half removed, so that failure is logged rather than reported as a failed removal.
One behaviour falls out of this for free: re-pairing a wallet that was removed with the toggle on restores its tags with no restore flow involved at all, because the pre-activity metadata rows survived locally and Core re-attaches them as the watcher recreates the activities.
The envelope is shared with iOS, whose model mirrors it field for field. Swift ignores unknown keys when decoding, so an older iOS build restores this envelope without trouble, but it drops the new field whenever it re-uploads, and it re-uploads often. A user running both apps on one seed would lose their backed-up names until the iOS side ships. Unlike the tags in #1163, which rode a field iOS already knew, this is a new field, so a companion iOS change is needed. A passthrough that decodes and re-encodes the field, with no UI, is enough to close the window.
Preview
QA Notes
Manual Tests
regression:Disconnect and reconnect the device without renaming → Settings → Data Backups: Tags is not re-uploaded.regression:Remove dialog → cancel: the wallet stays paired with its name and tags.regression:Enter a wrong passphrase for a paired hidden wallet: the stray wallet is cleaned up and leaves no name behind.Automated Checks
BackupRepoTest.kt, including that a failed name read fails the backup without uploading, that an envelope written before this field never clears stored names, and that a rename triggers a metadata backup while a reconnect does not.HwWalletRepoTest.kt, pinning the two orderings this depends on — the tag rewrite must follow Core's cascade, and the name must be stored before the device entries are forgotten — plus the toggle-off branch, the default, and a removal surviving a failed rewrite.TrezorRepoTest.kt, covering adopting and consuming a pending name, preferring a name set locally, and leaving another identity's name alone.ActivityRepoTest.kt. It unions the stored and the rendered metadata, because the cascade drops both and only the rendered half can be rebuilt from activity tags.HwWalletViewModelTest.kt, including that it returns to its default when the dialog is reopened.just compile,just testandjust lintpass, with no new detekt findings.