# Hardware Wallet Integration Architecture ## Overview Archipelago supports hardware wallets for secure Bitcoin transaction signing via PSBT (Partially Signed Bitcoin Transactions). This document covers integration with ColdCard, Trezor, and Ledger hardware wallets. ## Supported Devices | Device | Connection | PSBT Support | DID Signing | Detection | |--------|-----------|-------------|-------------|-----------| | ColdCard Mk4 | USB / MicroSD / NFC | Native PSBT | No (Bitcoin-only) | USB VID `0xd13e` | | Trezor Model T/Safe 3 | USB / WebUSB | Via trezorctl | No | USB VID `0x534c` (SatoshiLabs) | | Ledger Nano S/X/Plus | USB / Bluetooth | Via HWI | No | USB VID `0x2c97` | ## Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ Archipelago Node │ │ │ │ ┌──────────┐ ┌────────────┐ ┌──────────────────────────┐ │ │ │ Web UI │───▸│ RPC Server │───▸│ LND (gRPC) │ │ │ │ │ │ │ │ - FundPsbt │ │ │ │ QR code │ │ lnd.create │ │ - SignPsbt (partial) │ │ │ │ display │ │ -psbt │ │ - FinalizePsbt │ │ │ │ │ │ │ │ - PublishTransaction │ │ │ │ File │ │ lnd.final │ └──────────────────────────┘ │ │ │ upload │ │ ize-psbt │ │ │ └──────────┘ └────────────┘ │ │ ▲ │ │ │ PSBT (base64) │ │ ▼ │ │ ┌──────────────────────┐ │ │ │ Hardware Wallet │ │ │ │ - USB direct │ │ │ │ - QR code scan │ │ │ │ - MicroSD (CC) │ │ │ └──────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## PSBT Signing Flow ### 1. Create Unsigned PSBT The user initiates a transaction (send coins, open channel, close channel). Instead of LND signing automatically, we create an unsigned PSBT. **RPC endpoint**: `lnd.create-psbt` ```json { "method": "lnd.create-psbt", "params": { "outputs": [{"address": "bc1q...", "amount_sats": 50000}], "fee_rate_sat_per_vbyte": 10, "change_address": "bc1q..." } } ``` **Response**: ```json { "psbt_base64": "cHNidP8BAH...", "psbt_hex": "70736274ff...", "estimated_fee_sats": 1420, "inputs": [{"txid": "abc...", "vout": 0, "amount_sats": 100000}], "outputs": [{"address": "bc1q...", "amount_sats": 50000}, {"address": "bc1q...", "amount_sats": 48580}] } ``` **LND gRPC mapping**: Uses `WalletKit.FundPsbt` to select UTXOs and create the PSBT template. ### 2. Sign with Hardware Wallet Three transfer methods supported: #### QR Code (ColdCard NFC, Trezor via companion app) - Display PSBT as animated QR code (BBQr format for large PSBTs) - User scans with hardware wallet - Hardware wallet displays transaction details for verification - User confirms on device - Signed PSBT returned as QR code — user scans with camera or uploads screenshot #### USB Direct (Trezor, Ledger) - Detect hardware wallet USB device - Pass PSBT via USB HID protocol - User confirms on device - Signed PSBT returned via USB #### MicroSD (ColdCard) - Export PSBT file for download - User transfers to ColdCard via MicroSD - ColdCard signs and saves signed PSBT to MicroSD - User uploads signed PSBT file back to Archipelago ### 3. Finalize and Broadcast **RPC endpoint**: `lnd.finalize-psbt` ```json { "method": "lnd.finalize-psbt", "params": { "signed_psbt_base64": "cHNidP8BAH..." } } ``` **Response**: ```json { "txid": "abc123...", "raw_tx_hex": "0200000001...", "broadcast": true } ``` **LND gRPC mapping**: Uses `WalletKit.FinalizePsbt` then `WalletKit.PublishTransaction`. ## USB Device Detection **RPC endpoint**: `system.detect-usb-devices` Scans `/sys/bus/usb/devices/` or uses `lsusb` to detect known hardware wallet vendor IDs: | Vendor | VID | Product IDs | |--------|-----|-------------| | ColdCard (Coinkite) | `0xd13e` | `0xcc10` (Mk4), `0xcc20` (Q) | | Trezor (SatoshiLabs) | `0x534c` | `0x0001` (One), `0x0002` (T) | | Ledger | `0x2c97` | `0x0001` (Nano S), `0x0004` (Nano X), `0x0005` (Nano S+) | Implementation approach: ```rust // Read from /sys/bus/usb/devices/*/idVendor and idProduct async fn detect_usb_devices(known_vids: &[(u16, &str)]) -> Vec { // Parse /sys/bus/usb/devices/X-Y/idVendor // Match against known VIDs // Return device list with type identification } ``` The detection runs server-side since the hardware wallet is plugged into the Archipelago node (not the browser). ## UI Integration Points ### Send Coins View - Add "Sign with Hardware Wallet" toggle/option - When enabled: create unsigned PSBT → show QR/download → accept signed PSBT → finalize ### Channel Management - Open Channel: PSBT funding option - Close Channel: Cooperative close via PSBT ### Hardware Wallet Status - Show notification banner when USB device detected - Display device type and connection status - Auto-detect on the Server/Dashboard page ## Security Considerations 1. **PSBT verification**: Display transaction details (amounts, addresses, fees) before and after hardware signing — user should verify they match 2. **No private keys on node**: When using hardware wallet flow, LND's internal wallet creates watch-only inputs; the hardware wallet holds the actual signing keys 3. **PSBT size limits**: QR codes can handle ~2KB; larger PSBTs need animated QR (BBQr) or file transfer 4. **USB permissions**: The `archipelago` user needs access to USB HID devices (`udev` rules) ## Implementation Priority 1. **Phase 1** (HW-02): PSBT create/finalize RPC endpoints via LND gRPC 2. **Phase 2** (HW-03): QR code display + file upload UI 3. **Phase 3** (HW-04): USB device detection and notification 4. **Future**: Direct USB HID communication (trezorlib, ledger-transport) ## Dependencies - LND v0.18+ (PSBT API via WalletKit) - `qrcode` npm package (QR generation in UI) - `lsusb` or `/sys/bus/usb/` access (device detection) - No external hardware wallet libraries needed for Phase 1-3 (PSBT is a standard format)