Advanced Features
This guide covers advanced SwapKit features for building sophisticated DeFi applications.
Multi-Chain Operations
Section titled “Multi-Chain Operations”SwapKit excels at coordinating operations across multiple blockchains simultaneously.
Batch Balance Fetching
Section titled “Batch Balance Fetching”Fetch balances across all connected chains efficiently:
import { createSwapKit, Chain } from '@swapkit/sdk';import { SwapKitApi } from '@swapkit/helpers/api';
const swapKit = createSwapKit();
// Connect multiple chainsawait swapKit.connectKeystore( [Chain.Ethereum, Chain.Bitcoin, Chain.Avalanche, Chain.THORChain], 'your mnemonic phrase');
// Get all balances in parallelconst chains = [Chain.Ethereum, Chain.Bitcoin, Chain.Avalanche, Chain.THORChain];const balances = await Promise.all( chains.map(chain => swapKit.getBalance(chain, true)));
// Flatten and filter significant balancesconst allAssets = balances .flat() .filter(asset => asset.getValue('number') > 0.01);
// Calculate total USD valueconst priceData = await SwapKitApi.getPrice({ tokens: allAssets.map(a => ({ identifier: a.toString() })), metadata: false});
// Convert array response to a map for easier lookupconst prices = priceData.reduce((acc, item) => { if (item.identifier && item.price_usd) { acc[item.identifier] = item.price_usd; } return acc;}, {} as Record<string, number>);
const totalValue = allAssets.reduce((sum, asset) => { const price = prices[asset.toString()] || 0; return sum + (asset.getValue('number') * price);}, 0);
Cross-Chain Transaction Batching
Section titled “Cross-Chain Transaction Batching”Execute multiple transactions across different chains:
import { AssetValue, FeeOption } from '@swapkit/sdk';
// Prepare multiple transactionsconst transactions = [ { chain: Chain.Ethereum, assetValue: AssetValue.from({ asset: 'ETH.ETH', value: 0.1 }), recipient: '0x...' }, { chain: Chain.Bitcoin, assetValue: AssetValue.from({ asset: 'BTC.BTC', value: 0.001 }), recipient: 'bc1q...' }, { chain: Chain.Avalanche, assetValue: AssetValue.from({ asset: 'AVAX.AVAX', value: 1 }), recipient: '0x...' }];
// Execute all transactionsconst results = await Promise.allSettled( transactions.map(tx => swapKit.transfer({ ...tx, feeOptionKey: FeeOption.Fast }) ));
// Handle resultsresults.forEach((result, index) => { if (result.status === 'fulfilled') { console.log(`${transactions[index].chain} tx: ${result.value}`); } else { console.error(`${transactions[index].chain} failed:`, result.reason); }});
Synthetic Assets
Section titled “Synthetic Assets”THORChain synthetic assets provide instant swaps without waiting for L1 confirmations.
Understanding Synthetics
Section titled “Understanding Synthetics”Synthetic assets are represented with /
notation:
BTC/BTC
- Synthetic BitcoinETH/ETH
- Synthetic EthereumAVAX/AVAX
- Synthetic Avalanche
Minting Synthetics
Section titled “Minting Synthetics”Convert L1 assets to synthetics for faster swaps:
import { SwapKitApi } from '@swapkit/helpers/api';
// Get quote for minting synthetic BTCconst mintQuote = await SwapKitApi.getSwapQuote({ sellAsset: 'BTC.BTC', sellAmount: '10000000', // 0.1 BTC buyAsset: 'BTC/BTC', // Synthetic BTC sourceAddress: swapKit.getAddress(Chain.Bitcoin), destinationAddress: swapKit.getAddress(Chain.THORChain), slippage: 3});
// Execute mintconst mintTx = await swapKit.swap({ route: mintQuote.routes[0]});
Synth Swaps
Section titled “Synth Swaps”Swap between synthetics instantly:
// Instant swap between synthetics (no L1 wait)const synthSwapQuote = await SwapKitApi.getSwapQuote({ sellAsset: 'BTC/BTC', // Synthetic BTC sellAmount: '10000000', buyAsset: 'ETH/ETH', // Synthetic ETH sourceAddress: swapKit.getAddress(Chain.THORChain), destinationAddress: swapKit.getAddress(Chain.THORChain), slippage: 1 // Lower slippage for synth swaps});
// This swap is instant!const swapTx = await swapKit.swap({ route: synthSwapQuote.routes[0]});
Redeeming Synthetics
Section titled “Redeeming Synthetics”Convert synthetics back to L1 assets:
// Redeem synthetic ETH to real ETHconst redeemQuote = await SwapKitApi.getSwapQuote({ sellAsset: 'ETH/ETH', // Synthetic ETH sellAmount: '1000000000000000000', buyAsset: 'ETH.ETH', // L1 ETH sourceAddress: swapKit.getAddress(Chain.THORChain), destinationAddress: swapKit.getAddress(Chain.Ethereum), slippage: 3});
const redeemTx = await swapKit.swap({ route: redeemQuote.routes[0]});
Custom Transaction Memos
Section titled “Custom Transaction Memos”THORChain and Maya use transaction memos for protocol instructions.
Memo Types
Section titled “Memo Types”// Swap memoconst swapMemo = 'SWAP:BTC.BTC:bc1q...';
// Add liquidity memoconst addLiquidityMemo = '+:BTC.BTC:bc1q...';
// Withdraw liquidity memoconst withdrawMemo = '-:BTC.BTC:10000'; // Basis points
// THORName registrationconst thornameeMemo = '~:name:chain:address';
Building Custom Memos
Section titled “Building Custom Memos”import { getMemoForDeposit, getMemoForWithdraw, MemoType } from '@swapkit/sdk';
// Build deposit (liquidity) memoconst depositMemo = getMemoForDeposit({ chain: Chain.Bitcoin, symbol: 'BTC', address: 'bc1q...', // Optional: asymmetric add affiliateAddress: 'ss', affiliateBasisPoints: 50 // 0.5% fee});
// Build withdraw memoconst withdrawMemo = getMemoForWithdraw({ chain: Chain.Bitcoin, symbol: 'BTC', ticker: 'BTC', basisPoints: 10000, // 100% targetAsset: 'ETH.ETH' // Optional: withdraw to different asset});
Custom Route Building
Section titled “Custom Route Building”Build custom swap routes for specific requirements:
// Get all available routesconst { routes } = await SwapKitApi.getSwapQuote({ sellAsset: 'ETH.ETH', sellAmount: '1000000000000000000', buyAsset: 'BTC.BTC', sourceAddress: swapKit.getAddress(Chain.Ethereum), destinationAddress: swapKit.getAddress(Chain.Bitcoin), slippage: 3, providers: ['thorchain', 'chainflip', '1inch']});
// Filter routes by criteriaconst customRoute = routes.find(route => { // Prefer THORChain for cross-chain if (route.providers.includes('THORCHAIN')) return true;
// Use 1inch for same-chain swaps if (route.providers.includes('1INCH') && route.sellAsset.split('.')[0] === route.buyAsset.split('.')[0]) { return true; }
return false;});
// Add custom parametersconst modifiedRoute = { ...customRoute, memo: customRoute.memo + ':ss:50', // Add affiliate expiration: new Date(Date.now() + 10 * 60 * 1000).toISOString() // 10 min expiry};
// Execute custom routeawait swapKit.swap({ route: modifiedRoute });
Gas Optimization
Section titled “Gas Optimization”Optimize gas usage across different chains:
import { ChainToChainId, Chain } from '@swapkit/sdk';import { SwapKitApi } from '@swapkit/helpers/api';
// Get current gas ratesconst gasRatesArray = await SwapKitApi.getGasRate();
// Convert to a map for easier lookupconst gasRates = gasRatesArray.reduce((acc, rate) => { acc[rate.chainId] = rate; return acc;}, {} as Record<string, typeof gasRatesArray[0]>);
// Dynamic fee calculationasync function getOptimalFeeOption(chain: Chain, urgency: 'low' | 'medium' | 'high') { const chainId = ChainToChainId[chain]; const gasRate = gasRates[chainId];
if (!gasRate) { throw new Error(`Gas rate not found for chain ${chain}`); }
// Custom fee multipliers const multipliers = { low: 0.8, medium: 1.0, high: 1.5 };
const baseRate = Number(gasRate.value);
return { [Chain.Ethereum]: { maxFeePerGas: Math.floor(baseRate * multipliers[urgency]), maxPriorityFeePerGas: Math.floor(baseRate * 0.1 * multipliers[urgency]) }, [Chain.Bitcoin]: { feeRate: Math.floor(baseRate * multipliers[urgency]) } }[chain];}
// Use optimized feesconst customFees = await getOptimalFeeOption(Chain.Ethereum, 'low');const tx = await swapKit.transfer({ assetValue, recipient, customTxFee: customFees});
Token List Management
Section titled “Token List Management”Manage custom token lists and metadata:
import { AssetValue, ProviderName } from '@swapkit/sdk';import { SwapKitApi } from '@swapkit/helpers/api';
// Get token lists from providersasync function loadTokenList(provider: ProviderName) { const tokenList = await SwapKitApi.getTokenList(provider); return tokenList.tokens;}
// Custom token registry with cachingclass TokenRegistry { private tokens: Map<string, any> = new Map(); private cache: Map<string, { data: any; timestamp: number }> = new Map(); private cacheTTL = 3600000; // 1 hour
async loadProviderTokens(provider: ProviderName) { const cacheKey = `provider_${provider}`; const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTTL) { return cached.data; }
const tokenList = await SwapKitApi.getTokenList(provider); this.cache.set(cacheKey, { data: tokenList, timestamp: Date.now() });
// Index tokens by identifier tokenList.tokens.forEach(token => { this.tokens.set(token.identifier, token); });
return tokenList; }
addCustomToken(token: { chain: string; identifier: string; symbol: string; decimals: number; name?: string; logoURI?: string; address?: string; }) { this.tokens.set(token.identifier, token);
// Register with AssetValue for proper decimal handling AssetValue.setStaticAssets(new Map([[token.identifier, { identifier: token.identifier, chain: token.chain as any, decimal: token.decimals }]])); }
getToken(identifier: string) { return this.tokens.get(identifier); }}
// Usageconst registry = new TokenRegistry();
// Load tokens from a providerawait registry.loadProviderTokens(ProviderName.UNISWAP);
// Add custom tokenregistry.addCustomToken({ chain: 'ETH', identifier: 'ETH.CUSTOM-0x1234567890123456789012345678901234567890', symbol: 'CUSTOM', decimals: 18, name: 'Custom Token', logoURI: 'https://example.com/token.png'});
Transaction Tracking
Section titled “Transaction Tracking”Implement advanced transaction tracking:
import { ChainToChainId } from '@swapkit/sdk';import { SwapKitApi } from '@swapkit/helpers/api';
class TransactionTracker { private pendingTxs: Map<string, any> = new Map();
async trackTransaction(txHash: string, chain: Chain) { this.pendingTxs.set(txHash, { chain, status: 'pending' });
// Poll for updates const interval = setInterval(async () => { try { const chainId = ChainToChainId[chain]; const status = await SwapKitApi.getTrackerDetails({ hash: txHash, chainId });
if (status.status === 'completed') { this.pendingTxs.set(txHash, { ...status, chain }); clearInterval(interval); this.onComplete(txHash, status); } else if (status.status === 'failed') { this.pendingTxs.delete(txHash); clearInterval(interval); this.onFailed(txHash, status); } } catch (error) { // Continue polling } }, 10000); // Check every 10 seconds }
private onComplete(txHash: string, status: any) { console.log(`Transaction ${txHash} completed!`); // Update UI, send notifications, etc. }
private onFailed(txHash: string, status: any) { console.error(`Transaction ${txHash} failed!`); // Handle failure }}
// Usageconst tracker = new TransactionTracker();
// Track a swapconst txHash = await swapKit.swap({ route });await tracker.trackTransaction(txHash, Chain.Ethereum);
Error Recovery
Section titled “Error Recovery”Implement robust error handling and recovery:
import { SwapKitError } from '@swapkit/sdk';
class SwapKitRetry { async executeWithRetry<T>( operation: () => Promise<T>, maxRetries = 3, backoff = 1000 ): Promise<T> { let lastError: Error;
for (let i = 0; i < maxRetries; i++) { try { return await operation(); } catch (error) { lastError = error as Error;
// Don't retry user rejections if (error instanceof SwapKitError && error.message === 'wallet_connection_rejected_by_user') { throw error; }
// Wait before retry with exponential backoff if (i < maxRetries - 1) { await new Promise(resolve => setTimeout(resolve, backoff * Math.pow(2, i)) ); } } }
throw lastError!; }}
// Usageconst retry = new SwapKitRetry();
const result = await retry.executeWithRetry(async () => { return await swapKit.swap({ route });});
Performance Optimization
Section titled “Performance Optimization”Caching Strategy
Section titled “Caching Strategy”class SwapKitCache { private cache = new Map<string, { data: any, timestamp: number }>(); private ttl = 60000; // 1 minute
set(key: string, data: any) { this.cache.set(key, { data, timestamp: Date.now() }); }
get(key: string) { const entry = this.cache.get(key); if (!entry) return null;
if (Date.now() - entry.timestamp > this.ttl) { this.cache.delete(key); return null; }
return entry.data; }}
// Use cache for quotesconst cache = new SwapKitCache();
async function getCachedQuote(params: any) { const key = JSON.stringify(params); const cached = cache.get(key); if (cached) return cached;
const quote = await SwapKitApi.getSwapQuote(params); cache.set(key, quote); return quote;}
Next Steps
Section titled “Next Steps”- Explore THORChain Features for protocol-specific operations
- Review API Reference for all available methods
- Check Examples for real-world implementations