Skip to main content
Reproduce the full Writz flow from a clean checkout. This is the operational companion to Quick Start. Quick Start gets the test suites green; this runbook gets the protocol running against Stellar testnet and Bitcoin Signet.

What this covers, and what it cannot

The flow splits into two halves with very different reproducibility: Be aware of what the scripted half does not prove: e2e_local.mjs builds a fabricated Bitcoin transaction paying the depositor’s Writz script and mines easy-difficulty headers on top of a local checkpoint. The bitcoin-spv contract genuinely verifies that header chain and Merkle inclusion, but no real Bitcoin transaction, and therefore no real deposit, is involved. It also passes an empty enc_note, so the sealed recovery-note round trip (#18) is untested there. Treat the scripted run as proof that the Soroban and ZK layers work. The Bitcoin custody path needs the manual walkthrough at the end.

1. Prerequisites

Versions below are the ones CI pins; anything older is untested.
circom 2.x is a Rust binary. Do not npm install -g circom - that installs the legacy 1.x package, which cannot compile pragma circom 2.0.0:
snarkjs needs no global install - it is a dependency of privacy/circuits/.

2. Build the artifacts a clean checkout lacks

These paths the scripts depend on are gitignored, so a fresh clone does not have them:

3. Trusted setup - read before running setup_dev.sh

privacy/circuits/scripts/setup_dev.sh generates the proving keys. It seeds its entropy with $(date):
Two consequences that will otherwise cost you an afternoon:
  1. The setup is not reproducible. Running it produces a different proving/verification key pair every time.
  2. It overwrites the committed keys/*_vkey.json. Your working tree will show those four files as modified. Do not commit them unless you also intend to push the new keys on-chain.
The shared testnet zk-verifier holds the verification keys from the original setup, whose .zkey files are not in git. Proofs from a regenerated setup submitted to it fail with InvalidZkProof - that is a key mismatch, not a bug in your proof. The scripted flow below avoids this by deploying its own zk-verifier and registering whatever keys are in privacy/circuits/keys/.

4. Run the scripted ZK flow

It refuses to run against anything but the local standalone network. Each run deploys fresh instances of all four contracts through their constructors, then walks deposit → borrow → repay → release and replays the closed attacks: To rehearse the real deployment against the same local network, run scripts/deploy/deploy_stack.mjs with STELLAR_NETWORK=local (inputs in scripts/deploy/.env.example).

5. Testnet assumptions

The scripted flow is not a faithful mainnet rehearsal. What differs:

6. The Bitcoin half (manual)

This part cannot be scripted - it needs Signet coins and two browser wallets. You need: Xverse on Signet with ≥ 0.0001 sBTC (from a Signet faucet), and Freighter on Stellar testnet, funded via Friendbot.
  1. Start the relayer, or point at the hosted one:
    Hosted alternative: https://api.testnet.writz.xyz.
  2. Start the frontend:
  3. In the browser: connect Xverse + Freighter, derive the deposit P2WSH address, send sBTC to it, and wait for confirmations. Budget ~10 minutes per Signet confirmation - this is the slow step, and the reason the demo script pre-stages deposits.
  4. Click Deposit. The relayer assembles the SPV bundle, bitcoin-spv verifies inclusion on-chain, and the browser generates the deposit proof locally.
  5. Borrow, then repay in full. On full repayment the protocol co-signs the release PSBT; countersign in Xverse and broadcast. BTC returns to your wallet.
Watch both explorers: mempool.space/signet and stellar.expert testnet.

7. Troubleshooting

Errors seen while validating this runbook, and what they actually mean:
Next: Contribution Guide → · Contract Reference →