Docs/Sdk/Api Reference

SDK API Reference

Complete API reference for @zkmix/sdk

SDK API Reference

This page documents every public class, method, and type exported by the @zkmix/sdk package.

ZKMix Class

The ZKMix class is the main entry point for all SDK operations. It manages connections, pool discovery, proof generation, and transaction submission.

Constructor

typescript
constructor(config: ZKMixConfig)

Creates a new ZKMix instance.

Parameters:

typescript
interface ZKMixConfig {
  /** Solana RPC connection */
  connection: Connection;

  /** Solana cluster identifier */
  cluster: "mainnet-beta" | "devnet" | "localnet";

  /** URL to the proving key file (required for browser proof generation) */
  provingKeyUrl?: string;

  /** URL to the WASM circuit file (required for browser proof generation) */
  wasmUrl?: string;

  /** Path to the proving key file (Node.js only) */
  provingKeyPath?: string;

  /** Path to the WASM circuit file (Node.js only) */
  wasmPath?: string;

  /** Override the default Mixer Program ID */
  mixerProgramId?: PublicKey;

  /** Override the default Verifier Program ID */
  verifierProgramId?: PublicKey;
}

Example:

typescript
import { Connection } from "@solana/web3.js";
import { ZKMix } from "@zkmix/sdk";

const zkmix = new ZKMix({
  connection: new Connection("https://api.mainnet-beta.solana.com"),
  cluster: "mainnet-beta",
});

deposit()

typescript
async deposit(params: DepositParams): Promise<DepositResult>

Deposits funds into a ZKMix pool. Generates a random commitment, builds and submits the deposit transaction, and returns a DepositNote that must be saved for later withdrawal.

Parameters:

typescript
interface DepositParams {
  /** Wallet to sign the transaction and fund the deposit */
  wallet: Keypair | WalletAdapter;

  /** Token symbol ("SOL") or mint address for SPL tokens */
  token: string | PublicKey;

  /** Deposit amount in smallest units (lamports for SOL, base units for SPL) */
  denomination: number | bigint;

  /** Optional transaction configuration */
  options?: TransactionOptions;
}

interface TransactionOptions {
  /** Confirmation commitment level */
  commitment?: "processed" | "confirmed" | "finalized";

  /** Maximum number of retry attempts */
  maxRetries?: number;

  /** Whether to skip preflight simulation */
  skipPreflight?: boolean;

  /** Compute unit limit override */
  computeUnits?: number;

  /** Priority fee in microlamports per compute unit */
  priorityFee?: number;
}

Returns:

typescript
interface DepositResult {
  /** The deposit note containing secret, nullifier, and metadata */
  note: DepositNote;

  /** The transaction signature */
  txSignature: string;

  /** The commitment hash inserted into the Merkle tree */
  commitment: string;

  /** The leaf index in the Merkle tree */
  leafIndex: number;

  /** The block time of the confirmed transaction */
  blockTime: number;
}

Errors:

ErrorDescription
PoolNotFoundErrorNo pool exists for the given token and denomination
PoolInactiveErrorThe pool is currently paused
InsufficientFundsErrorWallet balance is below the denomination
TransactionErrorThe transaction failed on-chain

Example:

typescript
const result = await zkmix.deposit({
  wallet: myKeypair,
  token: "SOL",
  denomination: 1_000_000_000,
});

console.log(`Deposited! Leaf index: ${result.leafIndex}`);
// Save result.note.serialize() securely

withdraw()

typescript
async withdraw(params: WithdrawParams): Promise<WithdrawResult>

Withdraws funds from a ZKMix pool. Fetches the Merkle tree, generates a zero-knowledge proof, and submits the withdrawal transaction either directly or through a relayer.

Parameters:

typescript
interface WithdrawParams {
  /** The deposit note from a previous deposit */
  deposit: DepositNote;

  /** The recipient address for the withdrawn funds */
  recipient: PublicKey;

  /** Whether to use a relayer for gas-less withdrawal */
  useRelayer?: boolean;

  /** Specific relayer URL (overrides automatic selection) */
  relayerUrl?: string;

  /** Wallet to sign and pay for the transaction (required if useRelayer is false) */
  wallet?: Keypair | WalletAdapter;

  /** Optional transaction configuration */
  options?: TransactionOptions;
}

Returns:

typescript
interface WithdrawResult {
  /** The transaction signature */
  txSignature: string;

  /** The nullifier hash that was spent */
  nullifierHash: string;

  /** The relayer fee paid (0 if no relayer was used) */
  relayerFee: number;

  /** The net amount received by the recipient */
  amountReceived: number;

  /** The block time of the confirmed transaction */
  blockTime: number;
}

Errors:

ErrorDescription
InvalidNoteErrorThe deposit note is malformed or corrupted
NoteAlreadySpentErrorThis deposit has already been withdrawn
ProofGenerationErrorFailed to generate the ZK proof
NoRelayerAvailableErrorNo relayer is available for this pool
RelayerErrorThe relayer rejected the request or returned an error
TransactionErrorThe transaction failed on-chain

Example:

typescript
const result = await zkmix.withdraw({
  deposit: savedNote,
  recipient: freshAddress,
  useRelayer: true,
});

console.log(`Withdrawn! Tx: ${result.txSignature}`);
console.log(`Amount received: ${result.amountReceived} lamports`);

getDeposits()

typescript
async getDeposits(params: GetDepositsParams): Promise<DepositEvent[]>

Fetches deposit events from a specific pool. This is useful for reconstructing the Merkle tree state, computing anonymity set sizes, or building analytics dashboards.

Parameters:

typescript
interface GetDepositsParams {
  /** Token symbol or mint address */
  token: string | PublicKey;

  /** Pool denomination */
  denomination: number | bigint;

  /** Starting leaf index (inclusive, default: 0) */
  fromIndex?: number;

  /** Ending leaf index (exclusive, default: latest) */
  toIndex?: number;

  /** Maximum number of events to return */
  limit?: number;
}

Returns:

typescript
interface DepositEvent {
  /** The commitment hash */
  commitment: string;

  /** The leaf index in the Merkle tree */
  leafIndex: number;

  /** Unix timestamp of the deposit */
  timestamp: number;

  /** Transaction signature */
  txSignature: string;
}

Example:

typescript
// Get the last 100 deposits to the SOL-1 pool
const deposits = await zkmix.getDeposits({
  token: "SOL",
  denomination: 1_000_000_000,
  limit: 100,
});

console.log(`Found ${deposits.length} recent deposits`);
deposits.forEach((d) => {
  console.log(`  Leaf ${d.leafIndex}: ${d.commitment} at ${new Date(d.timestamp * 1000)}`);
});

generateProof()

typescript
async generateProof(params: GenerateProofParams): Promise<ProofData>

Generates a Groth16 zero-knowledge proof for a withdrawal without submitting a transaction. This is useful for advanced use cases where you want to construct the transaction yourself or submit the proof through a custom relayer integration.

Parameters:

typescript
interface GenerateProofParams {
  /** The deposit note */
  deposit: DepositNote;

  /** The recipient address */
  recipient: PublicKey;

  /** The relayer fee (use 0 for direct withdrawals) */
  relayerFee: number | bigint;

  /** The Merkle tree state (fetched automatically if not provided) */
  treeState?: MerkleTreeState;
}

Returns:

typescript
interface ProofData {
  /** The serialized proof */
  proof: {
    a: [string, string];
    b: [[string, string], [string, string]];
    c: [string, string];
  };

  /** The public inputs */
  publicInputs: {
    root: string;
    nullifierHash: string;
    recipient: string;
    fee: string;
  };

  /** Time taken to generate the proof in milliseconds */
  generationTime: number;
}

Example:

typescript
// Generate proof without submitting
const proofData = await zkmix.generateProof({
  deposit: savedNote,
  recipient: freshAddress,
  relayerFee: 3_000_000,
});

console.log(`Proof generated in ${proofData.generationTime}ms`);
console.log(`Root: ${proofData.publicInputs.root}`);
console.log(`Nullifier hash: ${proofData.publicInputs.nullifierHash}`);

// Submit the proof manually through a custom relayer
const response = await fetch("https://my-custom-relayer.com/relay", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    proof: proofData.proof,
    ...proofData.publicInputs,
    poolAddress: poolAddress.toBase58(),
  }),
});

Utility Functions

getPools()

typescript
async getPools(): Promise<PoolInfo[]>

Returns a list of all active ZKMix pools with their current state.

typescript
interface PoolInfo {
  /** Pool account address */
  address: PublicKey;

  /** Token symbol */
  token: string;

  /** Token mint address */
  tokenMint: PublicKey;

  /** Denomination in smallest units */
  denomination: bigint;

  /** Human-readable denomination */
  denominationFormatted: string;

  /** Total number of deposits */
  depositCount: number;

  /** Number of withdrawals (spent nullifiers) */
  withdrawalCount: number;

  /** Current anonymity set size (deposits - withdrawals) */
  anonymitySetSize: number;

  /** Whether the pool is accepting deposits */
  isActive: boolean;

  /** Merkle tree capacity */
  treeCapacity: number;

  /** Current tree utilization (0.0 to 1.0) */
  treeUtilization: number;

  /** Vault balance in smallest units */
  vaultBalance: bigint;
}

Example:

typescript
const pools = await zkmix.getPools();

for (const pool of pools) {
  console.log(`${pool.denominationFormatted} - ${pool.anonymitySetSize} deposits`);
}

getPoolInfo()

typescript
async getPoolInfo(token: string | PublicKey, denomination: number | bigint): Promise<PoolInfo>

Returns detailed information about a specific pool.

typescript
const info = await zkmix.getPoolInfo("SOL", 1_000_000_000);
console.log(`Anonymity set: ${info.anonymitySetSize}`);
console.log(`Vault balance: ${info.vaultBalance} lamports`);

parseNote()

typescript
parseNote(noteString: string): DepositNote

Deserializes a deposit note from its string representation.

typescript
const note = zkmix.parseNote("zkmix-1.0-devnet-SOL-1000000000-0x3a4b...-0x9e0f...-42");
console.log(`Token: ${note.token}`);
console.log(`Denomination: ${note.denomination}`);
console.log(`Leaf index: ${note.leafIndex}`);

isNoteSpent()

typescript
async isNoteSpent(note: DepositNote): Promise<boolean>

Checks whether a deposit note has already been used for a withdrawal by querying the on-chain nullifier set.

typescript
const spent = await zkmix.isNoteSpent(savedNote);
if (spent) {
  console.log("This deposit has already been withdrawn");
} else {
  console.log("This deposit is still available for withdrawal");
}

getRelayers()

typescript
async getRelayers(poolAddress?: PublicKey): Promise<RelayerInfo[]>

Fetches available relayers from the on-chain registry. Optionally filters to relayers that support a specific pool.

typescript
interface RelayerInfo {
  /** Relayer's Solana address */
  address: PublicKey;

  /** Relayer's HTTP endpoint */
  url: string;

  /** Fee percentage in basis points */
  feePercentage: number;

  /** Whether the relayer is currently active */
  isActive: boolean;

  /** Pools the relayer supports */
  supportedPools: PublicKey[];

  /** SOL staked by the relayer */
  stake: bigint;
}

Example:

typescript
const relayers = await zkmix.getRelayers();
console.log(`${relayers.length} relayers available`);

for (const relayer of relayers) {
  console.log(`  ${relayer.url} - ${relayer.feePercentage / 100}% fee`);
}

verifyVaultIntegrity()

typescript
async verifyVaultIntegrity(token: string | PublicKey, denomination: number | bigint): Promise<VaultIntegrityResult>

Verifies that a pool's vault balance matches the expected value based on deposit and withdrawal counts.

typescript
interface VaultIntegrityResult {
  /** Whether the vault balance is correct */
  isValid: boolean;

  /** Expected vault balance */
  expectedBalance: bigint;

  /** Actual vault balance */
  actualBalance: bigint;

  /** Difference (0 if valid) */
  difference: bigint;
}

Example:

typescript
const integrity = await zkmix.verifyVaultIntegrity("SOL", 1_000_000_000);

if (integrity.isValid) {
  console.log("Vault integrity verified");
} else {
  console.error(
    `Vault mismatch! Expected ${integrity.expectedBalance}, ` +
    `got ${integrity.actualBalance}`
  );
}

DepositNote Class

The DepositNote class encapsulates all data needed to withdraw a deposit. It is returned by deposit() and consumed by withdraw().

Properties

typescript
class DepositNote {
  /** The random secret (private, never shared) */
  readonly secret: Uint8Array;

  /** The random nullifier (private, never shared) */
  readonly nullifier: Uint8Array;

  /** The commitment hash (public, stored on-chain) */
  readonly commitment: string;

  /** The nullifier hash (public, revealed during withdrawal) */
  readonly nullifierHash: string;

  /** Token identifier */
  readonly token: string;

  /** Pool denomination */
  readonly denomination: bigint;

  /** Leaf index in the Merkle tree */
  readonly leafIndex: number;

  /** Network cluster */
  readonly cluster: string;
}

Methods

serialize()

typescript
serialize(): string

Serializes the deposit note to a compact string format for storage.

typescript
const noteString = note.serialize();
// "zkmix-1.0-devnet-SOL-1000000000-0x3a4b5c6d...-0x9e0f1a2b...-42"

toJSON()

typescript
toJSON(): object

Returns a JSON-serializable representation of the note.

typescript
const json = note.toJSON();
// {
//   version: "1.0",
//   cluster: "devnet",
//   token: "SOL",
//   denomination: "1000000000",
//   secret: "0x3a4b5c6d...",
//   nullifier: "0x9e0f1a2b...",
//   commitment: "0x1234abcd...",
//   leafIndex: 42
// }