Skip to content

Complete Example

This example demonstrates a complete Silent Swap flow using the Core SDK in a Node.js backend environment. Silent Swap enables private, non-custodial cross-chain swaps.

Quick Reference

Essential Imports

import {
  // Client & Signer
  createSilentSwapClient,
  createViemSigner,
  parseTransactionRequestForViem,
  
  // Authentication
  createSignInMessage,
  createEip712DocForWalletGeneration,
  createEip712DocForOrder,
  
  // Facilitator Group
  createHdFacilitatorGroupFromEntropy,
  queryDepositCount,
  hexToBytes,
  
  // Order & Quote
  quoteResponseToEip712Document,
  
  // Bridge Utilities
  solveOptimalUsdcAmount,
  
  // Token Utilities
  caip19FungibleEvmToken,
  
  // Constants
  DeliveryMethod,
  FacilitatorKeyType,
  PublicKeyArgGroups,
  ENVIRONMENT,
  GATEWAY_ABI,
} from '@silentswap/sdk';
import BigNumber from 'bignumber.js';

Setup

import { 
  createSilentSwapClient,
  createViemSigner,
  parseTransactionRequestForViem,
  createSignInMessage,
  createEip712DocForOrder,
  createEip712DocForWalletGeneration,
  createHdFacilitatorGroupFromEntropy,
  quoteResponseToEip712Document,
  caip19FungibleEvmToken,
  queryDepositCount,
  solveOptimalUsdcAmount,
  GATEWAY_ABI,
  PublicKeyArgGroups,
  DeliveryMethod,
  FacilitatorKeyType,
  ENVIRONMENT,
  hexToBytes,
  type SilentSwapClient,
  type EvmSigner,
  type AuthResponse,
  type SolveUsdcResult,
} from '@silentswap/sdk';
import { createWalletClient, http, publicActions, erc20Abi } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { avalanche, mainnet } from 'viem/chains';
import BigNumber from 'bignumber.js';
 
// Create wallet client
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const client = createWalletClient({
  account,
  chain: avalanche,
  transport: http(),
}).extend(publicActions);
 
// Create EVM signer
const signer = createViemSigner(account, client);
 
// Create SilentSwap client
const silentswap = createSilentSwapClient({
  environment: ENVIRONMENT.MAINNET,
  baseUrl: 'https://api.silentswap.com',
});

Required Core Methods

The following methods from @silentswap/sdk are essential for executing Silent Swaps:

Authentication & Entropy

  • createSignInMessage(address, nonce, domain): Creates a SIWE (Sign-In with Ethereum) message for authentication
  • createEip712DocForWalletGeneration(secretToken): Creates EIP-712 document for deriving entropy from auth token
  • hexToBytes(hex): Converts hex string to bytes array (required for entropy conversion)

Facilitator Group Management

  • queryDepositCount(userAddress): Queries the Gateway contract to get the number of deposits made by a user. This count is used as a nonce for creating facilitator groups.
  • createHdFacilitatorGroupFromEntropy(entropy, depositCount): Creates a hierarchical deterministic facilitator group from entropy and deposit count. This generates:
    • Viewer account (for observing order execution)
    • Facilitator accounts (for executing swaps on different chains)

Bridge Utilities

  • solveOptimalUsdcAmount(srcChainId, srcToken, srcAmount, userAddress, depositCalldata?, maxImpactPercent?): Calculates the optimal USDC amount that will be received after bridging a source token to Avalanche. This is essential for cross-chain swaps where you need to bridge first, then use the resulting USDC for SilentSwap.
    • Parameters:
      • srcChainId: Source chain ID (e.g., 1 for Ethereum mainnet)
      • srcToken: Source token address (0x0 or 0x0000... for native tokens)
      • srcAmount: Source amount in raw token units
      • userAddress: User's EVM address
      • depositCalldata (optional): Deposit calldata for post-bridge execution
      • maxImpactPercent (optional): Maximum price impact allowed (default from constants)
    • Returns: SolveUsdcResult with:
      • usdcAmountOut: USDC amount in microUSDC (6 decimals) - ready to use in quotes
      • actualAmountIn: Actual input amount required
      • provider: Bridge provider used ('relay' or 'debridge')
      • allowanceTarget: Allowance target address (for deBridge)

Token & Asset Utilities

  • caip19FungibleEvmToken(chainId, tokenAddress): Creates a CAIP-19 identifier for an EVM ERC20 token
    • Example: caip19FungibleEvmToken(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48')"eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"

Order Creation

  • quoteResponseToEip712Document(quoteResponse): Converts a quote response to an EIP-712 document for signing the order
  • createEip712DocForOrder(quoteResponse): Alternative method to create EIP-712 document for order signing

Signer Adapters

  • createViemSigner(account, walletClient): Creates an EVM signer adapter for viem wallet clients
  • parseTransactionRequestForViem(transactionRequest): Parses a transaction request from the API into viem-compatible format

Constants & Types

  • DeliveryMethod.SNIP: Delivery method constant for SilentSwap orders
  • FacilitatorKeyType.SECP256K1: Key type for EVM facilitator accounts
  • PublicKeyArgGroups.GENERIC: Predefined public key argument groups for facilitator accounts
  • ENVIRONMENT.MAINNET: Environment constant for mainnet configuration
  • GATEWAY_ABI: ABI for the Gateway contract (for querying deposit counts)

Method Usage Flow

// 1. Authentication
const signInMessage = createSignInMessage(address, nonce, domain);
const entropy = await signer.signEip712TypedData(
  createEip712DocForWalletGeneration(authResponse.secretToken)
);
 
// 2. Facilitator Group
const depositCount = await queryDepositCount(address);
const group = await createHdFacilitatorGroupFromEntropy(
  hexToBytes(entropy),
  depositCount
);
 
// 3. Token Asset
const asset = caip19FungibleEvmToken(chainId, tokenAddress);
 
// 4. Order Signing
const orderDoc = quoteResponseToEip712Document(quoteResponse);
const signature = await signer.signEip712TypedData(orderDoc);

Complete Silent Swap Flow

async function executeSilentSwap(
  recipientAddress: `0x${string}`,
  tokenAddress: `0x${string}`,
  tokenAmount: string,
  tokenDecimals: number = 6
) {
  try {
    // Step 1: Authenticate and derive entropy
    console.log('Step 1: Authenticating with SilentSwap...');
    const entropy = await authenticateAndDeriveEntropy(silentswap, signer);
    console.log('✓ Authentication successful');
 
    // Step 2: Create facilitator group
    console.log('\nStep 2: Creating facilitator group...');
    const depositCount = await queryDepositCount(account.address);
    const group = await createHdFacilitatorGroupFromEntropy(
      hexToBytes(entropy),
      depositCount
    );
    console.log(`✓ Facilitator group created (deposit count: ${depositCount})`);
 
    // Step 3: Get quote
    console.log('\nStep 3: Requesting quote...');
    const quoteResponse = await getQuote(
      silentswap,
      signer,
      group,
      recipientAddress,
      tokenAddress,
      tokenAmount,
      tokenDecimals
    );
    console.log(`✓ Quote received (Order ID: ${quoteResponse.quoteId})`);
 
    // Step 4: Sign authorizations and create order
    console.log('\nStep 4: Signing authorizations and creating order...');
    const orderResponse = await createOrder(
      silentswap,
      signer,
      group,
      quoteResponse
    );
    console.log(`✓ Order created (Order ID: ${orderResponse.response.orderId})`);
 
    // Step 5: Execute deposit
    console.log('\nStep 5: Executing deposit transaction...');
    const depositHash = await executeDeposit(client, orderResponse);
    console.log(`✓ Deposit transaction sent: ${depositHash}`);
 
    // Step 6: Watch for completion
    console.log('\nStep 6: Watching for order completion...');
    await watchForCompletion(
      client,
      tokenAddress,
      recipientAddress,
      group,
      tokenDecimals
    );
 
    return {
      orderId: orderResponse.response.orderId,
      depositHash,
      quote: quoteResponse,
    };
  } catch (err) {
    console.error('Silent Swap error:', err);
    throw err;
  }
}
 
// Helper: Authenticate and derive entropy
async function authenticateAndDeriveEntropy(
  silentswap: SilentSwapClient,
  signer: EvmSigner
): Promise<`0x${string}`> {
  // Get nonce
  const [nonceError, nonceResponse] = await silentswap.nonce(signer.address);
  if (!nonceResponse || nonceError) {
    throw new Error(`Failed to get nonce: ${nonceError?.type}: ${nonceError?.error}`);
  }
 
  // Create sign-in message
  const signInMessage = createSignInMessage(
    signer.address,
    nonceResponse.nonce,
    'silentswap.com'
  );
 
  // Sign message
  const siweSignature = await signer.signEip191Message(signInMessage.message);
 
  // Authenticate
  const [authError, authResponse] = await silentswap.authenticate({
    siwe: {
      message: signInMessage.message,
      signature: siweSignature,
    },
  });
 
  if (!authResponse || authError) {
    throw new Error(`Failed to authenticate: ${authError?.type}: ${authError?.error}`);
  }
 
  // Derive entropy from auth token
  const eip712Doc = createEip712DocForWalletGeneration(authResponse.secretToken);
  const entropy = await signer.signEip712TypedData(eip712Doc);
 
  return entropy;
}
 
// Helper: Get quote (for direct USDC swaps on Avalanche)
async function getQuote(
  silentswap: SilentSwapClient,
  signer: EvmSigner,
  group: Awaited<ReturnType<typeof createHdFacilitatorGroupFromEntropy>>,
  recipientAddress: `0x${string}`,
  tokenAddress: `0x${string}`,
  tokenAmount: string,
  tokenDecimals: number
) {
  // Derive viewer account
  const viewer = await group.viewer();
  const { publicKeyBytes: pk65_viewer } = viewer.exportPublicKey(
    '*',
    FacilitatorKeyType.SECP256K1
  );
 
  // Export public keys for facilitator group
  const groupPublicKeys = await group.exportPublicKeys(1, [
    ...PublicKeyArgGroups.GENERIC,
  ]);
 
  // Request quote
  const [quoteError, quoteResponse] = await silentswap.quote({
    signer: signer.address,
    viewer: pk65_viewer,
    outputs: [
      {
        method: DeliveryMethod.SNIP,
        recipient: recipientAddress,
        asset: caip19FungibleEvmToken(1, tokenAddress),
        value: BigNumber(tokenAmount).shiftedBy(tokenDecimals).toFixed(0) as `${bigint}`,
        facilitatorPublicKeys: groupPublicKeys[0],
      },
    ],
  });
 
  if (quoteError || !quoteResponse) {
    throw new Error(`Failed to get quote: ${quoteError?.type}: ${quoteError?.error}`);
  }
 
  return quoteResponse;
}
 
// Helper: Get quote with bridge (for cross-chain swaps)
async function getQuoteWithBridge(
  silentswap: SilentSwapClient,
  signer: EvmSigner,
  group: Awaited<ReturnType<typeof createHdFacilitatorGroupFromEntropy>>,
  recipientAddress: `0x${string}`,
  destinationTokenAddress: `0x${string}`,
  sourceChainId: number,
  sourceTokenAddress: `0x${string}`,
  sourceAmount: string,
  sourceTokenDecimals: number
) {
  // Step 1: Calculate USDC amount from bridge
  const bridgeResult: SolveUsdcResult = await solveOptimalUsdcAmount(
    sourceChainId,
    sourceTokenAddress,
    BigNumber(sourceAmount).shiftedBy(sourceTokenDecimals).toFixed(0),
    signer.address
  );
  
  // bridgeResult.usdcAmountOut is already in microUSDC (6 decimals)
  const usdcAmount = bridgeResult.usdcAmountOut.toString();
 
  // Step 2: Derive viewer account
  const viewer = await group.viewer();
  const { publicKeyBytes: pk65_viewer } = viewer.exportPublicKey(
    '*',
    FacilitatorKeyType.SECP256K1
  );
 
  // Step 3: Export public keys for facilitator group
  const groupPublicKeys = await group.exportPublicKeys(1, [
    ...PublicKeyArgGroups.GENERIC,
  ]);
 
  // Step 4: Request quote using the bridged USDC amount
  const [quoteError, quoteResponse] = await silentswap.quote({
    signer: signer.address,
    viewer: pk65_viewer,
    outputs: [
      {
        method: DeliveryMethod.SNIP,
        recipient: recipientAddress,
        asset: caip19FungibleEvmToken(1, destinationTokenAddress),
        value: usdcAmount as `${bigint}`,
        facilitatorPublicKeys: groupPublicKeys[0],
      },
    ],
  });
 
  if (quoteError || !quoteResponse) {
    throw new Error(`Failed to get quote: ${quoteError?.type}: ${quoteError?.error}`);
  }
 
  return {
    quoteResponse,
    bridgeResult, // Include bridge info for reference
  };
}
 
// Helper: Create order
async function createOrder(
  silentswap: SilentSwapClient,
  signer: EvmSigner,
  group: Awaited<ReturnType<typeof createHdFacilitatorGroupFromEntropy>>,
  quoteResponse: Awaited<ReturnType<typeof getQuote>>
) {
  // Sign authorizations
  const signedAuths = await Promise.all(
    quoteResponse.authorizations.map(async (g_auth) => ({
      ...g_auth,
      signature: await (async () => {
        if ('eip3009_deposit' === g_auth.type) {
          return await signer.signEip712TypedData(g_auth.eip712);
        }
        throw Error(`Authorization instruction type not implemented: ${g_auth.type}`);
      })(),
    }))
  );
 
  // Sign the order's EIP-712
  const orderDoc = quoteResponseToEip712Document(quoteResponse);
  const signedQuote = await signer.signEip712TypedData(orderDoc);
 
  // Approve proxy authorizations
  const facilitatorReplies = await group.approveProxyAuthorizations(
    quoteResponse.facilitators,
    {
      proxyPublicKey: silentswap.proxyPublicKey,
    }
  );
 
  // Place the order
  const [orderError, orderResponse] = await silentswap.order({
    quote: quoteResponse.quote,
    quoteId: quoteResponse.quoteId,
    authorizations: signedAuths,
    eip712Domain: orderDoc.domain,
    signature: signedQuote,
    facilitators: facilitatorReplies,
  });
 
  if (orderError || !orderResponse) {
    throw new Error(`Failed to place order: ${orderError?.type}: ${orderError?.error}`);
  }
 
  return orderResponse;
}
 
// Helper: Execute deposit
async function executeDeposit(
  client: ReturnType<typeof createWalletClient>,
  orderResponse: Awaited<ReturnType<typeof createOrder>>
) {
  // Parse transaction request
  const txRequestParams = parseTransactionRequestForViem(orderResponse.transaction);
 
  // Send transaction
  const hash = await client.sendTransaction(txRequestParams);
 
  // Wait for confirmation
  const txReceipt = await client.waitForTransactionReceipt({ hash });
  console.log(
    `Deposit confirmed: ${BigNumber(orderResponse.response.order.deposit)
      .shiftedBy(-6)
      .toFixed()} USDC at ${txReceipt.transactionHash}`
  );
 
  return hash;
}
 
// Helper: Watch for completion
async function watchForCompletion(
  client: ReturnType<typeof createWalletClient>,
  tokenAddress: `0x${string}`,
  recipientAddress: `0x${string}`,
  group: Awaited<ReturnType<typeof createHdFacilitatorGroupFromEntropy>>,
  tokenDecimals: number
) {
  // Get facilitator account for coin type 60 (ETH) at output index 0
  const facilitator0Eth = await group.account('60', 0);
  const facilitator0EthEvm = await facilitator0Eth.evmSigner();
 
  // Create client for destination chain (Mainnet)
  const destinationClient = createWalletClient({
    chain: mainnet,
    transport: http(),
  }).extend(publicActions);
 
  // Watch for ERC-20 transfer event
  return new Promise<void>((resolve) => {
    destinationClient.watchContractEvent({
      address: tokenAddress,
      abi: erc20Abi,
      eventName: 'Transfer',
      args: {
        to: recipientAddress,
        from: facilitator0EthEvm.address,
      },
      onLogs: (logs) => {
        for (const log of logs) {
          const { to, value } = log.args;
          console.log(
            `✓ Recipient ${to} received ${BigNumber(value!)
              .shiftedBy(-tokenDecimals)
              .toFixed()} tokens`
          );
        }
        resolve();
      },
    });
  });
}

Usage Example

Example 1: Direct USDC Swap (Avalanche → Ethereum)

For swaps where you already have USDC on Avalanche:

// Execute a Silent Swap: Send 10 USDC from Avalanche to Ethereum
const result = await executeSilentSwap(
  account.address, // Recipient address
  '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC token address (Ethereum mainnet)
  '10', // Amount in human-readable format (10 USDC)
  6 // USDC has 6 decimals
);
 
console.log('Silent Swap completed:', result);
// The function internally converts '10' to '10000000' (10 * 10^6)

Example 2: Cross-Chain Swap with Bridge (Ethereum → Ethereum via Avalanche)

For swaps from a different chain (e.g., ETH on Ethereum → USDC on Ethereum):

async function executeCrossChainSilentSwap(
  sourceChainId: number,
  sourceTokenAddress: `0x${string}`, // 0x0 for native tokens
  sourceAmount: string,
  sourceTokenDecimals: number,
  recipientAddress: `0x${string}`,
  destinationTokenAddress: `0x${string}`,
  destinationTokenDecimals: number = 6
) {
  try {
    // Step 1: Authenticate and derive entropy
    console.log('Step 1: Authenticating with SilentSwap...');
    const entropy = await authenticateAndDeriveEntropy(silentswap, signer);
    console.log('✓ Authentication successful');
 
    // Step 2: Create facilitator group
    console.log('\nStep 2: Creating facilitator group...');
    const depositCount = await queryDepositCount(account.address);
    const group = await createHdFacilitatorGroupFromEntropy(
      hexToBytes(entropy),
      depositCount
    );
    console.log(`✓ Facilitator group created (deposit count: ${depositCount})`);
 
    // Step 3: Calculate USDC amount from bridge
    console.log('\nStep 3: Calculating bridge USDC amount...');
    const bridgeResult = await solveOptimalUsdcAmount(
      sourceChainId,
      sourceTokenAddress,
      BigNumber(sourceAmount).shiftedBy(sourceTokenDecimals).toFixed(0),
      account.address
    );
    
    console.log(`✓ Bridge will provide ${BigNumber(bridgeResult.usdcAmountOut.toString()).shiftedBy(-6).toFixed()} USDC (provider: ${bridgeResult.provider})`);
 
    // Step 4: Get quote using bridged USDC amount
    console.log('\nStep 4: Requesting quote with bridged USDC...');
    const quoteResult = await getQuoteWithBridge(
      silentswap,
      signer,
      group,
      recipientAddress,
      destinationTokenAddress,
      sourceChainId,
      sourceTokenAddress,
      sourceAmount,
      sourceTokenDecimals
    );
    console.log(`✓ Quote received (Order ID: ${quoteResult.quoteResponse.quoteId})`);
 
    // Step 5: Sign authorizations and create order
    console.log('\nStep 5: Signing authorizations and creating order...');
    const orderResponse = await createOrder(
      silentswap,
      signer,
      group,
      quoteResult.quoteResponse
    );
    console.log(`✓ Order created (Order ID: ${orderResponse.response.orderId})`);
 
    // Step 6: Execute deposit (bridge + deposit in one transaction)
    console.log('\nStep 6: Executing bridge and deposit transaction...');
    const depositHash = await executeDeposit(client, orderResponse);
    console.log(`✓ Deposit transaction sent: ${depositHash}`);
 
    // Step 7: Watch for completion
    console.log('\nStep 7: Watching for order completion...');
    await watchForCompletion(
      client,
      destinationTokenAddress,
      recipientAddress,
      group,
      destinationTokenDecimals
    );
 
    return {
      orderId: orderResponse.response.orderId,
      depositHash,
      quote: quoteResult.quoteResponse,
      bridgeProvider: bridgeResult.provider,
      usdcAmountReceived: usdcAmount,
    };
  } catch (err) {
    console.error('Cross-chain Silent Swap error:', err);
    throw err;
  }
}
 
// Usage: Swap 1 ETH from Ethereum to USDC on Ethereum
const result = await executeCrossChainSilentSwap(
  1, // Ethereum mainnet
  '0x0000000000000000000000000000000000000000', // Native ETH
  '1', // 1 ETH
  18, // ETH has 18 decimals
  account.address, // Recipient
  '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
  6 // USDC has 6 decimals
);

Example 3: Direct USDC Swap (Avalanche → Ethereum)

// Example 1: Swap 1.5 ETH (18 decimals)
const ethResult = await executeSilentSwap(
  account.address,
  '0x0000000000000000000000000000000000000000', // Native ETH (use slip44:60 for native)
  '1.5', // 1.5 ETH
  18 // ETH has 18 decimals
);
// Internally converts to: 1500000000000000000
 
// Example 2: Swap 0.1 WBTC (8 decimals)
const wbtcResult = await executeSilentSwap(
  account.address,
  '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', // WBTC token address
  '0.1', // 0.1 WBTC
  8 // WBTC has 8 decimals
);
// Internally converts to: 10000000
 
// Example 3: Swap 100 USDT (6 decimals)
const usdtResult = await executeSilentSwap(
  account.address,
  '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT token address
  '100', // 100 USDT
  6 // USDT has 6 decimals
);
// Internally converts to: 100000000

Error Handling Example

async function safeSilentSwap(...args: Parameters<typeof executeSilentSwap>) {
  try {
    return await executeSilentSwap(...args);
  } catch (err) {
    if (err instanceof Error) {
      if (err.message.includes('Failed to get nonce')) {
        console.error('Nonce retrieval failed. Check your connection.');
      } else if (err.message.includes('Failed to authenticate')) {
        console.error('Authentication failed. Check your signature.');
      } else if (err.message.includes('Failed to get quote')) {
        console.error('Quote request failed. Check your parameters.');
      } else if (err.message.includes('Failed to place order')) {
        console.error('Order creation failed. Check your authorizations.');
      } else {
        console.error('Unexpected error:', err.message);
      }
    }
    throw err;
  }
}

Backend Service Example

import express from 'express';
import { executeSilentSwap } from './silent-swap';
 
const app = express();
app.use(express.json());
 
app.post('/api/silent-swap', async (req, res) => {
  try {
    const { recipientAddress, tokenAddress, amount, decimals } = req.body;
 
    const result = await executeSilentSwap(
      recipientAddress,
      tokenAddress,
      amount,
      decimals
    );
 
    res.json({
      success: true,
      orderId: result.orderId,
      depositHash: result.depositHash,
    });
  } catch (err) {
    res.status(500).json({
      success: false,
      error: err instanceof Error ? err.message : 'Unknown error',
    });
  }
});
 
app.listen(3000, () => {
  console.log('Silent Swap API server running on port 3000');
});

Key Concepts

Authentication Flow

  1. Get Nonce: Request a nonce from the SilentSwap API
  2. Sign Message: Create and sign a SIWE (Sign-In with Ethereum) message
  3. Authenticate: Send the signed message to get an auth token
  4. Derive Entropy: Sign the auth token to derive entropy for wallet generation

Facilitator Group

The facilitator group is a hierarchical deterministic (HD) wallet system that generates:

  • Viewer Account: Used to observe order execution
  • Facilitator Accounts: Used to execute the swap on different chains

Order Flow

  1. Quote: Request a quote with your desired outputs
  2. Sign Authorizations: Sign all required authorizations (deposits, meta-txs, etc.)
  3. Sign Order: Sign the order's EIP-712 typed data
  4. Approve Proxies: Approve proxy authorizations from facilitator accounts
  5. Place Order: Submit the complete order to the API
  6. Deposit: Execute the deposit transaction on the source chain
  7. Watch: Monitor for completion on the destination chain

Best Practices

  1. Secure Entropy Storage: Store entropy securely for wallet recovery

  2. Error Handling: Always handle errors at each step with meaningful error messages

  3. Transaction Monitoring: Monitor deposit transactions and watch for completion

  4. Nonce Management: Use the deposit count from queryDepositCount() as the nonce for facilitator groups

  5. Chain Switching: Ensure you're on the correct chain before executing transactions

  6. Bridge Integration: Use solveOptimalUsdcAmount for cross-chain swaps to automatically calculate the optimal USDC amount after bridging

Next Steps