@zkbounty/zk-sdk
v1.0.0
Published
Prove real-world physical action on Solana with hardware attestation and zero-knowledge. Capture, redact PII, prove, and settle on-chain.
Maintainers
Readme
@zkbounty/sdk
Prove a real-world action happened - at a specific coordinate, in a specific Solana slot, on a specific device - using hardware attestation and zero-knowledge. The SDK reads device metadata, strips personal identifiers, generates a succinct proof, and settles it against the on-chain verifier program. No proving infrastructure to run.
npm install @zkbounty/sdkQuickstart
import { ZkBounty } from "@zkbounty/sdk";
const zk = new ZkBounty({ cluster: "mainnet-beta" });
// 1. Capture - reads enclave signature, GPS lock, sensor signature + slot hash
const attested = await zk.capture({
bountyId: "bnt_3f9a…",
action: "photo",
});
// 2. Prove - strips PII, generates the zk proof locally
const proof = await zk.prove(attested, {
geofence: { lat: -3.46531, lng: -54.7233, radiusM: 120 },
requiredAttestations: ["enclave", "geo", "sensor", "slot"],
deviceClass: "secure-enclave",
});
// 3. Submit - the verifier program settles in one transaction
const receipt = await zk.submit(proof);
console.log(receipt.status); // "verified"
console.log(receipt.slot); // 353_120_991
console.log(receipt.payout); // { sol: 12, lamports: 12_000_000_000 }Or the whole flow in one call:
const receipt = await zk.proveAndSubmit(
{ bountyId: "bnt_3f9a…", action: "photo" },
{ geofence: { lat: -3.46531, lng: -54.7233, radiusM: 120 } },
);Privacy
Personal identifiers are stripped on the device, before any proof is generated.
prove() redacts automatically; call redact() explicitly for control:
const redacted = zk.redact(attested, {
faces: "blur+drop", // bystander privacy
deviceId: "drop", // no device fingerprint
exif: "drop", // no embedded identity
keep: ["contentHash"],
});
const proof = await zk.prove(redacted, criteria);
// proof.publicInputs -> { coordInGeofence: true, slotInWindow: true, ... }
// nothing else leaves the deviceAPI
new ZkBounty(config?)
| option | default | description |
| ------------ | ------------------------ | -------------------------------------------- |
| cluster | "mainnet-beta" | Solana cluster to settle against |
| apiUrl | https://api.zk-bounty.com | REST + WS API base |
| rpcUrl | public RPC for cluster | Solana JSON-RPC endpoint |
| enclaveKey | generated | hex ed25519 device key (from secure enclave) |
| apiKey | - | bearer token for authenticated calls |
| fetch | globalThis.fetch | custom fetch (non-browser runtimes) |
Methods
capture(options)→AttestedCapture- read device metadata and produce the four hardware attestations (enclave, geo, sensor, slot).redact(capture, options?)→AttestedCapture- strip PII locally.prove(capture, criteria?)→Proof- generate the zero-knowledge proof and compute public inputs against the bounty criteria.submit(proof)→SubmitReceipt- settle on-chain via the verifier program.proveAndSubmit(options, criteria?)→SubmitReceipt- the full pipeline.recentSlot()→{ slot, slotHash }- current slot + recent block hash.
All types are exported (AttestedCapture, Proof, BountyCriteria,
SubmitReceipt, …).
Runtimes
Works in the browser (uses the Geolocation API automatically) and in Node 18+,
Deno, and Bun (pass coordinate explicitly when there's no Geolocation API).
License
MIT
