Skip to content
SwapKit is a powerful suite of tools for building blockchain applications.

Advanced Features

This guide covers advanced SwapKit features for building sophisticated DeFi applications.

SwapKit excels at coordinating operations across multiple blockchains simultaneously.

Fetch balances across all connected chains efficiently:

import { createSwapKit, Chain } from '@swapkit/sdk';
import { SwapKitApi } from '@swapkit/helpers/api';
const swapKit = createSwapKit();
// Connect multiple chains
await swapKit.connectKeystore(
[Chain.Ethereum, Chain.Bitcoin, Chain.Avalanche, Chain.THORChain],
'your mnemonic phrase'
);
// Get all balances in parallel
const 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 balances
const allAssets = balances
.flat()
.filter(asset => asset.getValue('number') > 0.01);
// Calculate total USD value
const priceData = await SwapKitApi.getPrice({
tokens: allAssets.map(a => ({ identifier: a.toString() })),
metadata: false
});
// Convert array response to a map for easier lookup
const 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);

Execute multiple transactions across different chains:

import { AssetValue, FeeOption } from '@swapkit/sdk';
// Prepare multiple transactions
const 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 transactions
const results = await Promise.allSettled(
transactions.map(tx =>
swapKit.transfer({
...tx,
feeOptionKey: FeeOption.Fast
})
)
);
// Handle results
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`${transactions[index].chain} tx: ${result.value}`);
} else {
console.error(`${transactions[index].chain} failed:`, result.reason);
}
});

THORChain synthetic assets provide instant swaps without waiting for L1 confirmations.

Synthetic assets are represented with / notation:

  • BTC/BTC - Synthetic Bitcoin
  • ETH/ETH - Synthetic Ethereum
  • AVAX/AVAX - Synthetic Avalanche

Convert L1 assets to synthetics for faster swaps:

import { SwapKitApi } from '@swapkit/helpers/api';
// Get quote for minting synthetic BTC
const 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 mint
const mintTx = await swapKit.swap({
route: mintQuote.routes[0]
});

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]
});

Convert synthetics back to L1 assets:

// Redeem synthetic ETH to real ETH
const 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]
});

THORChain and Maya use transaction memos for protocol instructions.

// Swap memo
const swapMemo = 'SWAP:BTC.BTC:bc1q...';
// Add liquidity memo
const addLiquidityMemo = '+:BTC.BTC:bc1q...';
// Withdraw liquidity memo
const withdrawMemo = '-:BTC.BTC:10000'; // Basis points
// THORName registration
const thornameeMemo = '~:name:chain:address';
import { getMemoForDeposit, getMemoForWithdraw, MemoType } from '@swapkit/sdk';
// Build deposit (liquidity) memo
const depositMemo = getMemoForDeposit({
chain: Chain.Bitcoin,
symbol: 'BTC',
address: 'bc1q...', // Optional: asymmetric add
affiliateAddress: 'ss',
affiliateBasisPoints: 50 // 0.5% fee
});
// Build withdraw memo
const withdrawMemo = getMemoForWithdraw({
chain: Chain.Bitcoin,
symbol: 'BTC',
ticker: 'BTC',
basisPoints: 10000, // 100%
targetAsset: 'ETH.ETH' // Optional: withdraw to different asset
});

Build custom swap routes for specific requirements:

// Get all available routes
const { 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 criteria
const 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 parameters
const modifiedRoute = {
...customRoute,
memo: customRoute.memo + ':ss:50', // Add affiliate
expiration: new Date(Date.now() + 10 * 60 * 1000).toISOString() // 10 min expiry
};
// Execute custom route
await swapKit.swap({ route: modifiedRoute });

Optimize gas usage across different chains:

import { ChainToChainId, Chain } from '@swapkit/sdk';
import { SwapKitApi } from '@swapkit/helpers/api';
// Get current gas rates
const gasRatesArray = await SwapKitApi.getGasRate();
// Convert to a map for easier lookup
const gasRates = gasRatesArray.reduce((acc, rate) => {
acc[rate.chainId] = rate;
return acc;
}, {} as Record<string, typeof gasRatesArray[0]>);
// Dynamic fee calculation
async 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 fees
const customFees = await getOptimalFeeOption(Chain.Ethereum, 'low');
const tx = await swapKit.transfer({
assetValue,
recipient,
customTxFee: customFees
});

Manage custom token lists and metadata:

import { AssetValue, ProviderName } from '@swapkit/sdk';
import { SwapKitApi } from '@swapkit/helpers/api';
// Get token lists from providers
async function loadTokenList(provider: ProviderName) {
const tokenList = await SwapKitApi.getTokenList(provider);
return tokenList.tokens;
}
// Custom token registry with caching
class 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);
}
}
// Usage
const registry = new TokenRegistry();
// Load tokens from a provider
await registry.loadProviderTokens(ProviderName.UNISWAP);
// Add custom token
registry.addCustomToken({
chain: 'ETH',
identifier: 'ETH.CUSTOM-0x1234567890123456789012345678901234567890',
symbol: 'CUSTOM',
decimals: 18,
name: 'Custom Token',
logoURI: 'https://example.com/token.png'
});

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
}
}
// Usage
const tracker = new TransactionTracker();
// Track a swap
const txHash = await swapKit.swap({ route });
await tracker.trackTransaction(txHash, Chain.Ethereum);

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!;
}
}
// Usage
const retry = new SwapKitRetry();
const result = await retry.executeWithRetry(async () => {
return await swapKit.swap({ route });
});
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 quotes
const 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;
}