feat: transfer to spending from hw wallet#1039
Conversation
722a6bd to
455eb68
Compare
Observations from initial testingBelow I attach AI analysis of the issues: HW transfer to spending — QA analysis 1. transfer from Trezor 7 connected via BLE
Screen_Recording_20260623_120550_Bitkit.Regtest.mp42. transfer from Trezor 7 connected via USB
Screen_Recording_20260623_130312_Bitkit.Regtest.mp4Attaching logs from the session: In general it looks that there is a lot of "reconnect" errors - especially on connection via BLE. Other observations:
Screen.Recording.2026-06-23.at.11.59.26.movHW transfer to spending — QA analysisSession logs: Cross-checked manual testing observations against logs and the #1039 transfer flow. Verdict overview
1. BLE — “Reconnect Hardware Device” after MAXLogs: Four failed MAX attempts used clientBalanceSat ≈ 1,661,647 (not ~90k). Failures are:
All timeouts surface the same “Reconnect Hardware Device” toast, even though BLE was still active (244-byte TX/RX right before timeout). Successful BLE transfer: 25% order (415,412 sats) at 09:33 — tx Recommendations
Also saw a real BLE failure: 2. MAX ~90k with large Trezor balanceExpected, not a Trezor balance bug. MAX is capped by Blocktank total channel liquidity, not Trezor balance. Formula subtracts existing Blocktank channel capacity from LSP Logs: USB success at 10:17 — Trezor ~1.68M, transfer 90,278 sats ( Recommendations
3. USB — two ~90k MAX, then MAX = 0Expected after ~415k (BLE) + 2× ~90k (USB) ≈ ~1.6M of ~1.74M cap. Sending from spending balance does not reduce 4. “Insufficient funds” after closing channelsBug — misleading MAX, not empty Trezor. After coop-close, snapshot shows 0 channels, 483k on-chain swept, Trezor watcher still ~1.5M. UI offered MAX with clientBalanceSat ≈ 1,498,181. Logs (11:01:54):
MAX is derived from watcher total balance and client amount; signing pays Recommendations
5. Trezor “Transfer” activities stuck “In Transfer”Confirmed bug. Successful HW paths log RecommendationWhen watcher reports PR #1039 — suggested gateBlockers before merge
Polish (non-blocking but worth tracking)
Looks correct / expected
Log references (for dev follow-up)
|
Thanks Piotr, I pushed fixes for the issues you identified in the first round of early validation. This now:
Validation video: MAX transfer max2x.mp4Resolved in 2ecf4d1 |
This comment has been minimized.
This comment has been minimized.
QA re-test — HW transfer to spending (2026-06-24)Build: 2.3.0 (182) · Samsung S22, Android 16 · regtest · Trezor Safe 7 What I tested
ResultStable — no sign timeouts, no insufficient-funds on MAX, no THP failures on successful paths (major improvement vs 2026-06-23 session). Minor UX (non-blocking)On the HW sign screen, tapping “Open Trezor Connect” sometimes results in red “Reconnect Hardware Device” toast when device is locked / connection in progress — usually fixed by unlocking Trezor, not re-pairing. Logs: Out of scope for this PR (filed separately)
VerdictApprove for HW transfer-to-spending scope. Manual coverage is sufficient for merge; follow-ups are tracked issues + toast polish. |
Fixed by routing first-time hardware-wallet transfer-to-spending through the same shared I also checked the supplied Figma HW frames: they start at the HW Amount screen and do not define a separate HW intro, so this reuses the existing generic spending intro. Resolved in d9a5314 |
piotr-iohk
left a comment
There was a problem hiding this comment.
Re-approve after SpendingIntro fix.


Closes #1028
Refs #998
Refs #1029
This PR adds the watch-only hardware-wallet Transfer to Spending flow for funding a Lightning channel from a paired Trezor with the on-chain transaction signed on the device. Built on top of #1033.
Description
order.feeSatand the composed on-chain mining fee, while respecting the LSP receiving-cap limit.Figma Designs:
Preview
hwtransfer2x.mp4
max2x.mp4
QA Notes
Verified the original happy path end-to-end on an Android Pixel Phone against Trezor Bridge and a physical Trezor Safe 7 on regtest: the funding tx was signed on-device, broadcast, and the channel opened, moving the entered amount into the spending balance.
Additional Trezor Dev Bridge validation after Piotr's first-round review covered MAX, watcher confirmation, actual mining-fee persistence, and balance behavior around the paid-order/in-transfer phase. Trezor Dev Bridge signed and broadcast tx
7da3bf70153d47d1c1075ceb248b15c561ba5454c8a0d501d89877fec7cb17fa, then mined it to 6 confirmations. The transfer activity row endedconfirmed=1,value=43045,fee=141,fee_rate=1, andis_transfer=1.Hosted staging Blocktank validation covered the final paid-order → pending-channel → ready-channel transition using the LSP regtest API. Order
3e24ba9c-43d3-4b44-acbd-c8cf1c42ade4moved topaid, thenexecuted; channela2ed4674668e74a92e55cf7e4780a13dadafbd81acd6a6d6e8f39d80b7856d4bbecame ready from funding outpoint4b6d85b7809df3e8d6a6d6ac81bdafad3da180477ecf552ea9748e667446eda2:0. The app persisted that channel for the active transfer, marked the HW activity as transfer metadata for that channel, settled the transfer, and the final balance state showedbalanceInTransferToSpending=0withtotalLightningSats=562194.Manual Tests
order.feeSat, and the wallet spends onlyorder.feeSat + composed mining fee.order.feeSat + composed mining fee: signing is blocked with the insufficient-funds state instead of broadcasting.Automated Checks
ActivityRepoTest.kt: watcher confirmations update existing hardware-wallet transfer activities while preserving transfer metadata.ContentViewTest.kt: first-time hardware-wallet transfer-to-spending starts at SpendingIntro, preserves the hardware device id for the HW amount route, and skips the intro once it has been seen.DeriveBalanceStateUseCaseTest.kt: active hardware-wallet transfers are not double-counted when LDK exposes the pending channel before Blocktank order metadata catches up.HwWalletRepoTest.kt: native-segwit funding balance is tracked separately from aggregate hardware-wallet balance, and hardware-wallet funding compose/sign/broadcast returns and persists the composed mining fee, fee rate, and total spent.TransferRepoTest.kt: paid-order/channel lookup handles hardware-wallet funding transaction outpoints during settlement transitions.TransferViewModelTest.kt: HW MAX/available math, fee-estimator fallback reserve, fallback compose fee rate, finalorder.feeSatfunding, reconnect-on-disconnect, stale-session cleanup on signing timeout, and sign/broadcast error states.TrezorRepoTest.kt: reconnect/session handling around hardware-wallet signing, reconnect cancellation propagation withisConnectingcleanup, and reset fully disconnects connected transport sessions.TrezorBridgeTransportTest.kt: Bridge/call/{session}uses the longer signing read timeout while management/non-signing requests keep the shorter timeout, and Bridge HTTP calls honor the selected timeout.transfer-to-spending.xmltransfer-to-spending-max-lsp-cap.xmltransfer-to-spending-node-warmup.xmldetail-overview.xml7da3bf70153d47d1c1075ceb248b15c561ba5454c8a0d501d89877fec7cb17fa, mined 6 blocks, verified activity confirmation and actual fee persistence, and confirmed total balance moved only by Blocktank fees plus the 141 sat composed mining fee../lsp POST /regtest/chain/deposit,./lsp POST /regtest/chain/mine, and./lsp POST /channels/:id/opento drive the paid → executed → ready-channel transition, then verified the app settled the active transfer and removed the in-transfer balance.just test file ContentViewTest,just test file TransferViewModelTest,just test file DeriveBalanceStateUseCaseTest,just test file TrezorRepoTest,just compile,just test,just lint.