CLOISTER DOCS
ENDE
Website Open App →

Cloister — Integration guide

How to integrate Cloister into a wallet (the dfx-wallet path) and how the pieces fit.

1. Native prover module (iOS)

The wallet uses a local Expo module, dfx-wallet/modules/cloister-prover, which wraps the gomobile-built Cloister.xcframework and ships the proving keys in the app bundle.

Rebuild the native artifacts (they are git-ignored, ~75 MB):

cd packages/prover-gnark
./scripts/build-ios.sh ~/DFXswiss/dfx-wallet   # setup keys → gomobile bind → install

Then in the wallet:

npx expo prebuild --clean
(cd ios && pod install)

JS surface (modules/cloister-prover/index.ts):

import { initProver, isReady, hash, prove } from 'cloister-prover';
await initProver();              // load keys (idempotent)
const h = await hash([1n, 2n]);  // Poseidon2 → bigint
const { a, b, c, publicSignals, proofHex } = await prove(witnessInput);

2. Wire the SDK to the native backend

Add @cloister/sdk to the wallet package.json (file: link or published), then once at startup / before the first payment:

import { wireCloisterNativeBackend } from '@/features/cloister/proverBackend';
await wireCloisterNativeBackend();   // routes SDK hashing + proving to the native module

proverBackend.ts calls setHashBackend / setProveBackend from @cloister/sdk.

3. Build, prove, submit

import { MerkleTree, Note, Keypair, buildTransaction, submitShielded, syncWithFallback } from '@cloister/sdk';

// keep the tree in sync (indexer → chain-scan fallback)
await syncWithFallback({ indexerUrls, pool, tree, wallets });

// build + prove on-device, then submit (idempotent, with fallback)
const tx = await buildTransaction({ tree, inputs, outputs, extAmount, fee, recipient });
const res = await submitShielded(tx, {
  relayerUrls,            // privacy-preserving broadcast
  rpcUrls,                // idempotency check + optional direct fallback
  poolAddress,
  // allowDirect: true, directKey   // opt-in liveness fallback (reveals sender)
});
// res.status ∈ { 'broadcast', 'already-onchain' }; res.txHash, res.via

4. Relayer + indexer (backend)

5. Deploy

cd packages/prover-gnark && go run ./cmd/setup .      # keys + Groth16Verifier.sol
# copy build/Verifier.sol → packages/contracts/contracts/Groth16Verifier.sol (renamed)
cd packages/contracts && npx hardhat compile
# wire a hash backend (proverd) in your deploy script, then:
node -e "import('@cloister/contracts/deploy').then(({deployAll}) => …)"

deployAll(signer, { asp }) deploys TransactionVerifier, the token, ShieldedPool (with the Poseidon2 empty-tree initialRoot) and PoolRegistry. Set a hash backend (useHttpBackend) before calling — the empty root is computed with Poseidon2.

Public-signal order (must match everywhere)

[Root, PublicAmount, ExtDataHash, InputNullifier0, InputNullifier1, OutputCommitment0, OutputCommitment1, NewRoot, PairIndex, AssociationRoot]

On this page
1. Native prover module (iOS)2. Wire the SDK to the native backend3. Build, prove, submit4. Relayer + indexer (backend)5. DeployPublic-signal order (must match everywhere)