- Added new dependencies: `adler2`, `crc32fast`, `flate2`, `miniz_oxide`, and `libredox`. - Updated existing dependencies: `tokio-rustls` to version 0.26.4 and `filetime` to version 0.2.27. - Removed the `backup.rs` file as it is no longer needed. - Introduced tests for configuration and credential management. - Enhanced the `identity` module to generate W3C compliant DID documents. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.2 KiB
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
{
"method": "lnd.create-psbt",
"params": {
"outputs": [{"address": "bc1q...", "amount_sats": 50000}],
"fee_rate_sat_per_vbyte": 10,
"change_address": "bc1q..."
}
}
Response:
{
"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
{
"method": "lnd.finalize-psbt",
"params": {
"signed_psbt_base64": "cHNidP8BAH..."
}
}
Response:
{
"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:
// 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
- PSBT verification: Display transaction details (amounts, addresses, fees) before and after hardware signing — user should verify they match
- 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
- PSBT size limits: QR codes can handle ~2KB; larger PSBTs need animated QR (BBQr) or file transfer
- USB permissions: The
archipelagouser needs access to USB HID devices (udevrules)
Implementation Priority
- Phase 1 (HW-02): PSBT create/finalize RPC endpoints via LND gRPC
- Phase 2 (HW-03): QR code display + file upload UI
- Phase 3 (HW-04): USB device detection and notification
- Future: Direct USB HID communication (trezorlib, ledger-transport)
Dependencies
- LND v0.18+ (PSBT API via WalletKit)
qrcodenpm package (QR generation in UI)lsusbor/sys/bus/usb/access (device detection)- No external hardware wallet libraries needed for Phase 1-3 (PSBT is a standard format)