Sweep Bitcoin addresses across hardware wallets, hot wallets, and paper wallets into a single transaction using PSBTs (BIP 174).
This tool lets multiple wallet holders collaborate on a single Bitcoin transaction. Each person contributes UTXOs as inputs, signs their portion independently, and the results are combined into a finalized transaction ready for broadcast.
- Create -- Add inputs (UTXOs) from multiple wallets by address or xpub, set outputs and fee, then download the unsigned PSBT or display it as a QR code
- Sign -- Each wallet holder signs the PSBT with their own wallet (hardware wallet, Bitcoin Core, hot wallet, or paper wallet)
- Combine & Finalize -- Upload all signed PSBTs, the tool merges signatures and produces the raw transaction
- Broadcast -- Send the finalized transaction to the Bitcoin network via mempool.space
| Approach | How it works | Upload |
|---|---|---|
| Parallel | Each party independently signs a copy of the unsigned PSBT | Upload all signed copies |
| Serial | Party A signs, passes to B, B signs, passes to C... | Upload the single final file |
Both approaches work through the same Combine & Finalize step.
- Fetch UTXOs by address, extended public key (xpub/zpub/vpub/tpub/ypub/upub), or WIF private key from mempool.space (or local regtest server) -- xpub input auto-derives P2WPKH and/or P2TR addresses and scans receive + change chains with BIP44 gap limit; WIF input derives both P2WPKH and P2TR addresses and fetches UTXOs from both
- Inline signing for hot/paper wallets -- when all UTXOs have WIF private keys, signs and finalizes the transaction in-browser without needing external signing tools, going straight from Create to Broadcast
- Fee rate presets pulled live from the network (fast/medium/slow), with estimated fee and available sats display
- Optional tip with preset percentages (0.99%, 0.5%, 0.1%) and per-network donation addresses -- included as a PSBT output only when sats > 0
- Output percentage labels showing each output's share of total input, with a Wipe option to sweep remaining balance
- QR code display using BBQr protocol for air-gapped signing with hardware wallets like Coldcard Q (auto-splits large PSBTs into animated multi-part QR sequences)
- QR code scanning to upload signed PSBTs from hardware wallets via camera, with BBQr multi-part support and progress bar -- combine QR-scanned and file-uploaded PSBTs from different sources
- Hardware wallet support with BIP32 derivation paths, master fingerprint input (per xpub source, auto-propagated to all UTXOs), and xpub auto-derivation of compressed public keys (supports xpub/ypub/zpub/vpub/tpub/upub formats via SLIP-132 normalization)
- CLI signing tool (
tools/sign-psbt.py) for hot wallet signing with WIF keys - Network auto-selection -- Mainnet on GitHub Pages, Testnet4 on local static server, Regtest with regtest server
- Network support for Mainnet, Testnet4, and Regtest
- Step indicator wizard with dynamic step flow -- adapts between 2-step (Create → Broadcast) and 4-step (Create → Sign → Combine → Broadcast) modes based on whether WIF keys are present
- Guided workflow with brief instructions under each step
- No server required -- runs entirely in the browser on GitHub Pages
- Regtest mode with a local Python server for development and testing
Visit the live demo -- no installation needed.
Requires Bitcoin Core (bitcoind + bitcoin-cli).
# Start the regtest server (launches bitcoind, mines initial blocks)
python3 server/server.py 8000 --regtest
# Open in browser
open http://localhost:8000/index.htmlThe server provides a faucet and auto-mining, and exposes mempool.space-compatible API endpoints so the frontend works identically across all networks.
# Unit tests -- index.html, 194 tests, no bitcoind needed (~15s)
python3 tests/test_psbt_builder.py
# E2E regtest tests -- 148 tests, requires bitcoind + bitcoin-cli (~120s)
# Covers P2WPKH + P2TR (Taproot), parallel + serial signing,
# WIF fetch + inline signing, and mixed WIF partial signing
python3 tests/test_regtest_e2e.py
# Coldcard simulation tests -- 44 tests, requires bitcoind + embit (~120s)
# Simulates Coldcard signing via bitcoin-cli walletprocesspsbt
python3 tests/test_coldcard_simulation.py
# Real Coldcard MK4 regtest tests -- 28 tests, requires Coldcard + ckcc + bitcoind + embit
# User approves transaction on the Coldcard when prompted
python3 tests/_test_coldcard_regtest.py
# Real Coldcard MK4 testnet4 tests -- 25 tests, requires Coldcard + ckcc + embit
# Builds mixed WIF+CC PSBT, signs via ckcc, broadcasts to testnet4
python3 tests/_test_coldcard_testnet4.py
# Website + Coldcard E2E tests -- 23 tests, requires Coldcard + ckcc + Playwright
# Full browser flow: fetch UTXOs, set HW info, create/sign/combine/broadcast
python3 tests/_test_coldcard_website_e2e.py
# E2E testnet4 tests -- 27 tests, requires funded testnet4 wallet (~30s)
# Parallel + serial signing with real testnet4 transactions
python3 tests/test_testnet4_e2e.py
# E2E with visible browser
python3 tests/test_psbt_builder.py --headed
python3 tests/test_regtest_e2e.py --headed
python3 tests/test_testnet4_e2e.py --headed
# Recover funds from a failed testnet4 test run
python3 tests/test_testnet4_e2e.py --recoverThe testnet4 E2E test needs a pre-funded wallet. Provide credentials via:
- Environment variables:
TESTNET4_WIFandTESTNET4_ADDRESS - CLI arguments:
--wifand--address - settings.json in project root:
{"TESTNET4_WIF": "c...", "TESTNET4_ADDRESS": "tb1q..."}
Fund the wallet at the testnet4 faucet.
For hot wallet signing without Bitcoin Core:
pip install embit
python3 tools/sign-psbt.py unsigned.psbt <WIF-private-key>
# Outputs: unsigned-signed.psbtColdcard Q auto-finalizes P2WPKH inputs as P2PKH via QR: When the Coldcard Q receives a PSBT via QR where all inputs have partial_sigs, it auto-finalizes and outputs a raw transaction. It incorrectly places P2WPKH witness signatures in scriptSig (P2PKH-style), causing "Witness requires empty scriptSig" on broadcast. USB signing (ckcc sign) does not have this issue. Workaround: WIF inputs are left unsigned at PSBT creation and signed in the browser during the combine step after the Coldcard returns its signed PSBT. Firmware: v1.4.0Q.
ckcc addr blocks the Coldcard: ckcc addr returns the address to the CLI immediately but displays it on the Coldcard screen, blocking USB until the user dismisses it. The Coldcard tests avoid this by using ckcc pubkey and deriving the address locally via embit.
- Python 3
- Playwright:
pip install playwright && playwright install chromium - embit:
pip install embit(fortools/sign-psbt.pyand Coldcard tests) - ckcc-protocol:
pip install ckcc-protocol(for real Coldcard MK4 tests only) - Bitcoin Core v30+ (for regtest E2E tests only)
- Frontend:
index.html(sweeper) +donate.html, no build step - JS Libraries (loaded via CDN/esm.sh): bitcoinjs-lib v7.0.0-rc.0, bip32 v4.0.0, bs58check v3.0.1, ecpair v3.0.0, bbqr, jsQR
- QR Generator: Custom
qr_generator.js(shared with bitcoin-gift-paper-wallet) - Dev Server: Python stdlib (
http.server) + Bitcoin Core RPC - Tests: Playwright (Python sync API)
Building and maintaining open-source Bitcoin tools takes time, caffeine, and compute. If you find this project useful, consider buying me a coffee — with Bitcoin!
bc1qrfagrsfrm8erdsmrku3fgq5yc573zyp2q3uje8
This address was generated using ₿itcoin Gift Paper Wallet
Your donation helps cover the cost of Claude (the AI that helped build this), keeps the coffee flowing, and fuels development of more open-source Bitcoin tools. No VC funding, no ads, no tracking — just open-source code and generous supporters like you.
This project is provided as-is, without warranty of any kind. The author is not responsible for any loss of funds from transactions created with this tool. Always verify addresses, amounts, and fees before signing and broadcasting.