Skip to content

Complete private-swap example

This example shows the full EVM path. The UI must render the quote before calling placeOrder.

import {
  AmountOutOfRangeError,
  DepositSimulationError,
  HttpError,
  createSilentSwapClient,
} from '@silentswap/sdk';
import {
  createWalletClient,
  custom,
  parseUnits,
  type Address,
} from 'viem';
import { mainnet } from 'viem/chains';
 
declare const provider: Parameters<typeof custom>[0];
declare const account: Address;
 
const walletClient = createWalletClient({
  account,
  chain: mainnet,
  transport: custom(provider),
});
 
const client = createSilentSwapClient({
  walletClient,
});
 
export async function startSwap(): Promise<() => void> {
  try {
    const quote = await client.quote({
      privacy: true,
      inputAddress: account,
      sourceAsset: 'USDC',
      sourceChainId: 1,
      outputs: [{
        address: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
        chainId: 8453,
        amount: parseUnits('25', 6),
      }],
    });
 
    // Await a real UI review here, then optionally narrate approval.
    if (!(await client.hasAllowance(quote))) {
      await client.ensureAllowance(quote);
    }
 
    const order = await client.placeOrder(quote);
 
    return client.trackOrderViaWebSocket(
      order.reference,
      (state) => console.log(state.status),
      console.error,
    );
  } catch (error) {
    if (error instanceof AmountOutOfRangeError) {
      throw new Error(error.message, { cause: error });
    }
    if (error instanceof DepositSimulationError) {
      throw new Error('Nothing was broadcast.', { cause: error });
    }
    if (error instanceof HttpError) {
      throw new Error(`SilentSwap API: HTTP ${error.status}`, { cause: error });
    }
    throw error;
  }
}