Skip to main content
useShield (deposits) is temporarily paused. After StarkWare’s July 2026 STRK20 pool v2.0 upgrade, shielding into the shared privacy pool requires a screener attestation issued by StarkWare’s hosted proving service — Chipi is finalizing that access. useUnshield and usePrivateBalance work today; shields will revert until access lands. Don’t ship a shield flow to production yet — we’ll announce on X (@hichipipay) when shielding is back on.
Signatures below are stated from the package types (@chipi-stack/chipi-react) — if a snippet here doesn’t compile against the installed package, that’s a docs bug; report it.

The trust model, honestly

Keys derive client-side and are never stored server-side — but STRK20’s delegated proving requires the pool spending key inside each proof request, so Chipi’s proving service (a private prover Chipi operates; the same model as StarkWare’s hosted prover) sees it per operation and must be trusted not to retain or use it. Privacy holds against the public — chain observers, other users — not against the proving operator. Do not tell your users “nobody, including Chipi, can see your balance.” Local proving is the roadmap item that removes this trust.

useShield()

Moves money INTO the private balance. Returns { shield, shieldAsync, data, isLoading, isError, error, isSuccess, reset }. shieldAsync(input: ShieldHookInput) where:
Orchestration (all retried/hardened): gas-tank funding → your fundDeposit transfer → funding-arrival wait → companion deploy + approvals → prove → gateway submit → receipt + pool-event assertion (no phantom successes) → background STRK sweep. Resolves with { transactionHash, via, receipt, feeStrk }.

useUnshield()

Same spine, plus deliverTo: string (required): withdrawals land in the companion and are delivered onward to the user’s wallet (awaited).

Multiple tokens

Both hooks are per-token by design (token: string, amount: bigint).
  • Batch shield (N tokens, one proof, one 4-STRK fee) lives in the core engine: execShieldMany. Call it directly for multi-token shields; a single-item batch is exactly the hook’s path.
  • Sequential unshields need spacing: proving runs against head − 12, so a second withdrawal within ~13 blocks (~5–6 min) of the first fails with the prover’s state_too_fresh hint. Catch it, tell the user what already came back, and retry the rest a few minutes later — the full pattern is on the Core SDK privacy page.

usePrivateBalance(input)

Read-only — the difference from the actions: no gesture after setup, no gas, no writes.
  • { mode: "ledger", events: PrivacyLedgerEvent[] } — instant netting of your recorded events, clamped at zero. Use for passive display.
  • { mode: "onchain", config, keys, tokens? } — authoritative pool note scan with the viewing key. Use for an explicit “verify on-chain” action.
Returns { byToken: Record<string, bigint>, isLoading, isError, error, refetch }.

derivePrivacyAccount(p)

{ anchorSecret: Uint8Array; seedDomainTag: string; classHash: string } → Promise<PrivacyKeys> — deterministic, client-side. Cache the address, never the keys.