WebSocket client + CLI harness + pytest suite that exercises each axis of a CKBunker + Coldcard Mk4 policy and asserts the expected outcomes, including the critical negative test that a large PSBT without TOTP is rejected with a specific 'rule #1: need user(s) confirmation' reason. Configuration via .env / YAML / CLI flags, two pre-crafted test PSBTs as fixtures (generation guide in fixtures/README.md), dashboard counter scraper as sanity check, design rationale in docs/.
103 lines
3.8 KiB
Markdown
103 lines
3.8 KiB
Markdown
# Test PSBTs — how to generate them
|
|
|
|
The harness needs **two pre-crafted PSBTs**:
|
|
|
|
| Fixture | Amount | Policy path expected |
|
|
|------------------|------------------|------------------------------|
|
|
| `small.psbt` | ≤ auto-approve cap (e.g. 9,000 sats if your Rule #2 cap is 10,000) | Signs without TOTP |
|
|
| `large.psbt` | > auto-approve cap, ≤ user-auth cap (e.g. 100,000 sats) | Rejected without TOTP; signs with TOTP |
|
|
|
|
Both PSBTs must:
|
|
|
|
- be **spendable by the Coldcard** bound to your CKBunker (same seed / xpub)
|
|
- spend to **an address you control** (or a burn address — they are test
|
|
inputs, you never broadcast them)
|
|
- use a real UTXO the Coldcard can see (watch-only wallet)
|
|
|
|
---
|
|
|
|
## Method 1 — Sparrow Wallet (recommended for first-time setup)
|
|
|
|
1. In Sparrow, open or create a **watch-only wallet** loaded with your
|
|
Coldcard's xpub. (The Coldcard's HSM-Mode QR or a `coldcard.txt` export
|
|
works.)
|
|
2. Send yourself a small amount on testnet **or** signet so you have a UTXO
|
|
to spend without losing real sats. (For mainnet demos, 10k sats is
|
|
~AUD $1.)
|
|
3. Build two transactions:
|
|
- `Small demo` — pay **9,000 sats** (or 90% of your Rule #2 per-txn cap)
|
|
to any receive address in the same wallet. Sparrow → Send → *Save PSBT*
|
|
→ write to `fixtures/small.psbt`.
|
|
- `Large demo` — pay **100,000 sats** (or mid-range of your Rule #1 cap)
|
|
the same way. Save as `fixtures/large.psbt`.
|
|
4. Both PSBTs should show **Coldcard as a required signer** in Sparrow.
|
|
|
|
> Do NOT broadcast these. The harness signs them, but you verify the
|
|
> signatures in Sparrow and then discard — there's no reason to spend real
|
|
> sats on a validation run.
|
|
|
|
---
|
|
|
|
## Method 2 — bitcoind (CI / automation)
|
|
|
|
If you're wiring the harness into CI against a regtest or signet
|
|
deployment, scripting PSBT generation is a one-off:
|
|
|
|
```bash
|
|
#!/usr/bin/env bash
|
|
# Requires bitcoin-cli on PATH, pointed at a node that sees your wallet.
|
|
set -euo pipefail
|
|
|
|
WALLET="ckbunker-watch"
|
|
FEE_RATE=10 # sat/vB
|
|
|
|
recipient=$(bitcoin-cli -rpcwallet=$WALLET getnewaddress)
|
|
|
|
small_raw=$(bitcoin-cli -rpcwallet=$WALLET walletcreatefundedpsbt \
|
|
'[]' "[{\"$recipient\":0.00009000}]" 0 \
|
|
"{\"fee_rate\":$FEE_RATE}" | jq -r '.psbt')
|
|
echo "$small_raw" | base64 -d > fixtures/small.psbt
|
|
|
|
large_raw=$(bitcoin-cli -rpcwallet=$WALLET walletcreatefundedpsbt \
|
|
'[]' "[{\"$recipient\":0.00100000}]" 0 \
|
|
"{\"fee_rate\":$FEE_RATE}" | jq -r '.psbt')
|
|
echo "$large_raw" | base64 -d > fixtures/large.psbt
|
|
```
|
|
|
|
---
|
|
|
|
## Method 3 — use the same PSBT file over and over
|
|
|
|
Nothing in the harness requires the PSBT to be spendable *right now* for the
|
|
reject-path test (`test_04`). The Coldcard rejects on **amount**, not on
|
|
whether the UTXO is still unspent. So:
|
|
|
|
- `small.psbt` can be reused until the UTXO is spent elsewhere.
|
|
- `large.psbt` can be reused indefinitely — every validation run that tests
|
|
Rule #1 rejection produces a rejection regardless of UTXO state.
|
|
|
|
If you run the full suite frequently, consider crafting `large.psbt`
|
|
deliberately against an **already-spent UTXO** so the success path
|
|
(`test_05`) fails at signature verification (not policy evaluation) —
|
|
this is arguably safer than running with signable funds live.
|
|
|
|
---
|
|
|
|
## File format
|
|
|
|
Either **binary** (`psbt\xff...` magic bytes) or **base64**-encoded text is
|
|
accepted by the harness — it auto-detects via magic bytes. Sparrow exports
|
|
binary by default; bitcoin-cli returns base64.
|
|
|
|
---
|
|
|
|
## What NOT to do
|
|
|
|
- Do not commit real PSBTs to git — `.gitignore` already blocks `*.psbt` in
|
|
this directory.
|
|
- Do not use a PSBT that spends a UTXO you can't afford to move. The
|
|
harness does not broadcast, but a leaked signed PSBT *can* be broadcast
|
|
by anyone.
|
|
- Do not reuse production keys for generating fixtures — prefer testnet
|
|
or signet.
|