Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.cloak.ag/llms.txt

Use this file to discover all available pages before exploring further.

All examples use the current default program ID:
  • zh1eLd6rSphLejbFfJEneUwzHRfMKxgzrgkfwA6qRkW

Shared setup

import {
  CLOAK_PROGRAM_ID,
  NATIVE_SOL_MINT,
  createUtxo,
  createZeroUtxo,
  fullWithdraw,
  generateUtxoKeypair,
  getNkFromUtxoPrivateKey,
  partialWithdraw,
  swapWithChange,
  transact,
  scanTransactions,
  toComplianceReport,
} from "@cloak.dev/sdk";
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
import { Connection, Keypair, PublicKey } from "@solana/web3.js";

const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const USDT_MINT = new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB");

const connection = new Connection(
  "https://api.mainnet-beta.solana.com",
  "confirmed",
);
const signer = Keypair.fromSecretKey(/* Uint8Array secret key */);
const scanKeypair = await generateUtxoKeypair();
const viewingKeyNk = getNkFromUtxoPrivateKey(scanKeypair.privateKey);

const baseOptions = {
  connection,
  programId: CLOAK_PROGRAM_ID,
  depositorKeypair: signer,
  walletPublicKey: signer.publicKey,
  chainNoteViewingKeyNk: viewingKeyNk,
};

Send flow (SOL->SOL, USDC->USDC, USDT->USDT)

async function sendSameMint(args: {
  mint: PublicKey;
  amount: bigint;
  recipientWallet: PublicKey;
  partialWithdrawAmount?: bigint; // use for partial withdrawal example
}) {
  const owner = await generateUtxoKeypair();
  const output = await createUtxo(args.amount, owner, args.mint);

  const deposited = await transact(
    {
      inputUtxos: [await createZeroUtxo(args.mint)],
      outputUtxos: [output],
      externalAmount: args.amount,
      depositor: signer.publicKey,
    },
    baseOptions,
  );

  if (args.partialWithdrawAmount !== undefined) {
    return partialWithdraw(
      deposited.outputUtxos,
      args.recipientWallet,
      args.partialWithdrawAmount,
      {
        ...baseOptions,
        cachedMerkleTree: deposited.merkleTree,
      },
    );
  }

  return fullWithdraw(deposited.outputUtxos, args.recipientWallet, {
    ...baseOptions,
    cachedMerkleTree: deposited.merkleTree,
  });
}

// SOL -> SOL (full withdrawal send)
await sendSameMint({
  mint: NATIVE_SOL_MINT,
  amount: 1_000_000_000n,
  recipientWallet: Keypair.generate().publicKey,
});

// USDC -> USDC (recipient wallet must have a USDC ATA)
await sendSameMint({
  mint: USDC_MINT,
  amount: 8_000_000n,
  recipientWallet: Keypair.generate().publicKey,
});

// USDT -> USDT (recipient wallet must have a USDT ATA)
await sendSameMint({
  mint: USDT_MINT,
  amount: 8_000_000n,
  recipientWallet: Keypair.generate().publicKey,
});

// Partial withdrawal example (withdraw part, keep private change)
await sendSameMint({
  mint: NATIVE_SOL_MINT,
  amount: 1_000_000_000n,
  recipientWallet: Keypair.generate().publicKey,
  partialWithdrawAmount: 250_000_000n,
});

SOL swap flow (SOL -> token)

const swapOwner = await generateUtxoKeypair();
const swapInput = await createUtxo(600_000_000n, swapOwner, NATIVE_SOL_MINT);

const swapDeposit = await transact(
  {
    inputUtxos: [await createZeroUtxo(NATIVE_SOL_MINT)],
    outputUtxos: [swapInput],
    externalAmount: 600_000_000n,
    depositor: signer.publicKey,
  },
  baseOptions,
);

const recipientWallet = Keypair.generate().publicKey;
const recipientUsdcAta = getAssociatedTokenAddressSync(
  USDC_MINT,
  recipientWallet,
);

await swapWithChange(
  [swapDeposit.outputUtxos[0]],
  300_000_000n, // amount to swap
  USDC_MINT,
  recipientUsdcAta,
  1n, // replace with quote-based min output
  {
    ...baseOptions,
    cachedMerkleTree: swapDeposit.merkleTree,
  },
  recipientWallet,
);

Payroll flow (multi-recipient private payouts)

const payroll = [
  { wallet: Keypair.generate().publicKey, amount: 250_000_000n },
  { wallet: Keypair.generate().publicKey, amount: 400_000_000n },
  { wallet: Keypair.generate().publicKey, amount: 350_000_000n },
];

for (const payment of payroll) {
  await sendSameMint({
    mint: NATIVE_SOL_MINT,
    amount: payment.amount,
    recipientWallet: payment.wallet,
  });
}

History + compliance scan

// Reuse the same `viewingKeyNk` configured in your transaction options.

const scan = await scanTransactions({
  connection,
  programId: CLOAK_PROGRAM_ID,
  viewingKeyNk,
  limit: 250,
});

const report = toComplianceReport(scan);
console.log(report.summary);