examples - saltict/Demo-Docs GitHub Wiki

Usage Examples

Comprehensive examples and code samples for integrating the SubWallet Services SDK into your applications.

📖 Navigation


Table of Contents

Quick Start Examples

Basic SDK Setup and Usage

import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk';

// Configure the SDK
subwalletApiSdk.updateConfig({
  platform: 'webapp'
});

// Simple price history fetch
async function getTokenPrice() {
  try {
    const priceHistory = await subwalletApiSdk.priceHistoryApi.getPriceHistory('DOT', '1W');
    console.log('Price data points:', priceHistory.history.length);
    console.log('Latest price:', priceHistory.history[priceHistory.history.length - 1]);
  } catch (error) {
    console.error('Failed to fetch price:', error);
  }
}

getTokenPrice();

SDK Information and Health Check

// Check SDK version and availability
function sdkHealthCheck() {
  console.log('SDK Version:', subwalletApiSdk.version);
  console.log('Platform Headers:', subwalletApiSdk.headers);
  
  // Check service availability
  const services = {
    balanceDetection: !!subwalletApiSdk.balanceDetectionApi,
    priceHistory: !!subwalletApiSdk.priceHistoryApi,
    swap: !!subwalletApiSdk.swapApi,
    xcm: !!subwalletApiSdk.xcmApi,
    cardano: !!subwalletApiSdk.cardanoApi
  };
  
  console.log('Available Services:', services);
  return services;
}

sdkHealthCheck();

Service-Specific Examples

Price History API

Get historical price data for tokens with different timeframes.

// Get price history for different timeframes
async function priceHistoryExamples() {
  try {
    // 1 Day price history
    const dailyPrices = await subwalletApiSdk.priceHistoryApi.getPriceHistory('DOT', '1D');
    console.log('Daily prices (24h):', dailyPrices.history.length, 'data points');
    
    // 1 Week price history
    const weeklyPrices = await subwalletApiSdk.priceHistoryApi.getPriceHistory('KSM', '1W');
    console.log('Weekly prices:', weeklyPrices.history.length, 'data points');
    
    // 1 Month price history
    const monthlyPrices = await subwalletApiSdk.priceHistoryApi.getPriceHistory('ACA', '1M');
    console.log('Monthly prices:', monthlyPrices.history.length, 'data points');
    
    // Year-to-date price history
    const ytdPrices = await subwalletApiSdk.priceHistoryApi.getPriceHistory('GLMR', 'YTD');
    console.log('YTD prices:', ytdPrices.history.length, 'data points');
    
  } catch (error) {
    console.error('Price history error:', error);
  }
}

// Price change calculation
function calculatePriceChange(priceHistory: any) {
  const history = priceHistory.history;
  if (history.length < 2) return null;
  
  const latest = history[history.length - 1].value;
  const previous = history[0].value;
  const change = ((latest - previous) / previous) * 100;
  
  return {
    latest,
    previous,
    change: change.toFixed(2),
    direction: change > 0 ? 'up' : change < 0 ? 'down' : 'stable'
  };
}

// Usage
priceHistoryExamples();

Balance Detection API

Detect token balances for EVM addresses.

// Get EVM token balance slugs
async function balanceDetectionExamples() {
  try {
    const address = '0x742d35Cc6565C0532F3E4db7c5F804E5D5eDeF94';
    
    // Get token slugs for the address
    const tokenSlugs = await subwalletApiSdk.balanceDetectionApi.getEvmTokenBalanceSlug(address);
    
    console.log('Token slugs found:', tokenSlugs);
    console.log('Number of tokens:', tokenSlugs.length);
    
    return tokenSlugs;
  } catch (error) {
    console.error('Balance detection error:', error);
  }
}

// Batch balance detection for multiple addresses
async function batchBalanceDetection() {
  const addresses = [
    '0x742d35Cc6565C0532F3E4db7c5F804E5D5eDeF94',
    '0x8ba1f109551bD432803012645Hac136c7c5DeF95',
    '0x123f567801bD432803012645Hac136c7c5Ab123'
  ];
  
  try {
    const balancePromises = addresses.map(address =>
      subwalletApiSdk.balanceDetectionApi.getEvmTokenBalanceSlug(address)
    );
    
    const results = await Promise.allSettled(balancePromises);
    
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        console.log(`Address ${addresses[index]}: ${result.value.length} tokens`);
      } else {
        console.error(`Address ${addresses[index]} failed:`, result.reason);
      }
    });
  } catch (error) {
    console.error('Batch balance detection error:', error);
  }
}

balanceDetectionExamples();

XCM API

Cross-chain transfer operations within the Polkadot ecosystem.

// XCM transfer example
async function xcmTransferExample() {
  try {
    const xcmRequest = {
      address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',  // Sender address
      from: 'polkadot',           // Source chain
      to: 'acala',               // Destination chain
      recipient: '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',  // Recipient address
      value: '1000000000000'      // Amount in smallest unit (10 DOT)
    };
    
    const xcmData = await subwalletApiSdk.xcmApi.fetchXcmData(xcmRequest);
    
    console.log('XCM Transfer Data:', {
      sender: xcmData.sender,
      to: xcmData.to,
      value: xcmData.value,
      encodedCall: xcmData.transferEncodedCall.substring(0, 50) + '...' // Truncate for display
    });
    
    return xcmData;
  } catch (error) {
    console.error('XCM transfer error:', error);
  }
}

// XCM fee estimation helper
async function estimateXcmFee(from: string, to: string, amount: string) {
  try {
    const xcmRequest = {
      address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
      from,
      to,
      recipient: '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
      value: amount
    };
    
    const xcmData = await subwalletApiSdk.xcmApi.fetchXcmData(xcmRequest);
    
    // Extract fee information from metadata if available
    const fee = xcmData.metadata?.fee || 'Fee information not available';
    
    return {
      from,
      to,
      amount,
      estimatedFee: fee,
      transferCall: xcmData.transferEncodedCall
    };
  } catch (error) {
    console.error('XCM fee estimation error:', error);
    throw error;
  }
}

xcmTransferExample();

Cardano API

Cardano-specific transaction building.

// Cardano transaction building
async function cardanoTransactionExample() {
  try {
    const txRequest = {
      sender: 'addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj0vs2qd4a6gtmydwfqq5e8a0m',
      receiver: 'addr1qy93ktfeuwxm4k7k9u8xy6qxh0vlalq8a5q2kxj4rtj3v2ycu5d8ps7zex2k2xt3uqxgjqnnj0vs2qd4a6gtmydwfqq5dcd7',
      unit: 'lovelace',           // ADA in lovelace (1 ADA = 1,000,000 lovelace)
      quantity: '2000000'         // 2 ADA
    };
    
    const unsignedPayload = await subwalletApiSdk.cardanoApi.fetchUnsignedPayload(txRequest);
    
    console.log('Cardano Unsigned Transaction:', {
      sender: txRequest.sender,
      receiver: txRequest.receiver,
      amount: `${parseFloat(txRequest.quantity) / 1000000} ADA`,
      payload: unsignedPayload.substring(0, 100) + '...' // Truncate for display
    });
    
    return unsignedPayload;
  } catch (error) {
    console.error('Cardano transaction error:', error);
  }
}

// Cardano native token transfer
async function cardanoNativeTokenTransfer() {
  try {
    const nativeTokenTx = {
      sender: 'addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj0vs2qd4a6gtmydwfqq5e8a0m',
      receiver: 'addr1qy93ktfeuwxm4k7k9u8xy6qxh0vlalq8a5q2kxj4rtj3v2ycu5d8ps7zex2k2xt3uqxgjqnnj0vs2qd4a6gtmydwfqq5dcd7',
      unit: 'a0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235.484f534b59', // Example native token
      quantity: '1000'
    };
    
    const payload = await subwalletApiSdk.cardanoApi.fetchUnsignedPayload(nativeTokenTx);
    
    console.log('Native Token Transfer Payload:', payload);
    return payload;
  } catch (error) {
    console.error('Native token transfer error:', error);
  }
}

cardanoTransactionExample();

Swap API

Token swap operations and route finding.

// Note: Swap API implementation details may vary based on actual service endpoints
// This example shows the expected usage pattern

async function swapOperationExample() {
  try {
    // Example swap request (actual interface may differ based on implementation)
    const swapParams = {
      tokenIn: 'DOT',
      tokenOut: 'USDT',
      amountIn: '10',
      slippage: '0.5', // 0.5% slippage tolerance
      recipient: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
    };
    
    // Note: Actual method names and parameters depend on implementation
    console.log('Swap request prepared:', swapParams);
    
    // The SwapApi is available but specific methods depend on backend implementation
    console.log('Swap API available:', !!subwalletApiSdk.swapApi);
    
  } catch (error) {
    console.error('Swap operation error:', error);
  }
}

swapOperationExample();

Platform Integration Examples

React Application Integration

Complete React component examples with hooks and state management.

// React hook for price data
import React, { useState, useEffect } from 'react';
import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk';

interface PriceData {
  token: string;
  timeframe: string;
  history: Array<{ time: number; value: number }>;
  loading: boolean;
  error: string | null;
}

export const usePriceHistory = (token: string, timeframe: string) => {
  const [priceData, setPriceData] = useState<PriceData>({
    token,
    timeframe,
    history: [],
    loading: true,
    error: null
  });

  useEffect(() => {
    let isMounted = true;

    const fetchPriceHistory = async () => {
      try {
        setPriceData(prev => ({ ...prev, loading: true, error: null }));
        
        const result = await subwalletApiSdk.priceHistoryApi.getPriceHistory(token, timeframe);
        
        if (isMounted) {
          setPriceData(prev => ({
            ...prev,
            history: result.history,
            loading: false
          }));
        }
      } catch (error) {
        if (isMounted) {
          setPriceData(prev => ({
            ...prev,
            loading: false,
            error: error instanceof Error ? error.message : 'Unknown error'
          }));
        }
      }
    };

    fetchPriceHistory();

    return () => {
      isMounted = false;
    };
  }, [token, timeframe]);

  return priceData;
};

// React component using the hook
export const PriceChart: React.FC<{ token: string; timeframe: string }> = ({ token, timeframe }) => {
  const { history, loading, error } = usePriceHistory(token, timeframe);

  if (loading) return <div>Loading price data...</div>;
  if (error) return <div>Error: {error}</div>;
  if (history.length === 0) return <div>No price data available</div>;

  const currentPrice = history[history.length - 1]?.value;
  const previousPrice = history[0]?.value;
  const priceChange = currentPrice && previousPrice ? 
    ((currentPrice - previousPrice) / previousPrice * 100).toFixed(2) : '0';

  return (
    <div className="price-chart">
      <h3>{token} Price Chart</h3>
      <div className="price-info">
        <span className="current-price">${currentPrice?.toFixed(2)}</span>
        <span className={`price-change ${parseFloat(priceChange) >= 0 ? 'positive' : 'negative'}`}>
          {parseFloat(priceChange) >= 0 ? '+' : ''}{priceChange}%
        </span>
      </div>
      <div className="chart-container">
        {/* Chart implementation would go here */}
        <div>Chart with {history.length} data points</div>
      </div>
    </div>
  );
};

Vue.js Integration

// Vue 3 Composition API example
import { ref, computed, onMounted, watch } from 'vue';
import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk';

export default {
  setup() {
    const balances = ref([]);
    const loading = ref(false);
    const error = ref(null);
    const walletAddress = ref('');

    const fetchBalances = async () => {
      if (!walletAddress.value) return;
      
      loading.value = true;
      error.value = null;
      
      try {
        const tokenSlugs = await subwalletApiSdk.balanceDetectionApi.getEvmTokenBalanceSlug(walletAddress.value);
        balances.value = tokenSlugs;
      } catch (err) {
        error.value = err.message;
      } finally {
        loading.value = false;
      }
    };

    const totalTokens = computed(() => balances.value.length);

    watch(walletAddress, fetchBalances);

    onMounted(() => {
      // Configure SDK for web app
      subwalletApiSdk.updateConfig({ platform: 'webapp' });
    });

    return {
      balances,
      loading,
      error,
      walletAddress,
      totalTokens,
      fetchBalances
    };
  }
};

Browser Extension Integration

// Background script (service worker)
// background.js
import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk';

// Configure for extension environment
subwalletApiSdk.updateConfig({
  platform: 'extension'
});

// Handle messages from content script or popup
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  const handleApiRequest = async () => {
    try {
      let result;
      
      switch (request.action) {
        case 'getPriceHistory':
          result = await subwalletApiSdk.priceHistoryApi.getPriceHistory(
            request.token,
            request.timeframe
          );
          break;
          
        case 'getBalances':
          result = await subwalletApiSdk.balanceDetectionApi.getEvmTokenBalanceSlug(
            request.address
          );
          break;
          
        case 'buildXcmTransfer':
          result = await subwalletApiSdk.xcmApi.fetchXcmData(request.xcmRequest);
          break;
          
        default:
          throw new Error(`Unknown action: ${request.action}`);
      }
      
      sendResponse({ success: true, data: result });
    } catch (error) {
      sendResponse({ success: false, error: error.message });
    }
  };
  
  handleApiRequest();
  return true; // Keep message channel open for async response
});

// Popup script
// popup.js
function sendMessageToBackground(action, params) {
  return new Promise((resolve, reject) => {
    chrome.runtime.sendMessage({ action, ...params }, (response) => {
      if (response.success) {
        resolve(response.data);
      } else {
        reject(new Error(response.error));
      }
    });
  });
}

// Usage in popup
async function displayTokenPrices() {
  try {
    const priceData = await sendMessageToBackground('getPriceHistory', {
      token: 'DOT',
      timeframe: '1D'
    });
    
    document.getElementById('price-display').textContent = 
      `Current Price: $${priceData.history[priceData.history.length - 1].value}`;
  } catch (error) {
    console.error('Failed to fetch price:', error);
  }
}

Advanced Usage Patterns

Error Handling with Retry Logic

// Advanced error handling with exponential backoff
class APIRetryHandler {
  async retryWithBackoff<T>(
    apiCall: () => Promise<T>,
    maxRetries: number = 3,
    baseDelay: number = 1000
  ): Promise<T> {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        return await apiCall();
      } catch (error) {
        if (attempt === maxRetries) {
          throw new Error(`API call failed after ${maxRetries} attempts: ${error.message}`);
        }
        
        const delay = baseDelay * Math.pow(2, attempt - 1);
        console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
    
    throw new Error('Unexpected error in retry logic');
  }
}

const retryHandler = new APIRetryHandler();

// Usage with retry logic
async function robustPriceHistoryFetch(token: string, timeframe: string) {
  return retryHandler.retryWithBackoff(
    () => subwalletApiSdk.priceHistoryApi.getPriceHistory(token, timeframe),
    3,  // Max 3 retries
    1000 // Start with 1 second delay
  );
}

Batch Operations with Rate Limiting

// Batch operations with rate limiting
class BatchProcessor {
  constructor(private rateLimit: number = 5, private interval: number = 1000) {}

  async processBatch<T, R>(
    items: T[],
    processor: (item: T) => Promise<R>,
    onProgress?: (completed: number, total: number) => void
  ): Promise<R[]> {
    const results: R[] = [];
    const batches = this.createBatches(items, this.rateLimit);
    
    for (let i = 0; i < batches.length; i++) {
      const batch = batches[i];
      const batchPromises = batch.map(processor);
      const batchResults = await Promise.allSettled(batchPromises);
      
      batchResults.forEach((result, index) => {
        if (result.status === 'fulfilled') {
          results.push(result.value);
        } else {
          console.error(`Batch item ${index} failed:`, result.reason);
          results.push(null as any); // or handle error appropriately
        }
      });
      
      if (onProgress) {
        onProgress(results.length, items.length);
      }
      
      // Wait before next batch (except for last batch)
      if (i < batches.length - 1) {
        await new Promise(resolve => setTimeout(resolve, this.interval));
      }
    }
    
    return results;
  }

  private createBatches<T>(items: T[], batchSize: number): T[][] {
    const batches: T[][] = [];
    for (let i = 0; i < items.length; i += batchSize) {
      batches.push(items.slice(i, i + batchSize));
    }
    return batches;
  }
}

// Usage
const batchProcessor = new BatchProcessor(3, 2000); // 3 requests per 2 seconds

async function batchPriceHistoryFetch(tokens: string[]) {
  return batchProcessor.processBatch(
    tokens,
    token => subwalletApiSdk.priceHistoryApi.getPriceHistory(token, '1D'),
    (completed, total) => {
      console.log(`Progress: ${completed}/${total} tokens processed`);
    }
  );
}

// Fetch price data for multiple tokens
const tokens = ['DOT', 'KSM', 'ACA', 'GLMR', 'ASTR'];
batchPriceHistoryFetch(tokens).then(results => {
  console.log('All price data fetched:', results);
});

Caching Layer Implementation

// Advanced caching with TTL and storage backends
interface CacheEntry<T> {
  data: T;
  timestamp: number;
  ttl: number;
}

class AdvancedCache {
  private memoryCache = new Map<string, CacheEntry<any>>();
  
  constructor(
    private defaultTTL: number = 60000, // 1 minute
    private useLocalStorage: boolean = true
  ) {}

  async get<T>(
    key: string,
    fetcher: () => Promise<T>,
    customTTL?: number
  ): Promise<T> {
    const ttl = customTTL || this.defaultTTL;
    
    // Check memory cache first
    const memoryEntry = this.memoryCache.get(key);
    if (memoryEntry && this.isValid(memoryEntry)) {
      return memoryEntry.data;
    }
    
    // Check localStorage cache
    if (this.useLocalStorage) {
      const storageEntry = this.getFromStorage<T>(key);
      if (storageEntry && this.isValid(storageEntry)) {
        // Restore to memory cache
        this.memoryCache.set(key, storageEntry);
        return storageEntry.data;
      }
    }
    
    // Fetch fresh data
    const data = await fetcher();
    const entry: CacheEntry<T> = {
      data,
      timestamp: Date.now(),
      ttl
    };
    
    // Store in caches
    this.memoryCache.set(key, entry);
    if (this.useLocalStorage) {
      this.setToStorage(key, entry);
    }
    
    return data;
  }

  private isValid<T>(entry: CacheEntry<T>): boolean {
    return Date.now() - entry.timestamp < entry.ttl;
  }

  private getFromStorage<T>(key: string): CacheEntry<T> | null {
    try {
      const item = localStorage.getItem(`subwallet-cache-${key}`);
      return item ? JSON.parse(item) : null;
    } catch {
      return null;
    }
  }

  private setToStorage<T>(key: string, entry: CacheEntry<T>): void {
    try {
      localStorage.setItem(`subwallet-cache-${key}`, JSON.stringify(entry));
    } catch (error) {
      console.warn('Failed to store in localStorage:', error);
    }
  }

  clear(): void {
    this.memoryCache.clear();
    if (this.useLocalStorage) {
      const keys = Object.keys(localStorage).filter(key => 
        key.startsWith('subwallet-cache-')
      );
      keys.forEach(key => localStorage.removeItem(key));
    }
  }
}

// Create cached API wrapper
const cache = new AdvancedCache();

const cachedSDK = {
  priceHistory: {
    getPriceHistory: (token: string, timeframe: string) => 
      cache.get(
        `price-${token}-${timeframe}`,
        () => subwalletApiSdk.priceHistoryApi.getPriceHistory(token, timeframe),
        300000 // 5 minutes for price data
      )
  },
  
  balanceDetection: {
    getEvmTokenBalanceSlug: (address: string) =>
      cache.get(
        `balance-${address}`,
        () => subwalletApiSdk.balanceDetectionApi.getEvmTokenBalanceSlug(address),
        60000 // 1 minute for balance data
      )
  }
};

// Usage
const priceData = await cachedSDK.priceHistory.getPriceHistory('DOT', '1W');

Real-World Use Cases

Portfolio Dashboard

Complete portfolio tracking application example.

// Portfolio dashboard implementation
interface TokenHolding {
  symbol: string;
  balance: number;
  priceData: any;
  value: number;
  change24h: number;
}

class PortfolioDashboard {
  private cache = new AdvancedCache(300000); // 5 minute cache
  
  async getPortfolioData(walletAddress: string): Promise<{
    totalValue: number;
    holdings: TokenHolding[];
    totalChange24h: number;
  }> {
    try {
      // Get detected tokens for the address
      const tokenSlugs = await this.cache.get(
        `tokens-${walletAddress}`,
        () => subwalletApiSdk.balanceDetectionApi.getEvmTokenBalanceSlug(walletAddress)
      );
      
      // For this example, we'll map token slugs to actual tokens
      // In reality, you'd need additional APIs to get balance amounts
      const mockHoldings = await this.getMockHoldings(tokenSlugs);
      
      // Get price data for each holding
      const holdings: TokenHolding[] = await Promise.all(
        mockHoldings.map(async (holding) => {
          const priceData = await this.cache.get(
            `price-${holding.symbol}-1D`,
            () => subwalletApiSdk.priceHistoryApi.getPriceHistory(holding.symbol, '1D')
          );
          
          const currentPrice = priceData.history[priceData.history.length - 1]?.value || 0;
          const previousPrice = priceData.history[0]?.value || 0;
          const change24h = previousPrice ? ((currentPrice - previousPrice) / previousPrice) * 100 : 0;
          
          return {
            ...holding,
            priceData,
            value: holding.balance * currentPrice,
            change24h
          };
        })
      );
      
      const totalValue = holdings.reduce((sum, holding) => sum + holding.value, 0);
      const totalChange24h = holdings.length > 0 ? 
        holdings.reduce((sum, holding) => sum + holding.change24h, 0) / holdings.length : 0;
      
      return {
        totalValue,
        holdings,
        totalChange24h
      };
    } catch (error) {
      console.error('Portfolio data fetch failed:', error);
      throw error;
    }
  }
  
  private async getMockHoldings(tokenSlugs: string[]) {
    // Mock implementation - in reality, you'd get actual balance data
    return tokenSlugs.slice(0, 5).map((slug, index) => ({
      symbol: ['DOT', 'KSM', 'ACA', 'GLMR', 'ASTR'][index] || 'UNKNOWN',
      balance: Math.random() * 1000 + 10 // Mock balance
    }));
  }
}

// Usage
const portfolio = new PortfolioDashboard();
const portfolioData = await portfolio.getPortfolioData('0x742d35Cc6565C0532F3E4db7c5F804E5D5eDeF94');
console.log('Portfolio Value:', portfolioData.totalValue);
console.log('24h Change:', portfolioData.totalChange24h);

Cross-Chain Transfer Helper

// Cross-chain transfer utility
class CrossChainTransferHelper {
  async estimateTransferCost(
    from: string,
    to: string,
    amount: string,
    token: string = 'DOT'
  ) {
    try {
      // Get current token price for USD estimation
      const priceData = await subwalletApiSdk.priceHistoryApi.getPriceHistory(token, '1D');
      const currentPrice = priceData.history[priceData.history.length - 1]?.value || 0;
      
      // Build XCM transfer to get fee estimation
      const xcmRequest = {
        address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', // Mock address
        from,
        to,
        recipient: '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', // Mock recipient
        value: amount
      };
      
      const xcmData = await subwalletApiSdk.xcmApi.fetchXcmData(xcmRequest);
      
      // Extract fee from metadata (implementation depends on actual API response)
      const estimatedFee = xcmData.metadata?.fee || '0';
      const feeInToken = parseFloat(estimatedFee) / Math.pow(10, 10); // Assuming 10 decimal places
      const feeInUSD = feeInToken * currentPrice;
      
      return {
        from,
        to,
        amount,
        token,
        estimatedFee: feeInToken,
        estimatedFeeUSD: feeInUSD,
        transferCall: xcmData.transferEncodedCall,
        currentTokenPrice: currentPrice
      };
    } catch (error) {
      console.error('Transfer cost estimation failed:', error);
      throw error;
    }
  }
  
  async getSupportedRoutes() {
    // Mock implementation - in reality, this would come from an API
    return {
      polkadot: ['acala', 'moonbeam', 'astar', 'parallel'],
      kusama: ['karura', 'moonriver', 'shiden', 'heiko'],
      acala: ['polkadot', 'moonbeam'],
      moonbeam: ['polkadot', 'acala']
    };
  }
}

// Usage
const transferHelper = new CrossChainTransferHelper();
const cost = await transferHelper.estimateTransferCost('polkadot', 'acala', '10000000000000');
console.log('Transfer cost:', cost);

This comprehensive examples documentation provides developers with practical, real-world usage patterns for the SubWallet Services SDK across different platforms and use cases.


🔗 Related Documentation

⚠️ **GitHub.com Fallback** ⚠️