I built Coin Smith, a safe PSBT (Partially Signed Bitcoin Transaction) builder that handles coin selection (UTXOs), constructs unsigned Bitcoin transactions, exports PSBTs (BIP-174), emits machine-checkable JSON reports, and serves a web UI to visualize and justify the transaction building process.
I approached this project as a core wallet engineering problem: focusing on protocol-first correctness, defensive validation, and sensible optimization across various script types, fee/change edge conditions, and malformed inputs.
Given a JSON fixture containing a UTXO set, one or more payment outputs, a change template, and a fee rate target, my application produces:
- An optimal selected input set.
- A structurally valid PSBT containing an unsigned transaction and required prevout info.
- A JSON report explaining the exact construction.
- The same report visualized via a local web UI.
The coin selection strategy balances a multi-objective cost model, minimizing fees and input count while maintaining strong wallet-quality safety signals.
You can run a sample fixture through the CLI to generate a transaction:
./cli.sh fixtures/basic_change_p2wpkh.json
(Output is written to out/basic_change_p2wpkh.json)
To start the web server and view the visualizer:
./web.sh
(Runs on http://127.0.0.1:3000 by default and honors the PORT env variable)
- Defensively parses input JSON (rejects malformed inputs with structured errors).
- Selects inputs and computes precise fees and change.
- Outputs the generated JSON report to
out/<fixture_name>.json. - Exits with
0on success or1on error (e.g., invalid fixture, insufficient funds, malformed scripts).
- A candidate-facing web application that lets users load fixture JSON files.
- Visualizes the selected inputs, outputs, and specifically highlights change outputs.
- Displays calculated fees, fee rates, and critical safety warnings.
- Clearly surfaces RBF (Replace-By-Fee) signaling status and locktime info.
The transaction engine ensures internal consistency and wallet safety at all times:
- Balance: Ensures
sum(inputs) = sum(payment outputs) + sum(change outputs) + fee. - Fee target: The fee is strictly calculated to meet or exceed the target
fee_rate_sat_vbapplied to the transaction’s estimated vbytes (usingceil). - Dust Protection: Prevents the creation of dust outputs (strictly enforced at the 546 sats threshold).
- Change Handling: Creates at most one change output, and only when the change is not dust.
- Optimization: When change exists, the fee is the absolute minimum required to hit the target fee rate, pushing any extra leftover to the change output to avoid burning sats.
The transaction sets nSequence (per input) and nLockTime correctly based on the provided parameters, faithfully reproducing Bitcoin Core standardness and anti-fee-sniping behaviors.
nSequence rules:
rbf: true→ every inputnSequence = 0xFFFFFFFDrbf: false(or absent) with a non-zeronLockTime→ every inputnSequence = 0xFFFFFFFE(enables locktime without signaling RBF)- Otherwise →
nSequence = 0xFFFFFFFF(final; no RBF, no locktime)
nLockTime rules:
locktimeprovided → setsnLockTimeto that value.locktimeabsent,rbf: true, ANDcurrent_heightprovided → setsnLockTime = current_height(anti-fee-sniping).- Otherwise →
nLockTime = 0.
To ensure wallet safety, the system runs a diagnostic check and emits warning codes under specific conditions:
HIGH_FEE:fee_sats > 1_000_000ORfee_rate_sat_vb > 200DUST_CHANGE: A change output exists withvalue_sats < 546SEND_ALL: No change output was created (leftover was safely consumed as fee)RBF_SIGNALING:rbf_signalingistrue(transaction opts into Replace-By-Fee)
- Multiple coin selection strategies: Implement branch-and-bound alongside greedy selection and compare their scores.
- PSBT Signing: Add functionality to sign the PSBT with test keys and finalize the raw transaction hex.
- Watch-only Descriptors: Export watch-only descriptors based on the input data.
- Privacy Scoring: Implement a "Privacy meter" to evaluate input reuse and output linkage risks.