From abi.json to typed client bindings
The exporter's abi.json is the language-neutral contract between a circuit and its clients. This
tutorial turns it into typed TypeScript and Python bindings your frontend or backend can import,
using the ZeroStyl SDKs. Both read the exact same schema.
You'll use: @zerostyl/sdk-ts, zerostyl-sdk (Python). Time: ~10 minutes.
abi.json firstGenerate one from an annotated contract with
zerostyl-export transform (see #[zk_private] → circuit + contract),
or from a registered circuit with zerostyl-export schema --circuit <name>. The examples below use
examples/zk_private_demo/abi.json.
TypeScript
Install the published package and run its generator:
npm install @zerostyl/sdk-ts
npx zerostyl-sdk generate \
--abi examples/zk_private_demo/abi.json \
--out deposit.ts
// auto-generated by @zerostyl/sdk-ts — do not edit
import type { Hex } from '@zerostyl/sdk-ts';
export const DepositCircuit = {
name: "deposit",
version: "1.0.0",
defaultK: 10,
numPublicInputs: 1,
numPrivateWitnesses: 3,
} as const;
export interface DepositWitness {
collateral: bigint;
collateral_nonce: Hex;
threshold: bigint;
}
export interface DepositPublicInputs {
collateral_commitment: Hex;
}
Type mapping: u64/u128 → bigint, bool → boolean, fp/bytes32/address → Hex, arrays
→ ReadonlyArray<…>.
Python
Install the SDK (pure Python, no build step) and run the same generation:
pip install zerostyl-sdk
zerostyl-sdk-py generate --abi examples/zk_private_demo/abi.json --out deposit.py
# auto-generated by zerostyl-sdk (python) — do not edit
from dataclasses import dataclass
from typing import Final
DEPOSIT_CIRCUIT: Final = {
"name": 'deposit',
"version": '1.0.0',
"default_k": 10,
"num_public_inputs": 1,
"num_private_witnesses": 3,
}
@dataclass(frozen=True)
class DepositWitness:
collateral: int
collateral_nonce: str
threshold: int
@dataclass(frozen=True)
class DepositPublicInputs:
collateral_commitment: str
Type mapping: u64/u128 → int, bool → bool, fp/bytes32/address → str (0x-hex),
arrays → tuple[…, ...]. Field names that collide with Python keywords are suffixed (from →
from_).
What the bindings give you
The generated types mirror the circuit exactly: a …Witness shape for the private inputs you feed
the prover, a …PublicInputs shape for the values the verifier checks, and a circuit-metadata
constant (name, k, input counts). They keep your client code in lock-step with the circuit — if
the abi.json changes, regenerate and the compiler flags every call site that no longer matches.
The SDKs generate types. Proof generation from TypeScript/Python (bindings to the Rust prover)
is planned for a later release — produce proofs with the Rust SDK or the zerostyl-prove CLI (see
Prove & verify with the Rust SDK) and carry the typed
public-inputs/witness shapes on the client.
Next steps
- Rust proving loop → Prove & verify with the Rust SDK.
- The event and fingerprint an indexer decodes → Events & Fingerprinting.