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
| Route | Description |
|---|---|
| SOL → SOL | Privacy-preserving transfer (routed via USDC) |
| SOL → EVM Token | Swap native SOL to any EVM token (ETH, USDC, etc.) |
| EVM Token → SOL | Swap EVM tokens (USDC, ETH) to native SOL |
| EVM Token → SPL Token | Swap EVM tokens to Solana SPL tokens |
Quick Start
Installation
npm install @silentswap/sdk viem @solana/web3.js @scure/bip39 @scure/bip32 ed25519-hd-keyBasic 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=9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWMKey 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
| Asset | CAIP-19 Format |
|---|---|
| Native SOL | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501 |
| USDC (SPL) | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| wSOL | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:So11111111111111111111111111111111111111112 |
EVM Assets
| Asset | CAIP-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
| From | To | Notes |
|---|---|---|
| SOL → USDC (EVM) | Solana to Ethereum/Avalanche | SOL bridged via relay.link to USDC |
| USDC (EVM) → SOL | Avalanche to Solana | USDC swapped to SOL via facilitators |
| SOL → SOL | Privacy transfer | SOL routed through Avalanche USDC |
| USDC (EVM) → USDC (SPL) | Cross-chain stablecoin | Direct CCTP bridge route |
API Reference
executeSolanaSwap
Execute a Solana-to-Solana privacy swap.
function executeSolanaSwap(config: SolanaSwapConfig): Promise<SwapResult>SolanaSwapConfig
| Property | Type | Required | Description |
|---|---|---|---|
accounts | SwapAccounts | Yes | EVM and Solana accounts for signing |
sourceAsset | string | Yes | Source asset in CAIP-19 format |
sourceAmount | string | Yes | Amount in human-readable units (e.g., "0.1") |
destinationAsset | string | Yes | Destination asset in CAIP-19 format |
recipientAddress | string | Yes | Recipient address (Solana base58) |
solanaRpcUrl | string | No | Solana RPC URL (default: mainnet) |
environment | 'mainnet' | 'testnet' | No | Environment (default: 'mainnet') |
maxImpactPercent | number | No | Max price impact (default: 1.5) |
siweDomain | string | No | SIWE domain (default: 'app.silentswap.com') |
onStatus | (update: SwapStatusUpdate) => void | No | Status callback |
trackOrder | boolean | No | If true, poll bridge status until complete |
wsUrl | string | No | WebSocket URL for order tracking |
SwapResult
| Property | Type | Description |
|---|---|---|
orderId | string | Unique order identifier |
quoteId | string | Quote ID used for the order |
depositTxHash | string | Deposit transaction hash (Solana signature) |
usdcAmount | string | USDC amount bridged (micro units) |
actualSourceAmount | string | Actual source amount used |
viewingAuth | string | Base58 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
| Property | Type | Description |
|---|---|---|
type | 'info' | 'deposit' | 'stage' | 'error' | 'complete' | Update type |
message | string | Human-readable message |
data | any | Optional 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:
| Asset | CAIP-19 Format |
|---|---|
| Native SOL | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501 |
| USDC on Solana | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| Native ETH | eip155:1/slip44:60 |
| USDC on Ethereum | eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 |
| USDC on Avalanche | eip155: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:
| Chain | Path | Curve | Compatible Wallets |
|---|---|---|---|
| EVM (Ethereum/Avalanche) | m/44'/60'/0'/0/0 | secp256k1 | MetaMask, Ledger |
| Solana | m/44'/501'/0'/0' | ed25519 | Phantom, 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 swapNext Steps
- React Solana Examples - Frontend implementation with React hooks
- Bridge Operations - Direct bridge without privacy
- Complete Example - Full swap implementation details