Skip to main content

Writz Protocol - Testnet Deployments

Network: Soroban Testnet (Test SDF Network ; September 2015) Deployer: writz-deployer

Current deployment (2026-08-19)

Redeployed all four contracts together after the Elliot code-quality pass: is_borrow soundness fix + collateral/price range checks in the ZK circuits (new verification keys, since the constraint system changed), the Config.paused flag, the set_spv_contract/set_zk_verifier/set_oracle setters, supply/withdraw events, and the oracle-stub dedup into spv-types, per docs/architecture/contract-migration-runbook.md § Track 1 (planned migration, no funds at risk on the superseded testnet contracts - straight redeploy rather than a wind-down). Built via stellar contract build (wasm-opt applied). Per the immutability ADR (docs/architecture/adr/0001-contract-immutability.md) there is no in-place upgrade path, so this is four fresh Contract IDs, not an upgrade of the ones below.

bitcoin-spv

Checkpoint anchored to Bitcoin Signet tip at deploy time: Verified: get_checkpoint reads back exactly these values. ✓ The checkpoint must be refreshed periodically (recommended: weekly) - see docs/security/security-model.md for the full trust-model discussion. Before mainnet, convert the admin account to a multisig (2-of-3) rather than a single key.

zk-verifier

Verification keys set (regenerated from the range-checked circuits - IC lengths unchanged, but the key material itself differs from the superseded deployment since the constraint system changed): Verified: get_verification_key --circuit BorrowRepay reads back IC length 9 with all four curve-point fields populated. ✓
Note: These keys are from the development trusted setup (pot15). They are for testnet only and will be replaced by the multi-party ceremony keys before mainnet.

commitment-tree

Configuration

Verified: get_merkle_root"2134e76ac5d21aab186c2be1dd8f84ee880a1e46eaf712f9d371b6df22191f3e", matching the Poseidon-2 empty Merkle tree root at depth 20. ✓ Pool seeded: 500 USDC supplied by writz-deployer - 5241a90817.... get_pool_statetotal_supplied: 5,000,000,000 stroops (500 USDC), total_borrowed: 0. ✓

private-lend

Configuration

Verified: get_protocol_statetotal_supplied: 0, total_borrowed: 0, last_keeper_heartbeat set to init time. ✓ Pool seeded: 500 USDC supplied by writz-deployer - baf32ae36b.... get_protocol_statetotal_supplied: 5,000,000,000 stroops (500 USDC). ✓

End-to-End ZK Flow Test ✓ (2026-08-19, against the current deployment)

Test instance: CCCT2CQUOMICS3IULYYQKCZ6PBUMUKE7EA77NQPDHHHVLUPLNOVQR2UU Token: XLM native SAC (CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC) Running scripts/deploy/e2e_zkflow.js against the new zk-verifier (CBNZU23Q…) surfaced a real gap: the script’s synthetic single-tx-block header had always used bits = 0/nonce = 0 (no actual mining), which the current bitcoin-spv correctly rejects with InsufficientProofOfWork - this only ever “worked” historically against a build that didn’t yet enforce real proof-of-work. Rather than weaken the shared production bitcoin-spv’s checkpoint (which is anchored to real Bitcoin Signet difficulty specifically to reject easy fake chains), the script now deploys its own throwaway bitcoin-spv per run with an easy checkpoint (EASY_TEST_BITS = 0x207fffff, same constant the Rust test suite uses) and mines its test header for real against it. Production bitcoin-spv’s security is unaffected. What this confirms: the freshly-generated borrow_repay verification key (with the is_borrow soundness fix + the new collateral/price range checks, both from the Elliot pass) correctly verifies real Groth16 proofs from the current circuits - deposit, borrow, and a full repay all passed on-chain against zk-verifier CBNZU23Q…. ✓

Follow-ups this redeploy did not do

  • Doc sweep: done - every non-historical reference to the superseded Contract IDs across docs/, README.md, docs.json, mint.json, relayer/README.md, and packages/commitment-tree/README.md now points at the current deployment; scripts/check-docs-sync.mjs reports zero drift. Test counts across all docs were re-synced from docs/_data/facts.json (191 contract tests + 60 bitcoin-script + 59 relayer + 29 circuits = 339 total) via scripts/update-test-counts.mjs.
  • Relayer live .env: no relayer instance’s real .env exists in this checkout (only .env.example, which had no hardcoded contract IDs to begin with) - nothing to update. If a deployed relayer instance exists elsewhere, its env needs the new COMMITMENT_TREE_ID/PRIVATE_LEND_ID by hand.
  • docs/developers/contract-reference.md and a couple of quick-start/milestone-plan snippets document function signatures and CLI calls (set_vkey, verify_groth16, commitment-tree/private-lend initialize argument lists, a bitcoin-spv::get_version call) that don’t match the actual current contract interfaces - this predates this redeploy and is a separate, larger doc-accuracy gap (API reference, not contract addresses). Contract IDs and test counts in those files are now correct; the signatures themselves were not rewritten here - flag if a full rewrite is wanted.

Superseded deployment (2026-06-22 / 2026-06-30)

Left running per the migration runbook’s default (no forced state transplant); kept here for history. No known funds are at risk on these - they predate real usage.

bitcoin-spv

Verified call

Result:
Verified: txid and block_hash match SHA256d values exactly. ✓
[SUPERSEDED] This deployment predates the current contract build (pre-dates the is_borrow/range-check circuit fixes, the paused flag, and the VerificationResultSpvVerificationResult rename). Use the “Current deployment” section above instead.

zk-verifier (superseded)

Verification keys set

[SUPERSEDED] VKs here are from the pre-range-check circuits - proofs generated by the current circuits/ tree will NOT verify against this instance. Use the “Current deployment” section above.

commitment-tree (superseded)

Configuration

Verified call

Result: "2134e76ac5d21aab186c2be1dd8f84ee880a1e46eaf712f9d371b6df22191f3e" Verified: matches the Poseidon-2 empty Merkle tree root at depth 20. ✓
[SUPERSEDED] Predates paused/setters/supply/withdraw events and the current zk-verifier’s keys. Use the “Current deployment” section above.

private-lend (superseded)

[SUPERSEDED] Predates paused/setters/supply/withdraw events and the keeper stale-window liquidation fallback. Use the “Current deployment” section above.

P2WSH End-to-End Test (Bitcoin Signet)

Script: bitcoin-script/scripts/e2e_testnet.mjs
Run: node scripts/e2e_testnet.mjs --dry-run · node scripts/e2e_testnet.mjs (live broadcast)
Date: 2026-06-23
Network: Bitcoin Signet (Blockstream Esplora)

Deposit address

Live broadcast results ✓

What was verified:
  • P2WSH address derived correctly from (protocol_key, user_key, CLTV=700,000) ✓
  • Both keys signed the PSBT independently (multi-party flow) ✓
  • finalizePathA assembled witness [user_sig, protocol_sig, 0x01, redeemScript] correctly ✓
  • Transaction broadcast and accepted by Bitcoin Signet mempool ✓

End-to-End ZK Flow Test ✓

Test instance: CDCH7C5TBJOZWIUKVSDGLWPTLTBIC55WH4447ZVIOA4NRDWKOXPVKOHB
Token: XLM native SAC (CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC)
Date: 2026-06-22
What was verified on-chain:
  • Groth16 deposit proof: BN254 pairing check via bn254.pairing_check host function ✓
  • Commitment inserted into Poseidon Merkle tree (root updated) ✓
  • Groth16 borrow proof: collateral ratio enforced by ZK circuit (150% min) ✓
  • USDC (XLM) transferred from pool to borrower ✓
  • Groth16 repay proof: field-negation repay amount recovered correctly ✓
  • Pool accounting updated after each operation ✓
  • All proofs verified against zk-verifier contract CDV45GLXG4AOU6BDZSY5YHHVNGQIAYAPD3PUGXIIIYLIO6V2XGO6SMFV

Re-run after the enc_note interface change (#18)

The 2026-06-22 run above predates enc_note. e2e_zkflow.js was not updated alongside the contract, so it failed at the deposit step until fixed (#15). Re-verified against the current interface: Test instance: CBM5OUBYBICB3QB4T5PAGYUWWLZOIVWQCUHKV3HCSNZGB72GYM5Q5ID4 Token: XLM native SAC (CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC) Date: 2026-07-30 · whole run completes in about a minute Reproduction steps, build prerequisites, and the trusted-setup caveat: docs/developers/runbook.md.