Skip to content

Latest commit

 

History

History
749 lines (529 loc) · 20.6 KB

File metadata and controls

749 lines (529 loc) · 20.6 KB

SDK API Reference

Classes

Idempotent payroll retries

Use idempotencyKey when submitting payroll payments so client-side retries do not create duplicate submissions.

import { PayrollService, createPaymentIdempotencyKey } from "@zk-payroll/sdk";

const key = createPaymentIdempotencyKey({
  recipient: "G...",
  amount: 1000n,
  asset: "native",
});

const result = await service.processPayment({
  recipient: "G...",
  amount: 1000n,
  asset: "native",
  idempotencyKey: key,
});

Recommendation

  • Generate one idempotency key per user intent (for example, button click / request ID)
  • Reuse the same key for retries of that same intent
  • Use a new key for genuinely new payment requests

Typed Contract Clients

The SDK provides fully typed client wrappers for the core ZK Payroll Soroban contracts. Each client extends BaseContractWrapper and handles XDR encoding/decoding automatically.

PayrollRegistryClient

Typed client for the payroll_registry contract. Manages employer-employee payroll relationships.

constructor(server: rpc.Server, contractId: string, options?: ClientOptions)

Param Type Description
server rpc.Server Soroban RPC server instance
contractId string Deployed contract address
options.networkPassphrase string Network passphrase (default: Networks.TESTNET)

register(request: RegisterRequest, signer: Keypair, network?: string): Promise<void>

Registers a new payroll relationship.

interface RegisterRequest {
  employer: string;   // Stellar address
  employee: string;   // Stellar address
  salary: bigint;     // Amount in stroops
  token: string;      // Token contract address
  metadata?: string;  // Optional description
}

getRegistry(employer: string, employee: string, signer: Keypair, network?: string): Promise<RegistryEntry>

Returns the payroll registry entry for an employer-employee pair.

interface RegistryEntry {
  employer: string;
  employee: string;
  salary: bigint;
  token: string;
  metadata: string;
  active: boolean;
  createdAt: number;
  updatedAt: number;
}

updateRegistry(request: UpdateRegistryRequest, signer: Keypair, network?: string): Promise<void>

Updates the salary for an existing registry entry.

interface UpdateRegistryRequest {
  employer: string;
  employee: string;
  salary: bigint;
}

deactivateRegistry(employer: string, employee: string, signer: Keypair, network?: string): Promise<void>

Deactivates a payroll registry entry.

getEmployeeCount(employer: string, signer: Keypair, network?: string): Promise<number>

Returns the number of employees registered under an employer.

getEmployees(employer: string, start: number, limit: number, signer: Keypair, network?: string): Promise<string[]>

Returns a paginated list of employee addresses for an employer.

registryExists(employer: string, employee: string, signer: Keypair, network?: string): Promise<boolean>

Checks if a registry entry exists for the given employer-employee pair.


SalaryCommitmentClient

Typed client for the salary_commitment contract. Handles salary commitments with ZK proof verification.

constructor(server: rpc.Server, contractId: string, options?: ClientOptions)

Same constructor pattern as PayrollRegistryClient.

commit(request: CommitRequest, signer: Keypair, network?: string): Promise<void>

Commits to a salary amount for a specific pay cycle using a hash.

interface CommitRequest {
  employer: string;
  employee: string;
  commitmentHash: string;  // Hex-encoded hash
  cycleId: bigint;
}

getCommitment(employer: string, employee: string, cycleId: bigint, signer: Keypair, network?: string): Promise<CommitmentEntry>

Returns the salary commitment for a specific cycle.

interface CommitmentEntry {
  employer: string;
  employee: string;
  commitmentHash: string;
  cycleId: bigint;
  createdAt: number;
  revealed: boolean;
  actualAmount: bigint;
}

batchCommit(employer: string, commitments: BatchCommitItem[], signer: Keypair, network?: string): Promise<void>

Commits multiple salaries in a single transaction.

interface BatchCommitItem {
  employee: string;
  commitmentHash: string;
  cycleId: bigint;
}

verifyCommitment(employer: string, employee: string, cycleId: bigint, proof: ProofStruct, signer: Keypair, network?: string): Promise<boolean>

Verifies a salary commitment against a ZK proof.

revealSalary(employer: string, employee: string, cycleId: bigint, actualAmount: bigint, signer: Keypair, network?: string): Promise<void>

Reveals the actual salary for a previously committed cycle.

getCommitmentCount(employer: string, employee: string, signer: Keypair, network?: string): Promise<number>

Returns the number of commitment cycles for an employer-employee pair.


ProofVerifierClient

Typed client for the proof_verifier contract. Manages ZK proof verification and verification keys.

constructor(server: rpc.Server, contractId: string, options?: ClientOptions)

Same constructor pattern.

verify(proof: ProofStruct, publicInputs: string[], verificationKeyId: number, signer: Keypair, network?: string): Promise<boolean>

Verifies a ZK proof against a verification key.

interface ProofStruct {
  pi_a: [string, string];
  pi_b: [[string, string], [string, string]];
  pi_c: [string, string];
  publicSignals: string[];
}

addVerificationKey(vk: string, description: string, signer: Keypair, network?: string): Promise<number>

Adds a new verification key and returns its ID.

getVerificationKey(id: number, signer: Keypair, network?: string): Promise<string>

Returns the raw verification key bytes as hex.

setActiveVerificationKey(id: number, signer: Keypair, network?: string): Promise<void>

Sets the active verification key by ID.

getActiveVerificationKeyId(signer: Keypair, network?: string): Promise<number>

Returns the ID of the currently active verification key.

getVerificationKeyCount(signer: Keypair, network?: string): Promise<number>

Returns the total number of verification keys stored.

getVerificationKeyInfo(id: number, signer: Keypair, network?: string): Promise<VerificationKeyInfo>

Returns metadata for a verification key.

interface VerificationKeyInfo {
  id: number;
  description: string;
  key: string;  // Hex-encoded
}

PaymentExecutorClient

Typed client for the payment_executor contract. Handles executing and scheduling payments.

constructor(server: rpc.Server, contractId: string, options?: ClientOptions)

Same constructor pattern.

execute(request: ExecutePaymentRequest, signer: Keypair, network?: string): Promise<ExecutePaymentResponse>

Executes an immediate payment.

interface ExecutePaymentRequest {
  recipient: string;
  amount: bigint;
  asset: string;
  memo?: string;
}

interface ExecutePaymentResponse {
  txHash: string;
}

schedule(request: SchedulePaymentRequest, signer: Keypair, network?: string): Promise<SchedulePaymentResponse>

Schedules a future payment.

interface SchedulePaymentRequest {
  recipient: string;
  amount: bigint;
  asset: string;
  executeAt: number;   // Unix timestamp
  memo?: string;
}

interface SchedulePaymentResponse {
  paymentId: bigint;
}

cancel(paymentId: bigint, signer: Keypair, network?: string): Promise<void>

Cancels a scheduled payment.

getScheduledPayment(paymentId: bigint, signer: Keypair, network?: string): Promise<ScheduledPayment>

Returns details of a scheduled payment.

interface ScheduledPayment {
  id: bigint;
  employer: string;
  recipient: string;
  amount: bigint;
  asset: string;
  executeAt: number;
  memo: string;
  executed: boolean;
  cancelled: boolean;
  createdAt: number;
}

getPendingPayments(employer: string, start: bigint, limit: number, signer: Keypair, network?: string): Promise<ScheduledPayment[]>

Returns a paginated list of pending (non-executed, non-cancelled) payments for an employer.

getPaymentCount(employer: string, signer: Keypair, network?: string): Promise<number>

Returns the total number of payments scheduled by an employer.


PayrollService

Main entry point for payroll operations.

constructor(config: ClientConfig)

Initializes the service with network configuration.

processPayment(recipient: string, amount: bigint): Promise<string>

Generates a ZK proof and submits a payment transaction to the smart contract.

  • recipient: Stellar address of the employee.
  • amount: Salary amount to pay.
  • Returns: Transaction hash.

PayrollContract

Low-level wrapper for direct smart contract interactions.

SnarkjsProofGenerator

Production-ready ZK proof generator using snarkjs library.

constructor(config: ProofGeneratorConfig, cache?: CacheProvider<string>)

Creates a new proof generator instance.

  • config: Circuit artifact URLs and cache settings
  • cache: Optional cache provider for proof results

generateProof(witness: Record<string, unknown>): Promise<ProofPayload>

Generates a Groth16 zero-knowledge proof.

  • witness: Circuit inputs (must match circuit's input signal names)
  • Returns: ProofPayload formatted for smart contract verification

clearArtifactCache(): void

Clears cached .wasm and .zkey files to force re-download.

ZKProofGenerator

Legacy proof generator with factory methods for backward compatibility.

static generateProof(witness: any, cache?: CacheProvider<string>): Promise<Uint8Array>

Deprecated: Generates a simulated proof. Use SnarkjsProofGenerator for production.

static createSnarkjsGenerator(config: ProofGeneratorConfig, cache?: CacheProvider<string>): SnarkjsProofGenerator

Factory method to create a configured SnarkjsProofGenerator instance.

static generateSnarkjsProof(witness: Record<string, unknown>, config: ProofGeneratorConfig, cache?: CacheProvider<string>): Promise<ProofPayload>

Convenience method to generate a proof without creating a generator instance.

Interfaces

ClientConfig

  • networkUrl: RPC URL for the Stellar network.
  • contractId: ID of the deployed Payroll contract.

IProofGenerator

Interface for zero-knowledge proof generation implementations.

generateProof(witness: Record<string, unknown>): Promise<ProofPayload>

Generates a zero-knowledge proof for the given witness data.

ProofGeneratorConfig

Configuration for proof generation artifacts.

  • wasmUrl: URL or path to the circuit .wasm file
  • zkeyUrl: URL or path to the proving key .zkey file
  • artifactCacheTTL: Optional cache TTL in seconds for proof results

ProofPayload

Structured proof payload compatible with Solidity/Soroban verifiers.

interface ProofPayload {
  proof: {
    pi_a: [string, string];
    pi_b: [[string, string], [string, string]];
    pi_c: [string, string];
    protocol: string;
    curve: string;
  };
  publicSignals: string[];
}

Cache Providers

MemoryCacheProvider<T>

In-memory cache implementation (lost on page reload).

constructor()

Creates a new memory cache instance.

LocalStorageCacheProvider

Browser localStorage-based cache (persists across sessions).

constructor(keyPrefix?: string)

Creates a new localStorage cache with optional key prefix.

Usage Examples

Typed Client — PayrollRegistryClient

import { rpc, Keypair } from "@stellar/stellar-sdk";
import { PayrollRegistryClient } from "@zk-payroll/sdk";

const server = new rpc.Server("https://soroban-testnet.stellar.org");
const signer = Keypair.fromSecret("S...");

const registry = new PayrollRegistryClient(server, "CCONTRACT_ID...");

// Register a new employee
await registry.register({
  employer: "GEMPLOYER...",
  employee: "GEMPLOYEE...",
  salary: 1000n,
  token: "CTOKEN...",
  metadata: "engineering",
}, signer);

// Query
const entry = await registry.getRegistry("GEMPLOYER...", "GEMPLOYEE...", signer);
console.log(entry.active, entry.salary);

// Update salary
await registry.updateRegistry({
  employer: "GEMPLOYER...",
  employee: "GEMPLOYEE...",
  salary: 2000n,
}, signer);

// Paginated employee list
const employees = await registry.getEmployees("GEMPLOYER...", 0, 10, signer);

// Deactivate
await registry.deactivateRegistry("GEMPLOYER...", "GEMPLOYEE...", signer);

Typed Client — SalaryCommitmentClient

import { SalaryCommitmentClient } from "@zk-payroll/sdk";

const client = new SalaryCommitmentClient(server, "CCONTRACT_ID...");

// Commit to a salary
await client.commit({
  employer: "GEMPLOYER...",
  employee: "GEMPLOYEE...",
  commitmentHash: "deadbeef...",
  cycleId: 1n,
}, signer);

// Retrieve commitment
const commitment = await client.getCommitment("GEMPLOYER...", "GEMPLOYEE...", 1n, signer);

// Batch commit
await client.batchCommit("GEMPLOYER...", [
  { employee: "G1...", commitmentHash: "abcd", cycleId: 1n },
  { employee: "G2...", commitmentHash: "ef01", cycleId: 1n },
], signer);

// Reveal salary
await client.revealSalary("GEMPLOYER...", "GEMPLOYEE...", 1n, 1500n, signer);

Typed Client — ProofVerifierClient

import { ProofVerifierClient } from "@zk-payroll/sdk";

const client = new ProofVerifierClient(server, "CCONTRACT_ID...");

// Verify a proof
const valid = await client.verify(
  { pi_a: ["1","2"], pi_b: [["3","4"],["5","6"]], pi_c: ["7","8"], publicSignals: ["sig"] },
  ["public_input"],
  1,  // verification key ID
  signer
);

// Add verification key
const vkId = await client.addVerificationKey("aabbccdd...", "groth16 bn128", signer);

// Query key info
const info = await client.getVerificationKeyInfo(vkId, signer);

// Set as active
await client.setActiveVerificationKey(vkId, signer);

Typed Client — PaymentExecutorClient

import { PaymentExecutorClient } from "@zk-payroll/sdk";

const client = new PaymentExecutorClient(server, "CCONTRACT_ID...");

// Execute immediate payment
const execResult = await client.execute({
  recipient: "GPAYEE...",
  amount: 1000n,
  asset: "CNATIVE...",
  memo: "monthly salary",
}, signer);
console.log("TxHash:", execResult.txHash);

// Schedule payment
const scheduleResult = await client.schedule({
  recipient: "GPAYEE...",
  amount: 500n,
  asset: "CNATIVE...",
  executeAt: Math.floor(Date.now() / 1000) + 86400,
  memo: "bonus",
}, signer);

// Cancel scheduled payment
await client.cancel(scheduleResult.paymentId, signer);

// List pending payments
const pending = await client.getPendingPayments("GEMPLOYER...", 0n, 20, signer);

Basic Proof Generation

import { SnarkjsProofGenerator, ProofGeneratorConfig } from "@zk-payroll/sdk";

const config: ProofGeneratorConfig = {
  wasmUrl: "https://cdn.example.com/circuit.wasm",
  zkeyUrl: "https://cdn.example.com/circuit.zkey",
  artifactCacheTTL: 86400,
};

const generator = new SnarkjsProofGenerator(config);

const witness = {
  recipient: "GDZQHV...",
  amount: 1000000n,
  nullifier: 123456789n,
  secret: 987654321n,
};

const proof = await generator.generateProof(witness);

With Caching

import { SnarkjsProofGenerator, MemoryCacheProvider } from "@zk-payroll/sdk";

const cache = new MemoryCacheProvider<string>();
const generator = new SnarkjsProofGenerator(config, cache);

// First call generates and caches
const proof1 = await generator.generateProof(witness);

// Second call returns cached result
const proof2 = await generator.generateProof(witness);

Using Factory Methods

import { ZKProofGenerator } from "@zk-payroll/sdk";

// Create generator
const generator = ZKProofGenerator.createSnarkjsGenerator(config, cache);

// Or generate directly
const proof = await ZKProofGenerator.generateSnarkjsProof(witness, config);

Error Handling

All errors are wrapped in ZkPayrollError subclasses:

import { PayrollError } from "@zk-payroll/sdk";

try {
  const proof = await generator.generateProof(witness);
} catch (error) {
  if (error instanceof PayrollError) {
    console.error(`Error ${error.code}: ${error.message}`);
  }
}

Contract Metadata Discovery

The SDK provides helpers for discovering and validating deployed contract metadata across common Stellar environments, reducing manual wiring when connecting to testnet, mainnet, or local standalone networks.

getContractMetadata(environment, overrides?)

Returns the default metadata for a known environment, with optional field overrides.

Param Type Description
environment string Environment name ("testnet", "mainnet", or "standalone")
overrides Partial<ContractMetadata> Optional fields to merge on top of defaults

Throws if the environment name is not recognized.

import { getContractMetadata } from "@zk-payroll/sdk";

// Get testnet defaults
const metadata = getContractMetadata("testnet");
// {
//   networkUrl: "https://soroban-testnet.stellar.org",
//   networkPassphrase: "Test SDF Network ; September 2015",
// }

// Override with deployed contract IDs
const deployed = getContractMetadata("testnet", {
  payrollRegistryId: "CA3D5K7UZH7G4FZ...",
  salaryCommitmentId: "CB3D5K7UZH7G4FZ...",
  proofVerifierId: "CC3D5K7UZH7G4FZ...",
  paymentExecutorId: "CD3D5K7UZH7G4FZ...",
  adminPublicKey: "SAV75E2NK7Q5J2Y...",
});

validateContractMetadata(metadata)

Validates a ContractMetadata object and returns a structured result with actionable errors.

Param Type Description
metadata ContractMetadata The metadata to validate

Returns { valid: boolean, errors: MetadataValidationError[] }. Each error has field, message, and code properties.

import { validateContractMetadata } from "@zk-payroll/sdk";

const result = validateContractMetadata({
  networkUrl: "https://soroban-testnet.stellar.org",
  networkPassphrase: "Test SDF Network ; September 2015",
  payrollRegistryId: "CA3D5K7UZH7G4FZ...",
});

if (!result.valid) {
  for (const err of result.errors) {
    console.error(`[${err.code}] ${err.field}: ${err.message}`);
  }
}

Validation checks:

  • networkUrl is a valid HTTP(S) URL
  • networkPassphrase matches a known Stellar network
  • payrollRegistryId, salaryCommitmentId, proofVerifierId, paymentExecutorId are valid Soroban contract ID format (starts with C, 56 alphanumeric characters)
  • adminPublicKey is a valid Stellar secret key format (starts with S, 56 characters)
  • Required fields (networkUrl, networkPassphrase) are present and non-empty

isKnownEnvironment(environment)

Returns true if the given environment name is recognized.

import { isKnownEnvironment } from "@zk-payroll/sdk";

if (isKnownEnvironment(process.env.STELLAR_ENV)) {
  // proceed
}

listKnownEnvironments()

Returns the list of known environment descriptors.

import { listKnownEnvironments } from "@zk-payroll/sdk";

const envs = listKnownEnvironments();
// [
//   { name: "testnet",  label: "Stellar Testnet" },
//   { name: "mainnet",  label: "Stellar Mainnet" },
//   { name: "standalone", label: "Local Standalone" },
// ]

buildClientConfig(metadata)

Extracts networkUrl and a contract IDs map from a metadata object, suitable for constructing typed contract clients.

import {
  buildClientConfig,
  getContractMetadata,
  rpc,
  PayrollRegistryClient,
  Keypair,
} from "@zk-payroll/sdk";

const metadata = getContractMetadata("testnet", {
  payrollRegistryId: "CA3D5K7UZH7G4FZ...",
});

const config = buildClientConfig(metadata);
const server = new rpc.Server(config.networkUrl);
const signer = Keypair.fromSecret("SAV75E2NK7Q5J2Y...");

const registry = new PayrollRegistryClient(
  server,
  config.contractIds.payrollRegistryId
);

await registry.getRegistry("GEMPLOYER...", "GEMPLOYEE...", signer);

ContractMetadata

interface ContractMetadata {
  networkUrl: string;
  networkPassphrase: string;
  payrollRegistryId?: string;
  salaryCommitmentId?: string;
  proofVerifierId?: string;
  paymentExecutorId?: string;
  adminPublicKey?: string;
}

KNOWN_ENVIRONMENTS

A static array of KnownEnvironment entries defining the built-in network presets. Each entry has:

Field Type Description
name string Machine-readable key ("testnet", "mainnet", "standalone")
label string Human-readable label
metadata ContractMetadata Default network settings

See Also