archy/docs/hardware-wallet-integration.md

180 lines
7.2 KiB
Markdown
Raw Normal View History

# 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<DetectedDevice> {
// 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)