Skip to content

feat: back up hardware wallet names - #1173

Draft
jvsena42 wants to merge 10 commits into
masterfrom
feat/hw-wallet-name-backup
Draft

feat: back up hardware wallet names#1173
jvsena42 wants to merge 10 commits into
masterfrom
feat/hw-wallet-name-backup

Conversation

@jvsena42

Copy link
Copy Markdown
Member

This PR:

  1. Backs up the name you give a hardware wallet, and restores it when the device is paired again.
  2. Asks, when removing a hardware wallet, whether to keep its name and tags in the backup, defaulting to keeping them.

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

  • 1. Hardware Wallet → rename the wallet → Settings → Data Backups: Tags shows as synced again.
  • 2. regression: Disconnect and reconnect the device without renaming → Settings → Data Backups: Tags is not re-uploaded.
  • 3. Rename a hardware wallet and tag one of its transactions → wipe wallet → restore from seed → pair the device again: the tile shows the custom name and the tagged transaction shows its tags.
  • 4a. Hardware Wallet → Remove with the keep toggle on → pair the device again: name and tags return.
    • 4b. Remove with the keep toggle off → pair the device again: the wallet comes back under the device's own name with no tags.
  • 5. Settings → Hardware Wallets → trash icon: the same dialog opens, with the toggle on by default.
  • 6. Remove dialog → turn the toggle off → cancel → reopen the dialog: the toggle is on again.
  • 7. Passphrase wallet → Remove with the keep toggle on → pair again with the same passphrase: its own name returns, and the standard wallet's name is unaffected.
  • 8. regression: Remove dialog → cancel: the wallet stays paired with its name and tags.
  • 9. regression: Enter a wrong passphrase for a paired hidden wallet: the stray wallet is cleaned up and leaves no name behind.

Automated Checks

  • Unit tests added: cover the envelope and the restore in 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.
  • Unit tests added: cover the removal in 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.
  • Unit tests added: cover pairing in TrezorRepoTest.kt, covering adopting and consuming a pending name, preferring a name set locally, and leaving another identity's name alone.
  • Unit tests added: cover the wallet-scoped tag snapshot in 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.
  • Unit tests added: cover the toggle in HwWalletViewModelTest.kt, including that it returns to its default when the dialog is reopened.
  • Local just compile, just test and just lint pass, with no new detekt findings.

@jvsena42 jvsena42 self-assigned this Aug 20, 2026
@jvsena42
jvsena42 marked this pull request as ready for review August 21, 2026 10:34
@greptile-apps

greptile-apps Bot commented Aug 21, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds hardware-wallet names to metadata backups and lets users retain names and tags when removing a wallet.

  • Adds pending-name persistence and adoption during hardware-wallet pairing.
  • Extends metadata backup and restore with names keyed by wallet identity.
  • Snapshots and restores hardware-wallet tags around removal.
  • Adds a shared removal dialog with a keep-backup-data toggle and associated tests.

Confidence Score: 4/5

The 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

Important Files Changed

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
Loading

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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Pending name consumed after failed save

When persisting the paired device fails, saveKnownDevices suppresses the error and this code still deletes the pending name, causing the restored custom name to disappear permanently after the process restarts.

Knowledge Base Used:

@jvsena42
jvsena42 marked this pull request as draft August 21, 2026 10:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hardware Wallet Data Backup & Restore

1 participant