Bitcoin Wallet & UTXO Privacy/Fee Hygiene Auditor — Find the dust, address reuse and fee waste hiding in your UTXO set.
Audit any Bitcoin mainnet address you own (legacy P2PKH, nested SegWit, native SegWit, Taproot): count and bucket every UTXO, find stranded inputs that cost more to spend than they are worth, detect address reuse, dusting attacks and Ordinals-inscription UTXOs you must not sweep, measure common-input-ownership privacy leaks, and get a consolidation cost-vs-savings matrix plus copy-paste bitcoin-cli / Sparrow / Electrum coin-control commands to run in your own wallet.
SKU: btc-utxo-hygiene · Skills: btc-utxo-hygiene-setup + btc-utxo-hygiene · Tested: 1,242 lines stdlib Python, 157 unit tests · Category: Bitcoin / Wallet Hygiene
What It Does
- Validates one or more Bitcoin mainnet addresses (Base58Check, Bech32 BIP-173, Bech32m BIP-350) and reads public state from the Mempool.space REST API with Blockstream Esplora fallback, or from an
--offlinefixture: address stats, the full UTXO set, recent transactions, fee estimates, mempool blocks and BTC/USD price. - UTXO hygiene: value buckets,
UTXO_FRAGMENTATION,STRANDED_UTXOS(strictvalue ≤ input vB × rateand a conservative margin via--min-value-multiple),LEGACY_SCRIPT_TYPE,DUSTING_ATTACK_SUSPECT, and a creating-transaction witness scan that marks Ordinals-inscription UTXOs asINSCRIPTION_PROTECTEDso they are never swept. - Fee planning: a consolidation plan and cost-vs-savings matrix for P2WPKH or P2TR outputs (
--consolidate-to) at current and window fee rates, with break-even future fee rate and aCONSOLIDATION_WINDOW_OPENsignal (--window-rate,--target-fee). - Privacy exposure from recent transactions:
ADDRESS_REUSE,CIOH_COSPEND_EXPOSURE,CIOH_CROSS_ADDRESS_LINK,ROUND_NUMBER_CHANGE_LEAKandSCRIPT_TYPE_MISMATCH_CHANGE, plus a 0–100 hygiene score per address and per wallet. - Non-custodial coin control: freeze/do-not-spend outpoints (
bitcoin-cli lockunspent, Sparrow “Freeze UTXO”, Electrum “Freeze Coin”) and an unsigned-PSBTbitcoin-cli sendall ... psbt=trueconsolidation command, displayed for you to run yourself. - Stateful delta monitor (
--state PATH --delta): emitsNEW_DUST,UTXO_COUNT_CHANGEDandCONSOLIDATION_WINDOW_OPENevents between runs, with--format text|markdown|jsonoutput and exit codes 0 clean / 1 MEDIUM / 2 HIGH / 3 CRITICAL / 10 bad input / 11 degraded sources. 1,242 lines stdlib Python, 157 passing unit tests.
Live output (Bitcoin mainnet: one public legacy P2PKH address, 134 UTXOs)
Sample disclosure: this is a representative sample, not a customer report. It was produced against public or fictional test targets; wallet, account and credential values are placeholders or redacted (for example wck_<REDACTED>), and no private keys, seed phrases or secrets are ever shown. Your own report will differ in content and length.
snapshot 2026-10-27 10:00:58 UTC | tool=btc-utxo-hygiene endpoints https://blockstream.info/api, https://mempool.space/api fallbacks https://mempool.space/api failed -> https://blockstream.info/api wallet 1 address(es) utxos=134 (confirmed 134 / unconfirmed 0) total=44,408,175 sats (0.44408175 BTC, $35,340.47) hygiene_score=45/100 address 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S P2PKH utxos=134 balance=44,408,175 funded_txo=134 spent_txo=0 tx_count=131 score=45 fees fastestFee=2 halfHourFee=1 hourFee=1 economyFee=1 minimumFee=1 sat/vB (mempool.space) | blockstream 504-block floor=0.113 bucket <=546 (hard dust / inscription-suspect) count= 26 sum= 13,651 bucket 547-1,000 (sub-1k micro) count= 29 sum= 21,587 bucket 1,001-5,000 count= 18 sum= 29,863 bucket 5,001-100,000 count= 54 sum= 1,483,555 bucket >100,000 count= 7 sum= 42,859,519 stranded (strict: value <= input_vB*rate; conservative: x3 margin) fastestFee 2 sat/vB strict= 1 (1 sats) conservative= 46 (26,327 sats) halfHourFee 1 sat/vB strict= 1 (1 sats) conservative= 1 (1 sats) hourFee 1 sat/vB strict= 1 (1 sats) conservative= 1 (1 sats) economyFee 1 sat/vB strict= 1 (1 sats) conservative= 1 (1 sats) minimumFee 1 sat/vB strict= 1 (1 sats) conservative= 1 (1 sats) ref 5 5 sat/vB strict= 44 (24,677 sats) conservative= 72 (62,521 sats) ref 10 10 sat/vB strict= 58 (39,139 sats) conservative= 73 (65,101 sats) ref 20 20 sat/vB strict= 73 (65,101 sats) conservative= 81 (112,673 sats) ref 50 50 sat/vB strict= 81 (112,673 sats) conservative= 95 (284,500 sats) ref 100 100 sat/vB strict= 93 (245,591 sats) conservative= 116 (772,545 sats) scan creating-tx witness check on 60 txid(s) (UTXOs <= 10,000 sats, cap 60): envelope_hits=10 lookup_failures=0 unchecked=24 plan consolidate 55 UTXO(s) -> P2WPKH in 1 tx(s) at 1 sat/vB (economyFee): 8181.0 vB, fee 8,181 sats ($6.51), out 44,238,971 sats; protected/left untouched=79; break-even future rate=1.01 sat/vB [WINDOW OPEN] matrix P2WPKH @ fastestFee 2 sat/vB n= 55 vB= 8181.0 fee= 16,362 sats ($13.02) net@50=387,238 net@100=790,838 matrix P2WPKH @ economyFee 1 sat/vB n= 55 vB= 8181.0 fee= 8,181 sats ($6.51) net@50=395,419 net@100=799,019 matrix P2WPKH @ window 1 1 sat/vB n= 55 vB= 8181.0 fee= 8,181 sats ($6.51) net@50=395,419 net@100=799,019 matrix P2WPKH @ window 5 5 sat/vB n= 47 vB= 6997.0 fee= 34,985 sats ($27.84) net@50=309,415 net@100=653,815 matrix P2WPKH @ window 10 10 sat/vB n= 47 vB= 6997.0 fee= 69,970 sats ($55.68) net@50=274,430 net@100=618,830 matrix P2WPKH @ window 20 20 sat/vB n= 47 vB= 6997.0 fee= 139,940 sats ($111.37) net@50=204,460 net@100=548,860 matrix P2TR @ fastestFee 2 sat/vB n= 55 vB= 8193.0 fee= 16,386 sats ($13.04) net@50=387,739 net@100=791,864 matrix P2TR @ economyFee 1 sat/vB n= 55 vB= 8193.0 fee= 8,193 sats ($6.52) net@50=395,932 net@100=800,057 matrix P2TR @ window 1 1 sat/vB n= 55 vB= 8193.0 fee= 8,193 sats ($6.52) net@50=395,932 net@100=800,057 matrix P2TR @ window 5 5 sat/vB n= 47 vB= 7009.0 fee= 35,045 sats ($27.89) net@50=309,880 net@100=654,805 matrix P2TR @ window 10 10 sat/vB n= 47 vB= 7009.0 fee= 70,090 sats ($55.78) net@50=274,835 net@100=619,760 matrix P2TR @ window 20 20 sat/vB n= 47 vB= 7009.0 fee= 140,180 sats ($111.56) net@50=204,745 net@100=549,670 privacy 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S spend_txs=0 co_addresses=0 cospend_txs=0 round_change_txs=0 script_mismatch_txs=0 coinctl freeze=79 consolidate=55 leave=0 (use --format markdown for copy-paste commands) findings [CRITICAL] ADDRESS_REUSE: 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S received 134 separate outputs (funded_txo=134, spent_txo=0): every receipt and spend is publicly linked to one address [MEDIUM ] DUSTING_ATTACK_SUSPECT: 45 tiny unsolicited UTXO(s) (<= 1000 sats) sit beside a 44408175-sat wallet on 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S: freeze / do-not-spend them in Sparrow, Electrum or Bitcoin Core so they cannot link your main UTXOs [MEDIUM ] UTXO_FRAGMENTATION: 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S holds 134 UTXOs (44408175 sats): spending them costs far more than one consolidated input [LOW ] INSCRIPTION_CHECK_INCOMPLETE: 24 small UTXO(s) on 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S could not be checked for inscriptions (lookup failed or --max-lookups reached): excluded from consolidation [LOW ] LEGACY_SCRIPT_TYPE: 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S is legacy P2PKH: each input costs 148 vB vs 68 vB for P2WPKH and 57.5 vB for P2TR [LOW ] STRANDED_UTXOS: 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S has 1 UTXO(s) (1 sats) that cost more than their value to spend at 1.0 sat/vB (1 at the conservative 3x margin) [INFO ] CONSOLIDATION_WINDOW_OPEN: fees are low (1.0 sat/vB <= 3.0): consolidating 55 UTXO(s) costs 8181 sats and breaks even above 1.01 sat/vB [INFO ] INSCRIPTION_PROTECTED: 10 UTXO(s) on 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S carry an Ordinals envelope in their creating tx: excluded from consolidation, do not spend from a regular wallet exit_code 3 SCOPE_NOTE: Strictly read-only: only public Mempool.space / Blockstream Esplora REST GET endpoints (address stats, UTXO set, recent transactions, fee estimates, prices) or an --offline fixture. Never accepts or asks for private keys, WIF, xprv/yprv/zprv, seed phrases or PSBTs; no transaction is built, signed or broadcast by the tool; coin-control commands are displayed for the owner to run in their own wallet. Heuristics (CIOH, change detection, dusting, inscription envelopes) are probabilistic, cover only the recent transactions and small UTXOs it states it checked, and "no findings" never means "private" or "safe to sweep". P3... addresses are assumed to be nested SegWit (P2SH-P2WPKH). No financial, legal or tax advice. Refuses: targeting third-party wallets for exploitation or deanonymisation, ranking wallets by balance, or building dust-attack target lists.
What It Does Not Do
- Strictly read-only (public Mempool.space / Blockstream Esplora
GETendpoints only): never accepts or asks for private keys, WIF,xprv/yprv/zprv, seed phrases or PSBTs, and never builds, signs, or broadcasts a transaction. Coin-control commands are displayed for you to run in your own wallet. - Heuristics (CIOH, change detection, dusting, inscription envelopes) are probabilistic and cover only the recent transactions and small UTXOs it states it checked. “No findings” never means “private” or “safe to sweep”. Addresses starting with
3are assumed to be nested SegWit (P2SH-P2WPKH). - Refuses to target third-party wallets for exploitation or deanonymisation, rank wallets by balance, or build dust-attack target lists. Not financial, legal, or tax advice.
Pinned Runtime (SHA-256)
/runtime/btc_utxo_hygiene.py— SHA-256e3b8d9be91fb2ae75d272fea248d484a2c4076fd472e40eaef73ea903257d5ee/runtime/bot_common.py— SHA-256d1941b61b95ca664e4c1286c3bf1918c00e976c2c1601199b19200257650e526
The setup skill refuses to install either file if its SHA-256 does not match the pinned value above. Runtime URLs are license-gated: send X-License-Key: wcl_... or X-Agent-Key: wck_... (unauthenticated requests get 401). The served file carries a per-license watermark block (5 lines), so compare the X-Canonical-SHA256 response header (or the SHA-256 after stripping the block) against the pin. The recommended path is the setup skill installer.
Licensing & Setup
One-time license, up to 3 workspace-reset rebinds. On Turn 1 the btc-utxo-hygiene-setup skill verifies your agent key, binds your wcl_... code through the read-only license helper, and installs the SHA-256-pinned bot_common.py and btc_utxo_hygiene.py runtime. The license code is never printed in chat.
One wcl_... key, two runtimes. Your license key works inside Grok Bot and from any local terminal or IDE agent (Cursor, Claude Code, Windsurf, CI/CD) via the standalone single-file Python 3 CLI (/runtime/btc_utxo_hygiene.py) — Python 3.10+ standard library only, zero pip install dependencies, with --json / --markdown output.