web3.path

PHASE 25 Bitcoin wallet systems · 20–32 hours

Bitcoin Wallet & Transaction Engineering

A wallet is a policy engine, a key boundary, and a transaction-construction system. An address list is not a wallet design.

Goal — construct, inspect, sign, finalize, broadcast, replace, and recover descriptor-driven PSBTs without putting a seed phrase in an application server.

1. Descriptor-first wallet model

Use descriptors to represent spending policy and derivation, then derive addresses from that policy. Learn BIP-32 HD derivation, BIP-39 seed handling, BIP-84 native SegWit, BIP-86 Taproot, and why xpub exposure leaks wallet structure even though it cannot sign.

# Inspect descriptors and wallet state on regtest.
btc -rpcwallet=lab listdescriptors
btc -rpcwallet=lab getnewaddress "receive" bech32
btc -rpcwallet=lab listunspent 1 9999999 '[]' true
btc -rpcwallet=lab getaddressinfo "$ADDR"

Know P2WPKH, P2WSH, P2TR, Bech32/Bech32m, witness data, virtual size, and fee units. Build Script understanding around actual spending conditions; do not hand-roll serialization/signatures in a production system.

2. PSBT workflow

# Core can construct a funded PSBT; inspect before signing.
PSBT=$(btc -rpcwallet=lab walletcreatefundedpsbt \
  '[]' '[{"bcrt1...":0.001}]' 0 '{"replaceable":true,"fee_rate":2}')
echo "$PSBT" | jq -r .psbt | base64 -d > tx.psbt
btc decodepsbt "$(echo "$PSBT" | jq -r .psbt)"

# A separate signer owns keys. Finalize only after policy checks.
SIGNED=$(btc -rpcwallet=signer walletprocesspsbt "$(echo "$PSBT" | jq -r .psbt)")
FINAL=$(btc finalizepsbt "$(echo "$SIGNED" | jq -r .psbt)")
btc testmempoolaccept "[\"$(echo "$FINAL" | jq -r .hex)\"]"
Review before signingWhy
Inputs and UTXO ownershipprevents unexpected wallet/policy use
Recipient scripts and amount in satsprevents address/amount substitution
Change output classificationprevents accidental overpayment or change theft
Fee, vbytes, sat/vB, RBF sequencecontrols cost and future replacement ability
Locktime, sighash, derivation/policy metadataensures signing commits to the intended transaction

3. Fee and mempool operations

3b. Package relay & air-gapped signing

4. Practical lab — 2-of-3 treasury with recovery

Deliverable
  1. Create a 2-of-3 descriptor with an additional timelocked recovery path on regtest. Keep signers in separate wallet processes or hardware emulators.
  2. Fund it, create a PSBT with recipient/change/RBF policy, independently decode it, sign with two participants, test acceptance, broadcast, and mine it.
  3. Build an approval CLI/API that refuses unknown descriptors, excessive fee rates, non-whitelisted policy changes, and missing human-readable transaction review.
  4. Run a recovery drill: restore only from documented descriptors/backups, derive the same UTXOs, then spend through the recovery branch after advancing regtest time/blocks.
  5. Test an RBF replacement, CPFP child, dust rejection, malformed PSBT, wrong-network address, and unavailable signer.

Lab repo: labs/phase-25-bitcoin/scripts/regtest-setup.sh + air-gap drill.

← Phase 24Phase 26: Lightning Engineering & Capstone →