Get started
From npm install to a settled private trade — end to end.
This walkthrough wires the SDK into a fresh Next.js app and exercises every layer: wallet → deposit → order → settle → claim. Skim the Architecture page first if any of those words look unfamiliar.
1. Install
npm install @zkscatter/sdk ethers react@^19See Installation for Next.js wiring and Web Worker asset setup.
2. Configure the network
import {
parseTokenList,
withNativeEthAlias,
type NetworkConfig,
} from "@zkscatter/sdk";
const wethAddress = "0x...";
export const network: NetworkConfig = {
chainId: 11155111,
rpcUrl: process.env.NEXT_PUBLIC_RPC_URL!,
contracts: {
privateSettlement: "0x...",
commitmentPool: "0x...",
relayerRegistry: "0x...",
identityGate: "0x...",
feeVault: "0x...",
weth: wethAddress,
},
tokens: withNativeEthAlias(
parseTokenList(process.env.NEXT_PUBLIC_TOKEN_LIST),
wethAddress,
),
};parseTokenList expects the compact addr:symbol:decimals,… format —
useful for shipping the same config through env vars across web and mobile.
3. Mount the wallet provider
"use client";
import { WalletProvider } from "@zkscatter/sdk/react";
import { network } from "@/lib/network";
export function Providers({ children }: { children: React.ReactNode }) {
return <WalletProvider network={network}>{children}</WalletProvider>;
}import { Providers } from "./providers";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body><Providers>{children}</Providers></body>
</html>
);
}4. Deposit into the pool
"use client";
import { useWallet } from "@zkscatter/sdk/react";
import {
generateNote,
generateDepositProof,
deriveEdDSAKey,
} from "@zkscatter/sdk/zk";
import { ensureAllowance, callDeposit } from "@zkscatter/sdk/contracts";
import { network } from "@/lib/network";
export function DepositButton({ token, amount }: { token: string; amount: bigint }) {
const { signer } = useWallet();
async function deposit() {
if (!signer) throw new Error("Connect wallet first");
const eddsa = await deriveEdDSAKey(signer);
const note = generateNote(token, amount, eddsa.publicKey);
const result = await generateDepositProof(note, {
wasm: "/zk/deposit.wasm",
zkey: "/zk/deposit_final.zkey",
});
// ensureAllowance returns pending approval txs; wait for each to
// confirm before depositing or the deposit can race ahead.
const approvals = await ensureAllowance(
signer,
token,
network.contracts.commitmentPool,
amount,
);
await Promise.all(approvals.map((tx) => tx.wait()));
const tx = await callDeposit(
signer,
network.contracts.commitmentPool,
result,
token,
amount,
);
await tx.wait();
// Persist `note` + `result.commitment` — see /guides/persist-notes.
}
return <button onClick={deposit}>Deposit</button>;
}5. Discover relayers and place an order
import {
loadRelayersWithApiInfo,
RelayerClient,
type OrderData,
} from "@zkscatter/sdk/relayer";
import {
generateAuthorizeProof,
randomFieldElement,
} from "@zkscatter/sdk/zk";
const relayers = await loadRelayersWithApiInfo(
network.contracts.relayerRegistry,
readProvider,
);
const best = relayers.find((r) => r.online && r.api);
if (!best?.api) throw new Error("No relayer online");
const expiry = BigInt(Math.floor(Date.now() / 1000) + 600);
// AuthorizeProofInput uses `note.token` for the sell side — no
// separate `sellToken` field. `claims` here must match the order's
// claim distribution (see /guides/place-order for the full shape).
const authResult = await generateAuthorizeProof(
{
note,
leafIndex,
merkleProof,
sellAmount: amountIn,
buyToken: tokenB,
buyAmount: amountOut,
maxFee,
expiry,
nonce,
relayer: best.address,
eddsaPrivateKey: eddsa.privateKey,
claims: [/* stealth-addressed payouts */],
newSalt: randomFieldElement(),
},
{ wasm: "/zk/authorize.wasm", zkey: "/zk/authorize_final.zkey" },
);
const order: OrderData = {
maker: account,
sellToken: tokenA,
buyToken: tokenB,
sellAmount: amountIn.toString(),
buyAmount: amountOut.toString(),
maxFee: Number(maxFee),
expiry: Number(expiry),
nonce: Number(nonce),
claims, // wire-format claim entries
};
// `signature` is a relayer-protocol string — see the relayer's
// /api/info for the format it accepts.
const client = new RelayerClient(best.url);
await client.submitOrder(order, signature, "cover_taker");See Place an order for the complete flow, including how to build the merkle proof from indexed pool events.
6. Claim a payout
When a counterparty’s order matches yours, your stealth payout lands as a new commitment in the pool. Claim it whenever you like:
import { generateClaimProof } from "@zkscatter/sdk/zk";
import { callClaimWithProof } from "@zkscatter/sdk/contracts";
const claimResult = await generateClaimProof(claimInput, {
wasm: "/zk/claim.wasm",
zkey: "/zk/claim_final.zkey",
});
const tx = await callClaimWithProof(
signer,
network.contracts.privateSettlement,
claimResult.proof,
{ recipient, token, amount, releaseTime },
);
await tx.wait();Claims can also be batched — see Claim a payout.
What’s next
Last updated on