OTC: bonded offers with verifiable supply — design doc + contrib/otc tooling - #87
OTC: bonded offers with verifiable supply — design doc + contrib/otc tooling#87numair wants to merge 2 commits into
Conversation
Design for trustless OTC settlement and proof-of-offered-supply to counter phantom-supply OTC markets: - Bonded Offer Vaults: P2MR MAST vaults (venue co-sign or CTV-committed) with refund-after-expiry leaves, so offered coins provably exist, cannot be pulled early, and cannot back two offers (OP_RETURN terms-hash binding to the funding outpoint). - Settlement: HTLC atomic swaps for crypto legs (existing buildhtlcclaim/buildhtlcrefund + wBTX Model B), bounded-arbiter CTV escrow and per-offer-key CSFS oracles for fiat legs, classic 2-of-3 as the zero-new-code fallback. - Supply validation: offer-bundle JSON + verification algorithm over gettxout/scantxoutset, bond tiers, desk-level reserves proofs, macro supply audit via gettxoutsetinfo + shielded turnstile, and an explicit market rule that unverifiable shielded claims count as zero. - Roadmap: Phase 0 usable today with shipped RPCs; Phase 1 adds otc_createoffer/otc_verifyoffer/otc_settle tooling, a CTV template helper, and a message-pinned CSFS leaf. No consensus changes anywhere. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XyH9DxN4gxxXvBGQEoPkT3
Implements the Phase-1 tooling of doc/btx-otc-escrow-supply-validation.md so OTC quotes can be backed by on-chain proof instead of screenshots: - contrib/otc/btx_otc.py: SDK + CLI for bonded offers. Offer terms are canonicalized and hashed; the bond funding tx commits to that hash via an OP_RETURN "BTXOTC1"||sha256(terms) output, so one UTXO can never verifiably back two offers. Bond descriptors cover three tiers (B soft bond, A venue co-sign, A+ CTV covenant), all built from existing node descriptor leaves. verify_offer() re-checks everything against a local node and fails closed on unknown descriptor shapes; funding txs are fetched without -txindex by deriving the block from the UTXO's confirmation depth. Settlement wrappers reuse the audited buildhtlcclaim/buildhtlcrefund wallet RPCs (bond refunds ride the same refund-leaf path). Includes an offline selftest and a btx-cli-backed CLI (create/verify/watch/refund-bond/hash-terms). - test/functional/wallet_otc_offer.py: end-to-end regtest coverage: offer creation, walletless verification, rejection of tampered terms, double-pledged and fabricated outpoints, under-confirmed bonds and undeclared spend paths, bond refund after expiry, watcher spent detection, and stage-2 HTLC settlement with on-chain preimage reveal. BIP-322 attestation over p2mr addresses is exercised too. Registered in test_runner.py. - wallet_htlc_atomicswap.py: fix pre-existing failure on txindex-less nodes (getrawtransaction now scoped to the confirming block). - contrib/README.md, design doc: index the new tooling. No consensus, policy, or node changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XyH9DxN4gxxXvBGQEoPkT3
|
Independently verified Steps 1–2 (the fund-verification half) end-to-end on stock v0.32.12 — a throwaway regtest with a wallet-less / txindex-less verifier reimplementing the seven checks. All green: offer creation, positive verify (incl. a BIP-322 attestation over a p2mr address), and rejection of tampered terms, double-pledged outpoints, fabricated outpoints, under-confirmed bonds, early-pull ( Three footguns worth folding in: 1. 2. 3. Happy to share the verifier + regtest notes as a follow-up if useful. |
|
Accepted for the BTX 0.33.2 release. The complete reviewed change set from this PR has been incorporated into the 0.33.2 release integration, so this PR is being closed as accepted rather than merged independently. |
Targets the v0.33.2 release window.
Motivation
OTC desks have been quoting BTX size they cannot deliver (phantom supply) to suppress price: fabricated balances, the same coins shown to several venues at once, borrowed coins shown then returned, and unverifiable "it's in the shielded pool" claims. This PR ships (1) a design document for trustless-as-possible OTC escrow with proof-of-offered-supply, and (2) working Phase-1 reference tooling implementing it, so that an offer without a valid proof bundle can be treated by the market as no supply.
No consensus, policy, or node code changes — everything is built from descriptor leaves, opcodes, and wallet RPCs already live on
main(P2MR MAST, CLTVrefund()leaves,multi_pq/ctv_multi_pq, HTLC leaves,buildhtlcclaim/buildhtlcrefund, BIP-322signmessage).What's included
doc/btx-otc-escrow-supply-validation.md— the design: Bonded Offer Vaults (tier A+ CTV covenant / tier A venue co-sign / tier B soft bond), OP_RETURN"BTXOTC1"||sha256(canonical terms)funding-tx commitment that makes one UTXO ↔ one offer cryptographically exclusive (kills double-pledging), HTLC atomic settlement for crypto legs, bounded-arbiter CTV escrow and per-offer-key CSFS oracles for fiat legs, threat model, and roadmap.contrib/otc/btx_otc.py— SDK + CLI: terms canonicalization/hashing, bond descriptor builders and a strict fail-closed parser,create_offer(funds the vault + commitment in onesend), walletlessverify_offer(descriptor shape, UTXO existence/confirmations/amount, funding-tx commitment without-txindex, expiry, BIP-322 attestation),watch_offer, bond refund and HTLC settlement wrappers over the audited wallet RPCs.python3 btx_otc.py selftestruns offline unit checks.contrib/otc/README.md— usage, tier table, and an honest trust-model statement.test/functional/wallet_otc_offer.py— end-to-end regtest coverage (registered intest_runner.py).wallet_htlc_atomicswap.pyfailed on txindex-less nodes at its preimage-reveal check (getrawtransactionafter the tx left the mempool); now scoped to the confirming block. Same fix pattern used in the new test.Validation
src/libbitcoinpqc/**untouched — fuzz smoke not applicable.Ran locally on a fresh Release build (
-DBUILD_GUI=OFF -DBUILD_TESTS=OFF):test/functional/wallet_otc_offer.py --descriptors— passes: offer creation; positive verification (incl. BIP-322 attestation over a p2mr address); rejection of tampered terms, double-pledged outpoints, fabricated outpoints, under-confirmed bonds, undeclared descriptor spend paths, duplicate outpoints; expiry handling; bond refund via therefund()leaf; watcher spent-detection; stage-2 HTLC claim with on-chain preimage reveal.test/functional/wallet_htlc_atomicswap.py --descriptors— passes (was failing before the drive-by fix on nodes without-txindex).python3 contrib/otc/btx_otc.py selftest— passes (canonicalization, descriptor round-trips, fail-closed parsing, commitment framing).create→ mine →verify --min-conf 1 --require-attestationreturnsok: truewith all seven checks green, wallet-less.flake8 --select=F,E9clean on both new Python files.Notes for reviewers
-txindex: the block is derived from the bond UTXO's own confirmation depth (getblockhash(height − confs + 1)).contrib/otccarries the same UNAUDITED caveat ascontrib/wbtx.🤖 Generated with Claude Code
https://claude.ai/code/session_01XyH9DxN4gxxXvBGQEoPkT3
Generated by Claude Code