Skip to content

Solana Swap Examples

This guide demonstrates how to execute privacy-preserving swaps between Solana and EVM chains using the SilentSwap SDK. The SDK provides both a high-level executeSolanaSwap API for simple integrations and lower-level functions for advanced use cases.

Supported Swap Routes

RouteDescription
SOL → SOLPrivacy-preserving transfer (routed via USDC)
SOL → EVM TokenSwap native SOL to any EVM token (ETH, USDC, etc.)
EVM Token → SOLSwap EVM tokens (USDC, ETH) to native SOL
EVM Token → SPL TokenSwap EVM tokens to Solana SPL tokens

Quick Start

Installation

npm install @silentswap/sdk viem @solana/web3.js @scure/bip39 @scure/bip32 ed25519-hd-key

Basic Usage

import {
  executeSolanaSwap,
  SB58_CHAIN_ID_SOLANA_MAINNET,
  type SwapAccounts,
  type SwapStatusUpdate,
} from '@silentswap/sdk';
 
// Native SOL CAIP-19 identifier
const SOL_NATIVE = `solana:${SB58_CHAIN_ID_SOLANA_MAINNET}/slip44:501`;
 
// Execute a SOL to SOL privacy swap
const result = await executeSolanaSwap({
  accounts: {
    evm: {
      address: '0x...',
      signMessage: async (msg) => wallet.signMessage(msg),
      signTypedData: async (data) => wallet.signTypedData(data),
    },
    solana: {
      publicKey: 'ABC123...',
      signTransaction: async (tx) => solanaWallet.signTransaction(tx),
    },
  },
  sourceAsset: SOL_NATIVE,
  sourceAmount: '0.1', // 0.1 SOL
  destinationAsset: SOL_NATIVE,
  recipientAddress: '9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM',
  onStatus: (update) => console.log(update.message),
});
 
console.log('Order ID:', result.orderId);
console.log('Viewing auth (save for tracking/refund):', result.viewingAuth);
console.log('Used wallet:', result.usedWallet.evmAddress, result.usedWallet.solanaPublicKey);
// Store result.recoveryData (mnemonic + recoveryPaths) securely for refund/recovery; do not log.

Complete Node.js Example

This example shows a complete SOL to SOL privacy swap using a seed phrase for key derivation.

Setup

Create a project with the following dependencies:

{
  "dependencies": {
    "@silentswap/sdk": "latest",
    "@solana/web3.js": "^1.98.0",
    "@scure/bip39": "^1.5.0",
    "@scure/bip32": "^1.6.0",
    "ed25519-hd-key": "^1.3.0",
    "viem": "^2.21.0",
    "dotenv": "^16.4.0"
  }
}

Environment Configuration

Create a .env file:

PRIVATE_SEED="your twelve word seed phrase here"
SWAP_AMOUNT=0.1
RECIPIENT_ADDRESS=9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM

Key Derivation

Derive both EVM and Solana keys from a single BIP39 seed phrase:

import { mnemonicToSeedSync } from '@scure/bip39';
import { HDKey } from '@scure/bip32';
import { derivePath } from 'ed25519-hd-key';
import { Keypair } from '@solana/web3.js';
import { privateKeyToAccount } from 'viem/accounts';
 
interface DerivedKeys {
  evmPrivateKey: `0x${string}`;
  evmAddress: `0x${string}`;
  solanaKeypair: Keypair;
  solanaAddress: string;
}
 
/**
 * Derive EVM and Solana keys from a BIP39 seed phrase
 * - EVM: m/44'/60'/0'/0/0 (BIP32/secp256k1)
 * - Solana: m/44'/501'/0'/0' (SLIP-0010/ed25519)
 */
function deriveKeysFromSeed(seedPhrase: string): DerivedKeys {
  const seed = mnemonicToSeedSync(seedPhrase, '');
  const seedHex = Buffer.from(seed).toString('hex');
 
  // Derive EVM key using BIP32 (secp256k1)
  const hdKey = HDKey.fromMasterSeed(seed);
  const evmKey = hdKey.derive("m/44'/60'/0'/0/0");
  const evmPrivateKey = `0x${Buffer.from(evmKey.privateKey!).toString('hex')}` as `0x${string}`;
  const evmAccount = privateKeyToAccount(evmPrivateKey);
 
  // Derive Solana key using SLIP-0010 (ed25519)
  // This matches MetaMask/Phantom/Solflare derivation
  const solanaDerived = derivePath("m/44'/501'/0'/0'", seedHex);
  const solanaKeypair = Keypair.fromSeed(solanaDerived.key);
 
  return {
    evmPrivateKey,
    evmAddress: evmAccount.address,
    solanaKeypair,
    solanaAddress: solanaKeypair.publicKey.toString(),
  };
}

Complete Swap Script

import {
  executeSolanaSwap,
  SB58_CHAIN_ID_SOLANA_MAINNET,
  type SwapAccounts,
  type SwapStatusUpdate,
} from '@silentswap/sdk';
import { createWalletClient, http, publicActions } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { avalanche } from 'viem/chains';
import { Connection } from '@solana/web3.js';
import 'dotenv/config';
 
const SOL_NATIVE = `solana:${SB58_CHAIN_ID_SOLANA_MAINNET}/slip44:501`;
 
async function main() {
  // Load configuration
  const seedPhrase = process.env.PRIVATE_SEED!;
  const swapAmount = process.env.SWAP_AMOUNT!;
  const recipientAddress = process.env.RECIPIENT_ADDRESS!;
 
  // Derive keys from seed phrase
  const keys = deriveKeysFromSeed(seedPhrase);
  console.log('EVM Address:', keys.evmAddress);
  console.log('Solana Address:', keys.solanaAddress);
 
  // Check balances
  const connection = new Connection('https://api.mainnet-beta.solana.com');
  const balance = await connection.getBalance(keys.solanaKeypair.publicKey);
  console.log(`SOL Balance: ${(balance / 1e9).toFixed(6)} SOL`);
 
  // Create EVM client for signing
  const evmAccount = privateKeyToAccount(keys.evmPrivateKey);
  const evmClient = createWalletClient({
    account: evmAccount,
    chain: avalanche,
    transport: http(),
  }).extend(publicActions);
 
  // Create swap accounts
  const accounts: SwapAccounts = {
    evm: {
      address: evmAccount.address,
      signMessage: async (message) => evmClient.signMessage({ message }),
      signTypedData: async (typedData) => evmClient.signTypedData(typedData),
    },
    solana: {
      publicKey: keys.solanaAddress,
      signTransaction: async (tx) => keys.solanaKeypair.secretKey,
    },
  };
 
  // Execute swap
  console.log(`\nSwapping ${swapAmount} SOL to ${recipientAddress}...\n`);
 
  const result = await executeSolanaSwap({
    accounts,
    sourceAsset: SOL_NATIVE,
    sourceAmount: swapAmount,
    destinationAsset: SOL_NATIVE,
    recipientAddress,
    onStatus: (update: SwapStatusUpdate) => {
      const icon = update.type === 'error' ? '❌' : 
                   update.type === 'complete' ? '✅' : '📋';
      console.log(`${icon} ${update.message}`);
    },
  });
 
  console.log('\n=== Swap Result ===');
  console.log('Order ID:', result.orderId);
  console.log('Quote ID:', result.quoteId);
  console.log('Deposit TX:', result.depositTxHash);
  console.log('USDC Amount:', result.usdcAmount, 'micro');
  console.log('Viewing auth:', result.viewingAuth);
  console.log('Used wallet:', result.usedWallet.evmAddress, result.usedWallet.solanaPublicKey);
  // Store result.recoveryData (mnemonic + recoveryPaths) securely for refund/recovery
}
 
main().catch(console.error);

Example: SOL to EVM Token Swap

This example swaps native SOL on Solana to USDC on Ethereum.

import {
  executeSolanaSwap,
  SB58_CHAIN_ID_SOLANA_MAINNET,
  type SwapAccounts,
  type SwapStatusUpdate,
} from '@silentswap/sdk';
 
// Asset identifiers
const SOL_NATIVE = `solana:${SB58_CHAIN_ID_SOLANA_MAINNET}/slip44:501`;
const USDC_ETHEREUM = 'eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
 
async function swapSolToEvm(
  accounts: SwapAccounts,
  solAmount: string,
  recipientEvmAddress: `0x${string}`
) {
  console.log(`Swapping ${solAmount} SOL to USDC on Ethereum...`);
  console.log(`Recipient: ${recipientEvmAddress}`);
 
  const result = await executeSolanaSwap({
    accounts,
    sourceAsset: SOL_NATIVE,
    sourceAmount: solAmount,
    destinationAsset: USDC_ETHEREUM,
    recipientAddress: recipientEvmAddress,
    onStatus: (update: SwapStatusUpdate) => {
      console.log(`[${update.type}] ${update.message}`);
    },
  });
 
  console.log('Swap completed!');
  console.log('Order ID:', result.orderId);
  console.log('USDC received:', result.usdcAmount, 'micro');
  console.log('Viewing auth:', result.viewingAuth);
  console.log('Used wallet:', result.usedWallet.evmAddress, result.usedWallet.solanaPublicKey);
  return result;
}
 
// Usage
const accounts: SwapAccounts = {
  evm: {
    address: evmAccount.address,
    signMessage: async (message) => evmClient.signMessage({ message }),
    signTypedData: async (typedData) => evmClient.signTypedData(typedData),
  },
  solana: {
    publicKey: solanaKeypair.publicKey.toString(),
    signTransaction: async (tx) => solanaKeypair.secretKey,
  },
};
 
await swapSolToEvm(accounts, '0.5', '0x742d35Cc6634C0532925a3b844Bc9e7595f0Ab39');

Example: EVM Token to Solana SOL Swap

This example swaps USDC on Avalanche to native SOL on Solana.

import {
  createSilentSwapClient,
  createSignInMessage,
  createEip712DocForWalletGeneration,
  createHdFacilitatorGroupFromEntropy,
  queryDepositCount,
  hexToBytes,
  quoteResponseToEip712Document,
  DeliveryMethod,
  FacilitatorKeyType,
  PublicKeyArgGroups,
  ENVIRONMENT,
  SB58_CHAIN_ID_SOLANA_MAINNET,
} from '@silentswap/sdk';
import { createWalletClient, http, publicActions } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { avalanche } from 'viem/chains';
import BigNumber from 'bignumber.js';
 
// Asset identifiers
const USDC_AVALANCHE = 'eip155:43114/erc20:0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E';
const SOL_NATIVE = `solana:${SB58_CHAIN_ID_SOLANA_MAINNET}/slip44:501`;
 
async function swapEvmToSolana(
  evmPrivateKey: `0x${string}`,
  usdcAmount: string, // Human-readable (e.g., "10" for 10 USDC)
  recipientSolanaAddress: string
) {
  console.log(`Swapping ${usdcAmount} USDC (Avalanche) to SOL...`);
  console.log(`Recipient: ${recipientSolanaAddress}`);
 
  // Create EVM client
  const evmAccount = privateKeyToAccount(evmPrivateKey);
  const evmClient = createWalletClient({
    account: evmAccount,
    chain: avalanche,
    transport: http(),
  }).extend(publicActions);
 
  // Create SilentSwap client
  const client = createSilentSwapClient({
    environment: ENVIRONMENT.MAINNET,
    baseUrl: 'https://api.silentswap.com',
  });
 
  // Step 1: Authenticate
  console.log('1. Authenticating...');
  const [, nonceResponse] = await client.nonce(evmAccount.address);
  const signInMessage = createSignInMessage(
    evmAccount.address,
    nonceResponse.nonce,
    'app.silentswap.com'
  );
  const signature = await evmClient.signMessage({ message: signInMessage.message });
  const [, authResponse] = await client.authenticate({
    siwe: { message: signInMessage.message, signature },
  });
  console.log('✓ Authenticated');
 
  // Step 2: Derive entropy for facilitator keys
  console.log('2. Deriving entropy...');
  const scope = `eip155:43114:${evmAccount.address}`;
  const eip712Doc = createEip712DocForWalletGeneration(scope, authResponse.secretToken);
  const entropy = await evmClient.signTypedData(eip712Doc as any);
  console.log('✓ Entropy derived');
 
  // Step 3: Create facilitator group
  console.log('3. Creating facilitator group...');
  const depositCount = await queryDepositCount(evmAccount.address, client.s0xGatewayAddress);
  const group = await createHdFacilitatorGroupFromEntropy(hexToBytes(entropy), depositCount);
  console.log('✓ Facilitator group created');
 
  // Step 4: Get quote
  console.log('4. Getting quote...');
  const viewer = await group.viewer();
  const { publicKeyBytes } = viewer.exportPublicKey('*', FacilitatorKeyType.SECP256K1);
  const groupPublicKeys = await group.exportPublicKeys(1, [...PublicKeyArgGroups.GENERIC]);
 
  // Convert USDC amount to micro units (6 decimals)
  const usdcMicro = new BigNumber(usdcAmount).times(1e6).toString();
 
  const [, quoteResponse] = await client.quote({
    signer: evmAccount.address,
    viewer: publicKeyBytes,
    outputs: [{
      method: DeliveryMethod.SNIP,
      recipient: recipientSolanaAddress,
      asset: SOL_NATIVE,
      value: usdcMicro,
      facilitatorPublicKeys: groupPublicKeys[0],
    }],
  });
  console.log('✓ Quote received:', quoteResponse.quoteId);
 
  // Step 5: Place order
  console.log('5. Placing order...');
  const orderDoc = quoteResponseToEip712Document(quoteResponse);
  const signedQuote = await evmClient.signTypedData(orderDoc as any);
  
  const facilitatorReplies = await group.approveProxyAuthorizations(
    quoteResponse.facilitators,
    { proxyPublicKey: client.proxyPublicKey }
  );
 
  const [, orderResponse] = await client.order({
    quoteId: quoteResponse.quoteId,
    quote: quoteResponse.quote,
    authorizations: facilitatorReplies.map(f => f.authorization),
    eip712Domain: orderDoc.domain,
    signature: signedQuote,
    facilitators: facilitatorReplies,
  });
  
  const orderId = orderResponse.response?.approver;
  console.log('✓ Order placed:', orderId);
 
  // Step 6: Execute deposit (EVM USDC transfer)
  console.log('6. Executing deposit...');
  // For EVM source swaps, approve and transfer USDC to the depositor contract
  // This requires ERC-20 approval and deposit transaction
  // See complete-example.mdx for full deposit implementation
 
  return {
    orderId,
    quoteId: quoteResponse.quoteId,
  };
}
 
// Usage
await swapEvmToSolana(
  '0x...your_private_key...',
  '10', // 10 USDC
  '9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM'
);

Example: EVM to Solana SPL Token Swap

Swap an EVM token (e.g., USDC on Avalanche) to an SPL token on Solana (e.g., USDC SPL).

import {
  createSilentSwapClient,
  createSignInMessage,
  createEip712DocForWalletGeneration,
  createHdFacilitatorGroupFromEntropy,
  queryDepositCount,
  hexToBytes,
  quoteResponseToEip712Document,
  DeliveryMethod,
  FacilitatorKeyType,
  PublicKeyArgGroups,
  ENVIRONMENT,
  SB58_CHAIN_ID_SOLANA_MAINNET,
} from '@silentswap/sdk';
import BigNumber from 'bignumber.js';
 
// Asset identifiers
const USDC_AVALANCHE = 'eip155:43114/erc20:0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E';
const USDC_SOLANA = `solana:${SB58_CHAIN_ID_SOLANA_MAINNET}/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`;
 
async function swapEvmToSolanaSpl(
  evmClient: any,
  evmAddress: `0x${string}`,
  usdcAmount: string,
  recipientSolanaAddress: string
) {
  console.log(`Swapping ${usdcAmount} USDC (Avalanche) to USDC (Solana SPL)...`);
 
  const client = createSilentSwapClient({
    environment: ENVIRONMENT.MAINNET,
    baseUrl: 'https://api.silentswap.com',
  });
 
  // Authenticate
  const [, nonceResponse] = await client.nonce(evmAddress);
  const signInMessage = createSignInMessage(evmAddress, nonceResponse.nonce, 'app.silentswap.com');
  const signature = await evmClient.signMessage({ message: signInMessage.message });
  const [, authResponse] = await client.authenticate({
    siwe: { message: signInMessage.message, signature },
  });
 
  // Derive entropy
  const scope = `eip155:43114:${evmAddress}`;
  const eip712Doc = createEip712DocForWalletGeneration(scope, authResponse.secretToken);
  const entropy = await evmClient.signTypedData(eip712Doc as any);
 
  // Create facilitator group
  const depositCount = await queryDepositCount(evmAddress, client.s0xGatewayAddress);
  const group = await createHdFacilitatorGroupFromEntropy(hexToBytes(entropy), depositCount);
 
  // Get quote for SPL token destination
  const viewer = await group.viewer();
  const { publicKeyBytes } = viewer.exportPublicKey('*', FacilitatorKeyType.SECP256K1);
  const groupPublicKeys = await group.exportPublicKeys(1, [...PublicKeyArgGroups.GENERIC]);
  
  const usdcMicro = new BigNumber(usdcAmount).times(1e6).toString();
 
  const [, quoteResponse] = await client.quote({
    signer: evmAddress,
    viewer: publicKeyBytes,
    outputs: [{
      method: DeliveryMethod.SNIP,
      recipient: recipientSolanaAddress, // Base58 Solana address
      asset: USDC_SOLANA, // SPL token mint address in CAIP-19 format
      value: usdcMicro,
      facilitatorPublicKeys: groupPublicKeys[0],
    }],
  });
 
  // Place order
  const orderDoc = quoteResponseToEip712Document(quoteResponse);
  const signedQuote = await evmClient.signTypedData(orderDoc as any);
  
  const facilitatorReplies = await group.approveProxyAuthorizations(
    quoteResponse.facilitators,
    { proxyPublicKey: client.proxyPublicKey }
  );
 
  const [, orderResponse] = await client.order({
    quoteId: quoteResponse.quoteId,
    quote: quoteResponse.quote,
    authorizations: facilitatorReplies.map(f => f.authorization),
    eip712Domain: orderDoc.domain,
    signature: signedQuote,
    facilitators: facilitatorReplies,
  });
 
  console.log('Order ID:', orderResponse.response?.approver);
  console.log('Quote ID:', quoteResponse.quoteId);
 
  // Execute deposit transaction...
  // See complete-example.mdx for full implementation
 
  return {
    orderId: orderResponse.response?.approver,
    quoteId: quoteResponse.quoteId,
  };
}

Cross-Chain Asset Mapping

When swapping between chains, use the correct CAIP-19 identifiers:

Solana Assets

AssetCAIP-19 Format
Native SOLsolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501
USDC (SPL)solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
wSOLsolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:So11111111111111111111111111111111111111112

EVM Assets

AssetCAIP-19 Format
ETH (Ethereum)eip155:1/slip44:60
USDC (Ethereum)eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
AVAX (Avalanche)eip155:43114/slip44:9000
USDC (Avalanche)eip155:43114/erc20:0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E
USDT (Ethereum)eip155:1/erc20:0xdAC17F958D2ee523a2206206994597C13D831ec7

Common Swap Routes

FromToNotes
SOL → USDC (EVM)Solana to Ethereum/AvalancheSOL bridged via relay.link to USDC
USDC (EVM) → SOLAvalanche to SolanaUSDC swapped to SOL via facilitators
SOL → SOLPrivacy transferSOL routed through Avalanche USDC
USDC (EVM) → USDC (SPL)Cross-chain stablecoinDirect CCTP bridge route

API Reference

executeSolanaSwap

Execute a Solana-to-Solana privacy swap.

function executeSolanaSwap(config: SolanaSwapConfig): Promise<SwapResult>

SolanaSwapConfig

PropertyTypeRequiredDescription
accountsSwapAccountsYesEVM and Solana accounts for signing
sourceAssetstringYesSource asset in CAIP-19 format
sourceAmountstringYesAmount in human-readable units (e.g., "0.1")
destinationAssetstringYesDestination asset in CAIP-19 format
recipientAddressstringYesRecipient address (Solana base58)
solanaRpcUrlstringNoSolana RPC URL (default: mainnet)
environment'mainnet' | 'testnet'NoEnvironment (default: 'mainnet')
maxImpactPercentnumberNoMax price impact (default: 1.5)
siweDomainstringNoSIWE domain (default: 'app.silentswap.com')
onStatus(update: SwapStatusUpdate) => voidNoStatus callback
trackOrderbooleanNoIf true, poll bridge status until complete
wsUrlstringNoWebSocket URL for order tracking

SwapResult

PropertyTypeDescription
orderIdstringUnique order identifier
quoteIdstringQuote ID used for the order
depositTxHashstringDeposit transaction hash (Solana signature)
usdcAmountstringUSDC amount bridged (micro units)
actualSourceAmountstringActual source amount used
viewingAuthstringBase58 viewing auth for this order; save for tracking, refund, and recovery
recoveryData{ mnemonic: string; recoveryPaths: string[] }Mnemonic and BIP-44 paths for refund/recovery; store securely, do not log
usedWallet{ evmAddress: string; solanaPublicKey: string }EVM signer (refundee) and Solana depositor addresses used for the swap

SwapStatusUpdate

PropertyTypeDescription
type'info' | 'deposit' | 'stage' | 'error' | 'complete'Update type
messagestringHuman-readable message
dataanyOptional additional data

SwapAccounts

interface SwapAccounts {
  evm: {
    address: `0x${string}`;
    signMessage: (message: string) => Promise<`0x${string}`>;
    signTypedData: (typedData: any) => Promise<`0x${string}`>;
  };
  solana: {
    publicKey: string;
    signTransaction: (transaction: Uint8Array) => Promise<Uint8Array>;
  };
}

CAIP-19 Asset Identifiers

SilentSwap uses CAIP-19 for cross-chain asset identification:

AssetCAIP-19 Format
Native SOLsolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501
USDC on Solanasolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
Native ETHeip155:1/slip44:60
USDC on Ethereumeip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
USDC on Avalancheeip155:43114/erc20:0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E

Helper Constants

import { SB58_CHAIN_ID_SOLANA_MAINNET } from '@silentswap/sdk';
 
// Native SOL
const SOL = `solana:${SB58_CHAIN_ID_SOLANA_MAINNET}/slip44:501`;
 
// SPL Token (e.g., USDC)
const USDC_SOL = `solana:${SB58_CHAIN_ID_SOLANA_MAINNET}/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`;

Key Derivation Paths

The SDK uses standard BIP44 derivation paths compatible with popular wallets:

ChainPathCurveCompatible Wallets
EVM (Ethereum/Avalanche)m/44'/60'/0'/0/0secp256k1MetaMask, Ledger
Solanam/44'/501'/0'/0'ed25519Phantom, Solflare, MetaMask Snaps

Error Handling

try {
  const result = await executeSolanaSwap({
    // ... config
  });
} catch (error) {
  if (error.message.includes('Insufficient balance')) {
    console.error('Not enough SOL for swap');
  } else if (error.message.includes('Quote failed')) {
    console.error('Failed to get quote - try again later');
  } else if (error.message.includes('Order failed')) {
    console.error('Order placement failed');
  } else {
    console.error('Swap failed:', error.message);
  }
}

Advanced: Low-Level API

For more control over the swap process, you can use the lower-level SDK functions directly:

import {
  createSilentSwapClient,
  createSignInMessage,
  createEip712DocForWalletGeneration,
  createHdFacilitatorGroupFromEntropy,
  queryDepositCount,
  hexToBytes,
  quoteResponseToEip712Document,
  solveOptimalUsdcAmount,
  DeliveryMethod,
  FacilitatorKeyType,
  PublicKeyArgGroups,
  ENVIRONMENT,
  N_RELAY_CHAIN_ID_SOLANA,
  SB58_ADDR_SOL_PROGRAM_SYSTEM,
} from '@silentswap/sdk';
 
// 1. Create client
const client = createSilentSwapClient({ environment: ENVIRONMENT.MAINNET });
 
// 2. Authenticate
const [, nonceResponse] = await client.nonce(evmAddress);
const signInMessage = createSignInMessage(evmAddress, nonceResponse.nonce, 'app.silentswap.com');
const signature = await signer.signMessage(signInMessage.message);
const [, authResponse] = await client.authenticate({
  siwe: { message: signInMessage.message, signature },
});
 
// 3. Derive entropy
const scope = `eip155:43114:${evmAddress}`;
const eip712Doc = createEip712DocForWalletGeneration(scope, authResponse.secretToken);
const entropy = await signer.signTypedData(eip712Doc);
 
// 4. Create facilitator group
const depositCount = await queryDepositCount(evmAddress, client.s0xGatewayAddress);
const group = await createHdFacilitatorGroupFromEntropy(hexToBytes(entropy), depositCount);
 
// 5. Calculate bridge amount
const bridgeResult = await solveOptimalUsdcAmount(
  N_RELAY_CHAIN_ID_SOLANA,
  SB58_ADDR_SOL_PROGRAM_SYSTEM,
  sourceAmountLamports,
  solanaAddress,
  depositCalldata,
  1.5, // max impact percent
  client.s0xDepositorAddress,
  evmAddress,
);
 
// 6. Get quote
const viewer = await group.viewer();
const { publicKeyBytes } = viewer.exportPublicKey('*', FacilitatorKeyType.SECP256K1);
const groupPublicKeys = await group.exportPublicKeys(1, [...PublicKeyArgGroups.GENERIC]);
 
const [, quoteResponse] = await client.quote({
  signer: evmAddress,
  viewer: publicKeyBytes,
  outputs: [{
    method: DeliveryMethod.SNIP,
    recipient: recipientAddress,
    asset: destinationAsset,
    value: bridgeResult.usdcAmountOut.toString(),
    facilitatorPublicKeys: groupPublicKeys[0],
  }],
});
 
// 7. Place order
const orderDoc = quoteResponseToEip712Document(quoteResponse);
const signedQuote = await signer.signTypedData(orderDoc);
const facilitatorReplies = await group.approveProxyAuthorizations(
  quoteResponse.facilitators,
  { proxyPublicKey: client.proxyPublicKey }
);
 
const [, orderResponse] = await client.order({
  quoteId: quoteResponse.quoteId,
  quote: quoteResponse.quote,
  authorizations: signedAuths,
  eip712Domain: orderDoc.domain,
  signature: signedQuote,
  facilitators: facilitatorReplies,
});
 
// 8. Execute deposit transaction via relay.link
// ... (see full example in SDK repository)

Example Repository

A complete working example is available in the SDK repository:

git clone https://github.com/silentswap/sdk
cd sdk/packages/core/examples/swap
bun install
bun run swap

Next Steps