PrivacyPoolSDK, submit transact calls to the deployed PrivacyPoolsContract, and have every transaction automatically indexed by the Arcane scanner so auditors can open disclosure cases in the Audit Portal.
Prerequisites
Before you begin, make sure you have the following in place:- A Stellar/Soroban network and RPC endpoint — Testnet or Mainnet, with a reachable Soroban-compatible RPC URL.
- A deployed
PrivacyPoolsContract— Either deploy your own or obtain the address of an existing deployment. - The contract’s verification key and decoding key — The verification key is set at deploy time; the decoding key is used by Arcane to interpret encrypted audit payloads.
@auditable/privacy-pool-zk-sdkinstalled in your application — Install withnpm install @auditable/privacy-pool-zk-sdk.- A Stellar wallet integration — Your application needs to request message signing and transaction submission from a connected wallet.
- An Arcane organization and application — Contact Arcane support to provision your organization, application record, and scanner configuration.
Integration flow
The following diagram shows how the pieces fit together from your application all the way to the Audit Portal: Your application calls the SDK to build proofs and the wallet to sign transactions. The contract verifies the proof, updates on-chain state, and emits anAuditEncodedDigest event. The Arcane scanner picks up that event via the Stellar RPC and makes the transaction available to auditors in the portal.
Contract setup
DeployPrivacyPoolsContract with the following constructor arguments:
| Constructor argument | Purpose |
|---|---|
tree_depth | Depth of the on-chain Merkle commitment tree |
vk_bytes | Groth16 verification key bytes matching your compiled circuit |
public_n_inputs | Number of public withdrawal (input) slots in the circuit |
public_n_outputs | Number of public deposit (output) slots in the circuit |
admin | Stellar address granted admin privileges on the contract |
The
public_n_inputs and public_n_outputs values must match the circuit you compiled and the verification key you provide. Mismatches will cause proof verification to fail.Application integration
Install and initialize the SDK
Install the SDK package:Then initialize an SDK instance by loading the WASM binary, circuit WASM, and proving key. In a browser environment, fetch these files from your asset server:
Derive a user stealth address
Each user who wants to receive private funds needs a stealth address. The SDK derives one deterministically from a Stellar wallet signature — no extra key material is stored.The resulting
stpl1 address is what recipients share with depositors.Build a coin and read pool state
To spend or transfer a coin, you first need to construct it and build a Merkle witness against the current pool state. Read the commitment tree data from the contract, then use the SDK to build the witness:
Generate proof bytes and public signal bytes
With your coin and witness in hand, generate the Groth16 proof. Use
proveWithdrawal for a withdrawal transaction or proveTransaction for the general-purpose proof path:Prepare encrypted audit bytes
Every
transact call must include an encrypted audit payload (encoded) that Arcane’s scanner will index and decrypt using the contract’s decoding key. Construct this payload according to your Arcane application configuration before submitting the transaction.The
encoded argument is emitted verbatim by the contract as the AuditEncodedDigest event. Arcane’s scanner picks it up and decrypts it server-side using the decoding_key registered for your contract.Soroban call shape
Thetransact entrypoint accepts four arguments:
| Argument | Source |
|---|---|
from | Wallet-authenticated Stellar address — the transaction signer |
proof_bytes | Groth16 proof serialized by sdk.proofToHex() |
pub_signals_bytes | Public circuit signals serialized by sdk.publicToHex() |
encoded | Encrypted audit payload bytes for Arcane indexing |
Verification checklist
Use this checklist to confirm your integration is working end-to-end:- Contract is deployed with the correct
tree_depth,vk_bytes, and public slot counts -
PrivacyPoolSDKinitializes without errors in your application - A stealth address (
stpl1…) is successfully derived from a wallet signature -
proveWithdrawalorproveTransactionproduces a proof without errors - Wallet can sign and submit the
transactcall to the network - Contract emits an
AuditEncodedDigestevent after a successful transaction - Arcane scanner advances and writes audit rows for your contract
- Audit rows are interpreted (deposit / withdrawal / transfer records appear)
- An auditor can create a case request in the Audit Portal
- An administrator can approve or close the request
- Approved auditor can open the case and view scoped transaction fields
Troubleshooting
| Symptom | Check |
|---|---|
| No audit rows appear in the portal | Confirm the contract address is registered to the correct chain_id, the scanner chain name is configured, and the scanner checkpoint range covers the event ledger |
| Scanner runs but the event is ignored | Verify the event comes from a successful contract invocation and that the event topic maps to a supported audit type |
| Duplicate-looking scan results | Audit row upserts are idempotent by (contract_id, soroban_event_id) — duplicates are safely overwritten |
| Public signals are missing or wrong | Check that the scanner’s calldata parser can read the transact invocation metadata |
| Proof verification fails on-chain | Confirm vk_bytes, public_n_inputs, and public_n_outputs match the compiled circuit |
| Interpretation fails | Check contracts.decoding_key, that audit.cyphertext is populated, and that audit.public_signals_json is valid |
| Auditor cannot open a case | Check case assignment, approval status, application scope, and the access window |
| UI shows workspace but not the application route | Confirm the required permission key is present in the application permission bucket |