feat: add trezor send - #688
Conversation
Greptile SummaryThis PR integrates paired Trezor wallets into normal on-chain send and receive flows and hardens session recovery and hardware activity reconciliation.
Confidence Score: 3/5The PR should not merge until pending hardware activity survives process recreation and timeout cleanup can no longer tear down a retry’s newly established Trezor session. A restart can remove a just-broadcast hardware activity before Electrum observes it, while an immediate retry after a device timeout can race delayed stale-session cleanup and lose the replacement connection. Files Needing Attention: Bitkit/Services/CoreService.swift, Bitkit/Services/HwSnapshotMerge.swift, Bitkit/ViewModels/HwFundingSigner.swift, Bitkit/Managers/TrezorManager.swift
|
| Filename | Overview |
|---|---|
| Bitkit/ViewModels/HwFundingSigner.swift | Generalizes hardware signing for ordinary sends and adds non-structural timeouts, but asynchronous stale-session cleanup can race an immediate retry. |
| Bitkit/Managers/TrezorManager.swift | Serializes connection operations and retries stale sessions, while the separate reset path remains able to clear newer connection state. |
| Bitkit/Services/CoreService.swift | Protects newly broadcast hardware activity from watcher pruning, but stores the protection only in process memory. |
| Bitkit/Services/HwSnapshotMerge.swift | Preserves pending sends and contact metadata when supplied the pending-ID set, but intentionally prunes unprotected pending rows. |
| Bitkit/Managers/HwWalletManager.swift | Adds hardware receive-address derivation and verification plus funding-source balance support. |
| Bitkit/Views/Wallets/Send/SendSheet.swift | Integrates hardware source selection and signing routes throughout the existing send lifecycle. |
| Bitkit/Views/Wallets/Receive/ReceiveQr.swift | Adds Trezor receive QR, copy, device verification, and passphrase recovery states. |
Sequence Diagram
sequenceDiagram
participant User
participant Send as Send Flow
participant HW as Hardware Wallet Manager
participant Trezor
participant Electrum
participant Activity
User->>Send: Select Trezor funding source
Send->>HW: Compose payment and estimate fee
HW->>Electrum: Load account and UTXOs
Electrum-->>HW: Account state
Send->>HW: Sign and broadcast
HW->>Trezor: Verify identity and sign PSBT
Trezor-->>HW: Signed transaction
HW->>Electrum: Broadcast transaction
Electrum-->>HW: Transaction ID
Send->>Activity: Persist wallet-scoped sent activity
Send-->>User: Show success
Reviews (1): Last reviewed commit: "feat: add trezor send and receive" | Re-trigger Greptile
8a8ae72 to
2c2869a
Compare
|
Testing... (note: there are conflicts on this branch) |
piotr-iohk
left a comment
There was a problem hiding this comment.
Quick pass on device: standard HW send, passphrase HW send, and cancel-during-sign all worked. Not a full review — branch is conflicting, so not approving.
Nit: pending sent rows already use the hourglass, but it's orange even for HW. That branch runs before the blue HW tint, so a pending Trezor send is orange in the list and blue once it's no longer in that pending-sent rule. Figma has the hourglass (this and this) in brand/orange. For HW it would be more consistent to keep the hourglass and tint it blue, same as the rest of the hardware chrome.
2c2869a to
28be38a
Compare
ovitrif
left a comment
There was a problem hiding this comment.
Nothing would fail if HwSendCoordinator stopped reusing a signed payment after a flaky broadcast, or ran beforeBroadcast again on retry.
|
|
||
| let signer = Self.signer(manager: manager, address: address, satsPerVByte: satsPerVByte) | ||
| let signed: HwFundingSignedTx | ||
| if let pendingPayment, pendingPayment.request == request { |
There was a problem hiding this comment.
I walked HwSendCoordinator.signAndBroadcast and the unit suite never hits this recovery path. HwFundingSignerTests covers compose, sign, broadcast, timeout, and session retry, and the two new coordinator cases only assert selectWallet / seedAvailable. Nothing would fail if we stopped reusing pendingPayment after a successful sign, cleared it on .broadcastUncertain or a connectivity failure, or ran beforeBroadcast again on retry. Those branches are what keep a signed hardware payment from being thrown away or a contact prepare from running twice after a flaky broadcast. Could we add coordinator tests that hold a signed PendingPayment, fail broadcast as .broadcastUncertain and as a connectivity error, then assert retry reuses pendingPayment.signedTx and invokes beforeBroadcast only once?
There was a problem hiding this comment.
Fixed in 2f872cd. Added coordinator tests for both .broadcastUncertain and connectivity failures. They verify retry broadcasts the retained signed transaction without recomposing or resigning, and that beforeBroadcast runs only once. The focused HwFundingSignerTests suite passes with 22 tests.
Description
This PR:
The Send UI follows the Bitkit Wallet design.
Receive support will follow in a separate stacked PR.
Linked Issues/Tasks
N/A
Screenshot / Video
QA Notes
Manual Tests
regression:Send → switch between Savings, Spending, and Trezor: available balance and fee-aware maximum update for each source.regression:cancel or disconnect during signing → retry: Bitkit reconnects without creating or broadcasting a duplicate transaction.Automated Checks
HwFundingSignerTests.swiftandTrezorSessionFailureTests.swift: cover source coordination, timeouts, stale-session retry, retained signed transactions, and failure classification.HwSnapshotMergeTests.swift: cover pending sent activity and contact preservation during watcher reconciliation.ShopPaymentRequestTests.swift: cover hardware-wallet on-chain-only scan handling.