ZeraLabs logo
WALLET

SDK Reference

Complete function signatures, types, and constants for @zera-labs/sdk

All cryptographic operations use the BN254 scalar field (254-bit prime). Commitments and nullifiers are field elements. Proofs are Groth16 over BN254, formatted as Solana-compatible byte arrays.

Crypto Primitives

// Poseidon hashing — circomlibjs-compatible, BN254 X5
getPoseidon(): Promise<Poseidon>
poseidonHash(inputs: bigint[]): bigint
poseidonHash2(left: bigint, right: bigint): bigint
// Field ↔ bytes conversion
fieldToBytes32BE(value: bigint): Uint8Array
bytes32BEToField(bytes: Uint8Array): bigint
bigintToBytes32BE(value: bigint): Uint8Array
bytes32BEToBigint(bytes: Uint8Array): bigint
fieldToSolanaBytes(value: bigint): Uint8Array
// Keccak-256 (voucher system)
computeKeccakCommitment(secret: string): string
computeRecipientHash(pubkey: PublicKey, salt: string): string
generateRandomHex(): string
// Proof formatting
formatProofForSolana(proof: SnarkjsProof): SolanaProof
formatPublicInputsForSolana(signals: string[]): bigint[]

Note Types & Management

interface Note {
amount: bigint // raw token amount (e.g. 10_000_000n = $10 USDC)
asset: bigint // mint address → BN254 field element
secret: bigint // random 254-bit secret (never leaves client)
blinding: bigint // random 254-bit blinding factor
memo: bigint[] // 4 arbitrary 32-byte field elements
}
interface SolanaProof {
proofA: Uint8Array // 64 bytes (2 × G1 points)
proofB: Uint8Array // 128 bytes (2 × G2 points)
proofC: Uint8Array // 64 bytes (2 × G1 points)
}
createNote(amount: bigint, asset: PublicKey, memo?: bigint[]): Note
computeCommitment(note: Note): bigint
// = Poseidon(amount, secret, blinding, asset, memo[0], memo[1], memo[2], memo[3])
computeNullifier(secret: bigint, commitment: bigint): bigint
// = Poseidon(secret, commitment)
hashPubkeyToField(pubkeyBytes: Uint8Array): bigint

Merkle Tree

class MerkleTree {
static create(height?: number): Promise<MerkleTree>
// Default: height=24, capacity=16,777,216 leaves
// Node hash: Poseidon(left, right)
// Empty leaf: 0n
insert(commitment: bigint): number // → leaf index
getProof(leafIndex: number): {
pathElements: bigint[] // sibling hashes (24 elements)
pathIndices: number[] // 0=left, 1=right (24 elements)
}
getRoot(): bigint // current Merkle root
getLeaf(index: number): bigint
get nextIndex(): number // next available leaf slot
}

Proof Generators

Four circuit types, all producing Groth16 proofs via snarkjs groth16.fullProve():

// Deposit — prove correct commitment formation
generateDepositProof(
note: Note,
wasmPath: string,
zkeyPath: string
): Promise<{
proof: SolanaProof,
commitment: bigint,
publicSignals: string[]
}>
// Withdraw — prove Merkle inclusion + nullifier + recipient binding
generateWithdrawProof(
note: Note,
leafIndex: number,
tree: MerkleTree,
recipientHash: bigint,
wasmPath: string,
zkeyPath: string
): Promise<{
proof: SolanaProof,
nullifierHash: bigint,
publicSignals: string[]
}>
// Transfer — 1-input 2-output with value conservation
generateTransferProof(
inputNote: Note,
inputLeafIndex: number,
tree: MerkleTree,
outputNote1: Note,
outputNote2: Note,
wasmPath: string,
zkeyPath: string
): Promise<{
proof: SolanaProof,
nullifierHash: bigint,
outputCommitment1: bigint,
outputCommitment2: bigint,
publicSignals: string[]
}>
// Relayed Withdraw — gasless via operator relay
// Same as withdraw but includes relay fee parameters

Transaction Builders

// All builders return unsigned Solana Transactions
// Automatically derive PDAs (pool config, vault, Merkle tree, nullifiers)
buildDepositTransaction(params: DepositParams): Promise<Transaction>
buildWithdrawTransaction(params: WithdrawParams): Promise<Transaction>
buildTransferTransaction(params: TransferParams): Promise<Transaction>

PDA Derivation

derivePoolConfig(mint: PublicKey, programId?: PublicKey): PublicKey
deriveMerkleTree(mint: PublicKey, programId?: PublicKey): PublicKey
deriveVault(mint: PublicKey, programId?: PublicKey): PublicKey
deriveFeeVault(mint: PublicKey, programId?: PublicKey): PublicKey
deriveNullifier(nullifierHash: bigint, programId?: PublicKey): PublicKey
getAssociatedTokenAddress(mint: PublicKey, owner: PublicKey): PublicKey

High-Level Client & Storage

// High-level wrapper
class ZeraClient {
static create(config: ZeraClientConfig): Promise<ZeraClient>
syncTree(): Promise<void>
deposit(amount: bigint, mint: PublicKey): Promise<{ tx: Transaction, note: Note }>
withdraw(note: Note, recipient: PublicKey): Promise<{ tx: Transaction }>
transfer(inputNote: Note, splitAmounts: [bigint, bigint]):
Promise<{ tx: Transaction, notes: [Note, Note] }>
}
// On-chain state fetching
class TreeStateClient {
constructor(config: { rpcUrl: string, cacheEndpoint?: string })
fetchPoolState(): Promise<PoolState>
fetchCachedState(): Promise<CachedState>
fetchAllLeaves(forceRefresh?: boolean): Promise<bigint[]>
}
// Note persistence
interface NoteStore { save, load, delete, list }
class MemoryNoteStore implements NoteStore
class FileNoteStore implements NoteStore

Constants

TREE_HEIGHT = 24
TREE_CAPACITY = 16_777_216
BN254_PRIME = 21888242871839275222246405745257275088...617n
USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
USDC_DECIMALS = 6
ZERA_MINT = "8avjtjHAHFqp4g2RR9ALAGBpSTqKPZR8nRbzSTwZERA"
NATIVE_SOL_MINT = "So11111111111111111111111111111111111111112"
SHIELDED_POOL_PROGRAM_ID = "B83jSQx1CT1hPRBupinaJaEkCjrfeo6Ktncu31q3ZNeX"
PRIVATE_CASH_PROGRAM_ID = "ESQxpH9XkBQT6EVeWwAzTZD1e9NrLMrY8RPQ9SidYsgF"
FEE_BASIS_POINTS = 10 // 0.1%
MIN_FEE_AMOUNT = 1n

More Developer Resources

Quick Start

Deposit in 15 lines with @zera-labs/sdk

Architecture & Performance

Stack diagram, proof gen times, deployment

Testing & Security

144 tests, invariants, OFAC screening