feat: home-screen hardware wallet (watch-only)#605
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as outdated.
This comment was marked as outdated.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bae69fd746
ℹ️ 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".
…calls. improved eficiency caching wallet Ids and comparing merged activities before notify activity changes
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5777dbbb4e
ℹ️ 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".
Observations from initial testingInitial observations (Trezor Safe 7, regtest + iPhone 13)Logs: bitkit_logs_2026-06-25_14-26-56.zip Test address (regtest native segwit): 1. first connect (problematic) — logs ~13:41 UTC ❌
2. recovery ✅
3. follow-up retest ✅
Follow-up suggestion (non-blocking):
In general the watch-only path works once xpub capture completes cleanly (4/4). First connect with 3/4 xpubs left Home at 0 despite the watcher starting. Other observations:
|
Agreed, I can move it on the last polish PR |
Follow-up (non-blocking): watch-only first-sync latency — balance & activities take a few seconds to appear after connectWhile re-testing on HEAD against the Trezor Bridge emulator, the hardware balance — and the device's activities — took several seconds to appear after a successful connect. Traced it in the session log:
Root cause: connect + xpub capture complete in ~70 ms; the lag is entirely
So "balance took a while" and "activities took a while" are the same first-sync latency — not a correctness issue, and distinct from the earlier 0-balance report (where the watcher started but never reported). Note this was over Bridge with only Suggested follow-up (app-side): show a loading state (spinner/skeleton) on the hardware row + activity placeholders while a device's first watcher sync is in flight, instead of a bare |
Fixed in 4d788bd |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 14566f6550
ℹ️ 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".
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
…se syncWatcher check logic
…sPinVerified) to reconnect on unlock so the pairing-code sheet can present.
Observations from retestRetest observations (Trezor Safe 7, regtest + iPhone 13, HEAD after Logs: bitkit_logs_2026-06-29_15-01-09.zip Compared to the initial testing note — previous blockers look resolved. Connect/reconnect (including fresh re-pair after forget) works end-to-end. Also exercised the rest of the QA checklist beyond connect/reconnect: watcher-driven receive while disconnected, activity list/detail with blue hardware icon, headline total including HW balance, etc. Details below. Previous issues — status
QA checklist coverage
Session timeline (from logs)
Takeaway: watch-only path is solid once xpub capture completes cleanly. Stale-pairing errors after forget are iOS BLE housekeeping, not app logic bugs. 1. fresh connect ✅First connect: 4/4 xpubs, watcher started, balance showed after ~3 s. No repeat of the Jun 25 “0 balance with partial xpubs” case. 2. forget + fresh re-pair ✅Disconnect → forget → stale pairing on old BLE UUID → fresh pairing on new path → 4/4 xpubs again. 3. auto-reconnect ✅Multiple 4. connection indicator when Bluetooth off ❌Manual test 4a (disable phone Bluetooth → indicator turns grey) — does not match Android in my retest. The green BLE badge on the Home hardware row stays green even with phone Bluetooth disabled (or device out of range). Android greys it out on disconnect.
The UI already supports grey ( Suggestion (non-blocking, but QA 4a fails without it): on peripheral disconnect or 5. watcher + receive while disconnected ✅Sent sats to a Trezor address from an external wallet while the watcher was running — received sheet popped once Electrum picked it up. Confirmed this works even with the device disconnected (watch-only / xpub watcher), which is the intended behaviour for this slice. 6. activity detail + blue hardware styling ✅HW transactions show blue icon in Home recent activity and in Activity Detail when tapped. Headline total includes HW balance while paired. Overall: looks good for merge from a functional standpoint. Broad QA coverage passes except 4a (connection-indicator grey on BT off). Either fix that or explicitly descope 4a for this PR. Just to confirm: for iOS we will only support Bluetooth and no USB, is that correct? |
@piotr-iohk correct |


This PR:
TrezorManagerfrom theTrezorViewModelgod object, adds a fully decoupledHwWalletManager, and splits the device-less on-chain calls out ofTrezorServiceinto a vendor-neutralOnChainHwService.Description
Brings the first slice of the Trezor hardware-wallet epic to the wallet home screen. A paired Trezor now shows as a watch-only balance: a device row under the Savings/Spending tiles, its sats folded into the headline total, and its on-chain transactions merged into the activity lists with a blue icon. Users with no paired device see a new Hardware suggestion card that opens an intro sheet, and a one-time pairing code is handled by an app-wide Pair Device sheet.
How it works: on connect, each device's account xpubs are captured and persisted. The watch-only layer then runs one on-chain xpub watcher per device and enabled address type, aggregates the per-device balance in memory, and persists each device's activity into bitkit-core scoped by a derived wallet id — so balances and activity stay available while the device is disconnected, and the activity lists merge hardware transactions through the normal pipeline. The same physical device re-paired is de-duplicated by its xpubs into a single tile.
Scope notes:
wallet_idto every activity. This migrates the whole app (not just hardware) to pass a wallet id through the activity APIs; the normal wallet uses the core default.deriveWalletId— the canonical cross-platform derivation finalized in core 0.3.4 — so iOS and Android produce identical ids for the same device.TrezorViewModelinto aTrezorManager, and the watch-onlyHwWalletManageris driven purely by the composition root (no manager-to-manager or service-to-viewmodel coupling). The device-less on-chain surface — Electrum account/address info, tx history/detail, compose, broadcast, and the xpub watcher — was also split out ofTrezorServiceinto a vendor-neutralOnChainHwServicebehind anOnChainWatcherServicingprotocol.HwWalletManagernow depends on no Trezor-named type;TrezorServiceis reduced to Trezor device FFI (connect, sign, on-device address/pubkey, credentials).Linked Issues/Tasks
Ports synonymdev/bitkit-android#999.
Related to #589
QA Notes
Trezor Emulator Setup
Test against the Trezor emulator from bitkit-docker:
--recurse-submodules, thendocker compose up -dand./scripts/trezor-emulator start.TREZOR_BRIDGE=trueTREZOR_BRIDGE_URL=http://127.0.0.1:21325TEST_TREZOR_EMU— that flag boots the standalone dev/test harness and bypasses the wallet.Manual Tests
regression:open Receive and other large sheets, and the normal on-chain/LN activity list and detail behave as before (wallet-scoped activity migration).Automated Checks
BitkitTests/HwWalletManagerTests.swift(aggregation, xpub dedup, displayName, merge-by-txid, received-tx detection, monitored-type filtering, watcher params, saturating total, stale-watcher, removeDevice, resetState),BitkitTests/HwWalletIdTests.swift,BitkitTests/HwAddressTypeTests.swift,BitkitTests/ActivityHardwareTests.swift.BitkitTests/TrezorViewModelWatcherTests.swiftretargeted toTrezorManagerafter the extraction; theMockWatcherServicemocks inTrezorViewModelWatcherTestsandHwWalletManagerTestsnow conform to the newOnChainWatcherServicingprotocol.BitkitTestssuite — 553/556 pass; the 3 failures are pre-existingAddressTypeIntegrationTestscases that hit the live Blocktank regtest deposit API (HTTP 404), unrelated to this change.swiftformat --lint,scripts/validate-translations.js, and a Debug build (iPhone 16 simulator) are clean.Screenshot / Video
connect-and-disconnect.mov