Skip to main content
This guide takes you from zero to a working integration: install the SDK, create an OpaqueClient from a connected wallet, register your meta-address, and run a stealth send.

Prerequisites

  • Node.js 20.17+
  • An Ethereum wallet (Sepolia testnet ETH for writes)
  • Optional: Solana wallet on devnet for multichain flows
  • For scan/sweep/prove: host or load the cryptography WASM module

1. Install

npm install @opaquecash/opaque viem

2. Create the client from a wallet

OpaqueClient.fromWallet does the whole session setup in one call: it prompts the wallet once for a signature over the canonical SETUP_MESSAGE, derives the viewing and spending keys from it (your private key is never touched), and wires the wallet as the chain’s transaction signer.
import { OpaqueClient } from "@opaquecash/opaque";

const client = await OpaqueClient.fromWallet({
  wallets: { chain: "ethereum", address: userAddress, provider: window.ethereum },
  chainId: 11155111,                              // Sepolia
  rpcUrl: "https://ethereum-sepolia-rpc.publicnode.com",
  wasmModuleSpecifier: "/pkg/cryptography.js",    // required for scan/sweep/prove
});
Solana wallets use the same shape with wallet-adapter fields:
wallets: { chain: "solana", publicKey, signMessage, signTransaction }
The signature is HKDF entropy only and is never sent on-chain. Cache it (the walletSignature from requestSetupSignature) and pass it back to fromWallet to rebuild the client without prompting again. PSR schema/attestation admin does not require WASM; scanning, sweeping, and proof generation do.
If you prefer to manage the signature yourself, sign SETUP_MESSAGE manually and use OpaqueClient.create.

3. Share your meta-address

const metaAddress = client.getMetaAddressHex();
// Share this 66-byte hex so senders and issuers can pay or attest to you.
Register on-chain so others can resolve your normal address:
// High-level: submits the tx for you
const { txHash } = await client.registerMetaAddress("ethereum");

// Or build calldata and submit via your own wallet UI
const reg = client.buildRegisterMetaAddressTransaction();
await walletClient.sendTransaction({ to: reg.to, data: reg.data, chain: sepolia });

4. Send a stealth payment

sendStealthPayment resolves the recipient, derives a one-time stealth destination, transfers the native asset, and publishes the discovery announcement:
import { parseEther } from "viem";

const result = await client.sendStealthPayment({
  chain: "ethereum",
  recipient: "0xRecipientEoaAddress...",
  amount: parseEther("0.01"),
});
The recipient can be an EVM address, a 66-byte meta-address, a Solana pubkey, an ipfs:// DID document, or a *.eth name with a com.opaque.meta record. To resolve without sending (for example to show a confirmation screen):
const { metaAddressHex, source } = await client.resolveRecipient(recipientInput);
For full control (custom gas, batching, your own wallet UI), use the low-level pair:
const send = client.prepareStealthSend(metaAddressHex);
const announce = client.buildAnnounceTransactionRequest(send);
await walletClient.sendTransaction({ to: send.stealthAddress, value: parseEther("0.01"), chain: sepolia });
await walletClient.sendTransaction({ to: announce.to, data: announce.data, chain: sepolia });

5. Receive: scan and sweep

const inbox = await client.scan({ chains: ["ethereum"] });
const balances = await client.getBalancesForOutputs(inbox);

if (inbox.length > 0) {
  const { tx } = await client.sweep({
    output: inbox[0],
    chain: inbox[0].chain,
    destination: freshAddress,
  });
}
Building a React app? @opaquecash/react packages the read side as hooks; see React hooks.

Runnable examples

The SDK repo ships a runnable example per flow in sdk/examples/: from-wallet, scan, send (including a delayed announcement), psr-prove, and uab-readonly.

Next steps

Issue an attestation

Full issuer flow: schema, attest, announce.

Generate a reputation proof

Discover traits and submit a Groth16 proof on-chain.

Cross-chain inbox

UAB announcements over Wormhole.

API reference

Every OpaqueClient method documented with examples.