Building on Writz from your own project? This page is the contributor guide: it builds and tests this repository. To call the deployed contracts from your app or your Soroban contract, start with Build on Writz. AI coding agents: For AI Agents.The core lending and verification logic in this repository is working code, not a mockup: the contracts are deployed on Stellar testnet, and the tests pass (see
docs/developers/runbook.md). Writz v1 is bitcoin-spv and writz-lend; zk-verifier, commitment-tree and the circuits, all under privacy/, belong to the separate privacy edition, in progress and testnet only. writz-lend/src/oracle.rs’s get_btc_price_stroops now calls a real Reflector oracle on testnet (see docs/research/oracle-design.md) - the privacy edition’s commitment-tree still returns a hardcoded price; it is not part of v1. Start here and have something running in under 5 minutes.
Prerequisites
Install the following before proceeding:Clone the Repository
Run All Tests
Soroban contracts (Rust)
bitcoin-spv (68), zk-verifier (26), commitment-tree (59), writz-lend (100), and spv-types (10).
Bitcoin script toolkit (TypeScript, Bun)
Relayer service (TypeScript, Bun install + Jest)
The relayer installs with Bun but its suite is Jest (ts-jest), so it must run through the package script - plainbun test selects Bun’s own runner and
fails. It also imports the local @writz/* packages via their built dist/
output, so build those first.
ZK circuits (Circom + snarkjs, npm)
verify() assertions fail here while prove() succeeds, your local privacy/circuits/keys/*_final.zkey (gitignored, regenerated locally) is out of sync with the committed privacy/circuits/keys/*_vkey.json. Run bash scripts/compile_all.sh && bash scripts/setup_dev.sh to regenerate both together from a fresh dev trusted setup, then re-run npm test.
All together: 623 tests, all passing.
Build the Contracts
contracts/target/wasm32v1-none/release/:
bitcoin_spv.wasm- 28.4 KBwritz_lend.wasm- 23.7 KB
privacy/contracts/target/wasm32v1-none/release/:
zk_verifier.wasm- 11.8 KBcommitment_tree.wasm- ~38 KB
Use the Testnet Deployments
All four contracts are live on Stellar testnet. You can call them directly without deploying:Run the Privacy Edition End-to-End Flow
scripts/deploy/e2e_local.mjs deploys all four contracts through their
constructors on a local Stellar network, registers the verification keys and
runs deposit → borrow → repay → release with real Groth16 proofs. It also
replays the closed attacks (a deposit claiming someone else’s output, a
redirected borrow, a re-borrow after release, the same txid in both lenders)
and expects each to fail. CI runs it as the e2e-local job. No testnet
account or real keys are involved.
npm run setup:dev regenerates the development keys in privacy/circuits/keys/;
restore the committed ones afterwards with git checkout privacy/circuits/keys.
Run the Bitcoin P2WSH End-to-End
This script tests the Bitcoin locking and release flow on Bitcoin Signet. No funds required for a dry run.- Generate a unique P2WSH address
- Send Signet BTC to the address
- Build the Path A co-signed release transaction
- Sign with both user and protocol keys (PSBT round-trip)
- Broadcast to Bitcoin Signet
Deploy Your Own Contracts
scripts/deploy/deploy_stack.mjs deploys and wires up all four contracts in
the order they depend on each other. Without --execute it only validates its
inputs and prints the plan. Set STELLAR_NETWORK=local to rehearse against the
local network above. The inputs are listed in scripts/deploy/.env.example.
Repository Layout for Developers
Next: Bitcoin SPV SDK →