Skip to content

feat: add blockstream jade hardware wallet support - #1231

Draft
coreyphillips wants to merge 2 commits into
masterfrom
feat/jade-hardware-wallet
Draft

feat: add blockstream jade hardware wallet support#1231
coreyphillips wants to merge 2 commits into
masterfrom
feat/jade-hardware-wallet

Conversation

@coreyphillips

Copy link
Copy Markdown
Contributor

This PR:

  1. Adds Blockstream Jade as a second hardware wallet vendor, over USB and Bluetooth
  2. Generalises the hardware wallet layer so every device call is routed by the vendor of the paired entry
  3. Releases an open Jade Bluetooth link while Bitkit is backgrounded and reconnects silently on return

Requires bitkit-core 0.5.15, which carries the Jade module and the jade-client-rs crate.

Description

A Jade can now be paired from Connect Hardware over either transport, unlocked with its PIN, and
used exactly like a paired Trezor: watch-only balances, on-device receive address verification, and
on-device signing for both a normal send and a transfer to spending. The protocol, the pinserver
round trip and every deadline live in bitkit-core. This app supplies the byte transport over the
phone's radios and the UI that drives the flows.

The transport covers USB serial through a CP210x bridge on Jade v1 and native USB CDC on Jade Plus,
plus Bluetooth over the Nordic UART Service. Three USB device filter entries were added so Android
offers Bitkit when a Jade is plugged in.

Four things only a physical device revealed, each fixed here:

  • The TX characteristic is indicate-only on this firmware, so the transport subscribes to
    indications when notify is absent instead of failing the connection.
  • A Jade advertises under a new random Bluetooth address after every reboot or pairing reset, so a
    stored entry is recognised by name, which is Jade plus the last six hex digits of its efuse MAC,
    rather than by address.
  • A link left open when the process dies wedges the device's single connection slot until it is
    power-cycled. Links are now closed when the activity finishes, and released after 30 seconds in
    the background so the same thing does not happen when Android kills a backgrounded Bitkit. Coming
    back to the foreground reconnects without a prompt.
  • A bond that went stale across a re-pair used to stall the first write. It now gets a write budget
    wide enough to cover a re-pair, and a message telling the user to forget the Jade in Android's
    Bluetooth settings and pair again.

The vendor-neutral part is a refactor rather than new behaviour. The hardware wallet repository now
merges both vendors' discovery state, routes connect, verify and sign by the vendor stored on the
paired entry, and alternates which vendor gets the Bluetooth half of a scan so repeated searches
stay under Android's scan-rate limit. Watchers, transaction composition and broadcast are vendor
neutral already and stay where they are. Entries saved before this change carry no vendor and are
read as Trezor, so paired Trezors are untouched. Reconnect gets a longer deadline for a Jade,
because that reconnect may be waiting for a PIN to be entered on the device.

Jade-specific failures get their own copy: PIN entry, wrong PIN, an unreachable pinserver, a device
that is busy, firmware too old, a device that has no wallet yet, a network mismatch, and a PSBT the
device cannot hold.

Two gaps worth naming. The Jade illustration is a placeholder vector until design supplies the real
asset. Signet is not supported by Jade, so that combination throws rather than mapping to a network.

Preview

QA Notes

Verified against a Jade v1 on firmware 1.0.41. There is no Jade emulator in bitkit-docker, so
these are all physical-device checks.

Manual Tests

  • 1. Jade over USB → Connect Hardware → Search → Pair: PIN prompt shows on the device,
    unlock completes, accounts export and the wallet tile appears.
  • 2. regression: USB → Send → pick the Jade source → sign on device → broadcast:
    transaction confirms.
  • 3. Jade over Bluetooth → Connect Hardware → Search → Pair: pairs and unlocks.
  • 4. Bluetooth → Receive → Hardware tab → Verify on Device: the address shown on the Jade
    matches the one in the app.
  • 5. Bluetooth → Send → sign on device → broadcast: broadcast succeeded, txid
    d955bc0c....
  • 6. Bluetooth connected → background Bitkit for about 45 seconds → reopen: reconnects with
    no pairing prompt and no PIN re-entry.
  • 7. Reboot the Jade after pairing over Bluetooth → Connect Hardware: the stored entry is
    still recognised even though the device advertises a new address.
  • 8. regression: Trezor paired before this branch → open the wallet, verify an address and
    send: unchanged.

Automated Checks

  • Unit tests added: JadeTransportTest.kt covers USB driver selection, the CP210x and CDC open and
    close sequences, chunk sizing and read and write timeouts; JadeRepoTest.kt covers connect,
    unlock, replug and reconnect, recognising a Bluetooth Jade by name after its address changed, the
    background release and its USB counterpart, signing and address verification; JadeServiceTest.kt
    covers the finalizePsbt alias that used to recurse into itself; HwUsbIdTest.kt covers vendor
    detection from USB ids; KnownDeviceTest.kt covers vendor-aware entry matching, migration of
    pre-Jade entries and wallet identity; HwErrorPresenterTest.kt and HwExceptionExtTest.kt cover
    the Jade error copy and classification. The Bluetooth GATT paths themselves, including the
    indicate-only fallback, are not unit testable and were validated on hardware.
  • Unit tests modified: HwWalletRepoTest.kt, HwConnectViewModelTest.kt, HwSendViewModelTest.kt,
    HwReceiveViewModelTest.kt, TransferViewModelTest.kt, TrezorRepoTest.kt and
    ReceiveInvoiceUtilsTest.kt move onto the vendor-neutral device state and the per-vendor routing.
  • Local: just compile, just test (2350 tests, 0 failures) and just lint all pass.

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.

1 participant