Skip to main content

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.

Get an abi.json first

Generate 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
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/u128bigint, boolboolean, fp/bytes32/addressHex, 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
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/u128int, boolbool, fp/bytes32/addressstr (0x-hex), arrays → tuple[…, ...]. Field names that collide with Python keywords are suffixed (fromfrom_).

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.

Scope

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