OpaqueApp

Docs/Reference

SDK

Build on Opaque from JavaScript.

@opaque/sdk is the library the app is built on. It runs in Node and in the browser, and it does everything except hold your keys for you.

Accounts

import { accountFromSeed, encodeAddress } from "@opaque/sdk";

const account = accountFromSeed(seed);      // seed: 32 bytes, e.g. sha256 of a wallet signature
const address = encodeAddress(account);     // 64-byte shielded address, base58, to give out

Syncing

import { Wallet, status, sync } from "@opaque/sdk";

const wallet = new Wallet(account);
await sync(wallet, SERVER);                 // replays every leaf, nullifier, reveal and claim
const { assets } = await status(SERVER);    // each listed mint and its pool index
wallet.balance(aapl.index);                 // raw units
wallet.unspent(aapl.index);                 // notes with their leaf indices

Assets are identified inside the pool by their index, not their mint.

Transacting

import { transact, newNote, relay, transactInstructions } from "@opaque/sdk";

const tx = await transact(
  {
    account, tree: wallet.tree, auditorKey, asset: aapl.index,
    inputs: wallet.unspent(aapl.index).slice(0, 2),
    outputs: [{ note: newNote(BigInt(aapl.index), amount, recipient.owner), viewKey: recipient.viewKey }],
  },
  prove,                                     // a Prover: Node's from "@opaque/sdk/node", or a Web Worker
);
await relay(SERVER, tx);                     // or build and send the two transactions yourself:
const { stage, transact: execute } = await transactInstructions(connection, payer, tx, { mint, tokenProgram });

transact balances the notes, pads missing inputs and outputs, encrypts the memos, and returns the proof and the instruction data. Deposits set extAmount positive and are sent by the depositor; withdrawals set it negative with a recipient.

Cross

import { draftOrder, commitHash, relayCommit, proveReveal, relayReveal, crossBatches } from "@opaque/sdk";

const { open, quotePrice } = await crossBatches(SERVER, market.id);
const batch = BigInt(open.id);
const draft = draftOrder(account, market, batch, 1, qty, limit, fundingNote);
await relayCommit(SERVER, market.id, batch, commitHash(account, draft));
// ...after the batch closes at `price`:
await relayReveal(SERVER, await proveReveal(account, draft, price, wallet.tree, auditorKey, prove));

Payouts arrive as notes with one-time secrets; sync finds them from the public reveal and claim streams.

Proofs

import { proveHoldings, holdingsSignals, holdsAtLeastInstruction, disclose, readDisclosure, ANY_INDEX } from "@opaque/sdk";

const statement = await proveHoldings({ asset: aapl.index, threshold, maxIndex: ANY_INDEX }, wallet.unspent(aapl.index), wallet.tree, prove);
holdingsSignals(statement);              // the verifier's public inputs, for snarkjs
holdsAtLeastInstruction(connection, statement.proof, statement.nullifiers, statement.root, aapl.index, threshold, ANY_INDEX); // for the chain
disclose(notes, reader.viewKey);         // encrypt notes to one reader; readDisclosure opens them

Audit

import { publicShare, combine, partial, openAudit } from "@opaque/sdk";

Key holders use these through the auditor CLI; see Auditor CLI.