Updated 2026-10-26. Parts of this June 2026 research are superseded. The output type for mainnet v1 stays P2WSH with an absolute-height CLTV (OP_CHECKLOCKTIMEVERIFY, heights only). The move to Taproot with a MuSig2 key path is withdrawn until threshold Schnorr signing is supported by the launch wallets and signers. The planned script change is a 2-of-3 protocol side written as miniscript,wsh(and_v(v:pk(U),or_i(multi(2,K1,K2,K3),after(H)))), so policy-based hardware wallets can sign it; today’s deployed script is not miniscript and those devices cannot sign it yet. The SPV contract is an on-chain header light client, not the stateless design recommended below. The sections below are kept as the original research, with these points corrected in place.
Overview
When a user deposits BTC into Writz Protocol, that BTC must be provably locked on the Bitcoin side - the user cannot move it until the loan is repaid. This document designs the Bitcoin-side locking mechanism, evaluating P2WSH vs. Taproot approaches and defining the exact script logic.The Core Problem
Bitcoin has no native way to “freeze” funds based on activity on another chain. Writz needs a mechanism where:- BTC is deposited to a specific Bitcoin address
- That BTC cannot be moved without the protocol’s co-signature (until loan is repaid)
- The user has a fallback recovery path if the protocol becomes unavailable
- The locking is verifiable on Stellar via SPV proof
Option A: P2WSH (Pay-to-Witness-Script-Hash)
Chosen for mainnet v1 (decision of 2026-10-26) P2WSH locks funds to the hash of a custom redeem script, with spending data carried in the Witness field rather than ScriptSig. Lower witness weight = lower transaction fees when spending.Script Design
Redeem script:- Branch:
OP_IF(push1to unlock) - Requires: protocol signature + user signature
- Triggered: when user repays USDC loan and Writz co-signs the BTC release
- Branch:
OP_ELSE(push0to unlock) - Requires: only user signature + block height ≥ timelock
- Triggered: after a predefined locktime if Writz becomes unavailable
- Protects user from permanent loss if the protocol disappears
Timelock value selection
The timelock must be long enough that:- The loan has time to be repaid normally
- The protocol can resolve issues before the escape hatch opens
- But not so long that the user’s capital is locked for an unreasonable period
OP_CHECKLOCKTIMEVERIFY (CLTV) with an absolute block height, not a relative timelock. This avoids complexity when the loan term is extended or renewed.
P2WSH address generation
Each deposit gets a unique P2WSH address derived from:timelock is unique per deposit (based on current block height + loan duration). The user_pubkey is the user’s Bitcoin public key. The protocol_pubkey is Writz Protocol’s co-signing key.
On-chain footprint
- Output: 34 bytes (version byte + 32-byte script hash)
- Spending (path A, normal): ~250 bytes (user sig + protocol sig + redeem script in witness)
- Spending (path B, emergency): ~180 bytes (user sig + redeem script in witness)
- Fee impact: Witness bytes are discounted by 4x in Bitcoin’s fee calculation - P2WSH spends are economically efficient
Option B: Taproot / P2TR (Pay-to-Taproot)
Not planned. Withdrawn on 2026-10-26 until threshold Schnorr signing exists in the launch wallets and protocol signers (see the reasons under “Why P2WSH, and not Taproot” below). Taproot (BIP 341, active since November 2021) is a significant privacy and efficiency upgrade to Bitcoin scripting. It uses Schnorr signatures and Merkle trees (MAST - Merkelized Abstract Syntax Tree) to hide spending conditions until they are used.How Taproot improves on P2WSH for Writz
Taproot design for Writz
Key-path spend (normal - loan repaid): Using MuSig2, the protocol key and user key are aggregated into a single tweaked public key. When the loan is repaid, both parties cooperatively produce a single Schnorr signature that unlocks the funds. On-chain this looks identical to a standard single-key Bitcoin payment - no evidence that it was a 2-of-2 multi-sig or a bridge deposit. Script-path spend (emergency - timelock): The timelock recovery script is embedded in a Tapscript leaf, committed to in the Taproot output. If the key-path spend is unavailable (Writz offline), the user reveals the leaf script and spends using only their key after the timelock. Privacy benefit: Chain surveillance firms cannot identify Writz deposits from normal Bitcoin payments in the common case. Only the emergency path reveals the script structure.Why P2WSH, and not Taproot
- MuSig2 for the key-path requires interactive signing protocols (nonce exchange) between the user and the Writz backend. This adds complexity to the UX flow (two round trips instead of one).
- Hardware wallet support for Taproot key-path with MuSig2 is still limited in 2026.
- P2WSH is well-audited and simpler to implement correctly, and a P2WSH miniscript can be signed by the launch wallets today.
- The planned 2-of-3 protocol side does not fit a MuSig2 key path (MuSig2 is n-of-n); it would need FROST or nested aggregation, which no launch wallet or custody option supports.
multi(2,...)in P2WSH works with ECDSA signers now. - Verifying a Taproot output on Soroban would need BIP-340 Schnorr verification or secp256k1 point arithmetic, which Soroban does not provide as host functions; a P2WSH check is one SHA-256 comparison, already built.
- The security properties are equivalent - only the on-chain privacy and fee efficiency differ.
Protocol Co-Signing Key Architecture
The problem
Writz holds a co-signing private key for theprotocol_pubkey in every locking script. Every spending path also requires the user’s key, so a compromised protocol key cannot move locked BTC on its own, but it is a single point of failure for cooperative releases, and any future path in which the protocol side completes a transaction the user pre-signed (such as liquidation) raises its value to an attacker.
Solutions (in order of security)
Planned: 2-of-3 protocol side in the script Instead of splitting one key with MPC, the script itself requires the user’s key and any 2 of 3 protocol keys,wsh(and_v(v:pk(U),or_i(multi(2,K1,K2,K3),after(H)))), held separately. Bitcoin enforces the threshold natively, each protocol key signs plain ECDSA, and the user’s timelock exit is unchanged. Threshold ECDSA (MPC, for example GG20/21 or CGGMP21) is not planned. The signing policy, what the protocol signers can and cannot sign, will be published.
Considered: Stellar Auth Delegation (Protocol 27)
Protocol 27 (July 8, 2026) enables distributing the co-signing authority on the Stellar side across multiple delegated accounts. While this doesn’t directly affect the Bitcoin signing key, it enables a multi-party signing ceremony where multiple Stellar accounts must authorize a BTC co-signature before it’s produced.
Only if Taproot is reopened: FROST (Flexible Round-Optimized Schnorr Threshold)
If Writz ever moves to Taproot, FROST enables threshold Schnorr signatures where t-of-n parties cooperate to sign. More efficient than ECDSA MPC. Produces a single Schnorr signature indistinguishable from a regular single-key spend.
zkRelay Alternative: ZK-SNARK Bitcoin Relay
Research uncovered an interesting alternative to verifying every header on chain: zkRelay - using ZK-SNARKs to batch-verify multiple Bitcoin block headers off-chain and post a single proof on-chain.zkRelay approach
Instead of the caller providing raw headers + Merkle proofs, a prover computes a ZK proof that:- “I have validated N consecutive Bitcoin block headers”
- “Each header has valid PoW”
- “Transaction T is included in block at height H”
Why this matters for Writz
Writz’s SPV contract is an on-chain header light client, the same family as BTC Relay: each header is submitted and verified on Stellar. zkRelay’s approach could reduce the on-chain cost of the header chain, or serve as an independent second check of it. Recommendation (original, superseded): this research recommended starting with stateless SPV (the summa-tx approach). The contract has since moved to a header light client, because a stateless design lets a caller present a header chain it mined privately. A zero-knowledge proof of the header chain remains under research as a second check that could only refuse a tip, never credit value (see SPV vs Wrapped Bitcoin).Bitcoin Reorg Handling
A Bitcoin block reorganization (“reorg”) occurs when the network switches to a longer chain, invalidating previously confirmed blocks. If Writz accepts a deposit based on a block that later gets reorged out, the BTC effectively disappears.Risk assessment
- Reorgs of 1–2 blocks: happen occasionally (~once per few days)
- Reorgs of 3 blocks: extremely rare (a few times in Bitcoin’s history)
- Reorgs of 6 blocks or more: very rare; the deepest on mainnet are the 2010 value-overflow fix (about 53 blocks) and the 2013 BIP-50 fork (24 blocks)
Fast lane option - considered, not adopted
For users willing to pay a higher fee and accept slightly elevated risk:- Require 3 confirmations (~30 minutes)
- Cap the maximum deposit size to $5,000 at 3-confirmation tier
- Standard deposits (>$5,000) always require 6 confirmations
docs/products/writz-lend.md, docs/how-it-works/spv-verification.md, and docs/how-it-works/stellar-side.md all specify a flat 6-confirmation requirement with no fast lane, and the contract’s min_confirmations parameter is set by the caller with no fast-lane logic in bitcoin-spv. If the fast lane is revisited, update those three docs together with this one.
Complete Deposit-to-Repayment Flow
Key Decisions Summary
Last updated: 2026-06-22 Sources: Bitcoin P2WSH - learnmeabitcoin.com · Taproot Technical - learnmeabitcoin.com · zkRelay paper - eprint.iacr.org · SmartCustody Timelocks - BlockchainCommons