Purpose
This skill enables Claude to help users swap tokens on decentralized exchanges across EVM-compatible networks.
Security Warnings
BEFORE ANY SWAP:
- ALWAYS show the expected output amount and minimum received
- ALWAYS explain slippage and its implications
- ALWAYS check token approvals before swapping
- WARN about potential price impact for large trades
- RECOMMEND checking token contract legitimacy
Supported DEXs
| DEX | Network | Router Address |
|---|---|---|
| PancakeSwap V2 | BNB Chain | 0x10ED43C718714eb63d5aA57B78B54704E256024E |
| PancakeSwap V3 | BNB Chain | 0x13f4EA83D0bd40E75C8222255bc855a974568Dd4 |
| Uniswap V2 | Ethereum | 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D |
| Uniswap V3 | Ethereum | 0xE592427A0AEce92De3Edee1F18E0157C05861564 |
| QuickSwap | Polygon | 0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff |
| SushiSwap | Multiple | Varies by network |
Quick Start
Get Swap Quote (PancakeSwap V2)
import { createPublicClient, http, parseUnits, formatUnits } from 'viem'
import { bsc } from 'viem/chains'
const PANCAKE_ROUTER_ABI = [
{
name: 'getAmountsOut',
type: 'function',
inputs: [
{ name: 'amountIn', type: 'uint256' },
{ name: 'path', type: 'address[]' }
],
outputs: [{ name: 'amounts', type: 'uint256[]' }]
}
]
const publicClient = createPublicClient({
chain: bsc,
transport: http()
})
const PANCAKE_ROUTER = '0x10ED43C718714eb63d5aA57B78B54704E256024E'
const WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
const USDT = '0x55d398326f99059fF775485246999027B3197955'
// Get quote: How much USDT for 1 BNB?
const amountIn = parseUnits('1', 18) // 1 BNB
const path = [WBNB, USDT] // Swap path
const amounts = await publicClient.readContract({
address: PANCAKE_ROUTER,
abi: PANCAKE_ROUTER_ABI,
functionName: 'getAmountsOut',
args: [amountIn, path]
})
console.log('Input:', formatUnits(amounts[0], 18), 'BNB')
console.log('Output:', formatUnits(amounts[1], 18), 'USDT')
Execute Swap (Exact Input)
import { createWalletClient, createPublicClient, http, parseUnits } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { bsc } from 'viem/chains'
const PANCAKE_ROUTER_ABI = [
{
name: 'swapExactTokensForTokens',
type: 'function',
inputs: [
{ name: 'amountIn', type: 'uint256' },
{ name: 'amountOutMin', type: 'uint256' },
{ name: 'path', type: 'address[]' },
{ name: 'to', type: 'address' },
{ name: 'deadline', type: 'uint256' }
],
outputs: [{ name: 'amounts', type: 'uint256[]' }]
},
{
name: 'swapExactETHForTokens',
type: 'function',
inputs: [
{ name: 'amountOutMin', type: 'uint256' },
{ name: 'path', type: 'address[]' },
{ name: 'to', type: 'address' },
{ name: 'deadline', type: 'uint256' }
],
outputs: [{ name: 'amounts', type: 'uint256[]' }],
stateMutability: 'payable'
}
]
const account = privateKeyToAccount('0x...')
const PANCAKE_ROUTER = '0x10ED43C718714eb63d5aA57B78B54704E256024E'
const WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
const USDT = '0x55d398326f99059fF775485246999027B3197955'
const walletClient = createWalletClient({
account,
chain: bsc,
transport: http()
})
// Swap BNB for USDT
const amountIn = parseUnits('0.1', 18) // 0.1 BNB
const amountOutMin = parseUnits('50', 18) // Minimum 50 USDT (with slippage)
const path = [WBNB, USDT]
const deadline = BigInt(Math.floor(Date.now() / 1000) + 60 * 20) // 20 minutes
const hash = await walletClient.writeContract({
address: PANCAKE_ROUTER,
abi: PANCAKE_ROUTER_ABI,
functionName: 'swapExactETHForTokens',
args: [amountOutMin, path, account.address, deadline],
value: amountIn
})
console.log('Swap transaction:', hash)
Common Operations
1. Approve Token for Swap
Before swapping ERC20 tokens, you must approve the router:
import { createWalletClient, http, maxUint256 } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { bsc } from 'viem/chains'
const ERC20_ABI = [
{
name: 'approve',
type: 'function',
inputs: [
{ name: 'spender', type: 'address' },
{ name: 'amount', type: 'uint256' }
],
outputs: [{ name: '', type: 'bool' }]
},
{
name: 'allowance',
type: 'function',
inputs: [
{ name: 'owner', type: 'address' },
{ name: 'spender', type: 'address' }
],
outputs: [{ name: '', type: 'uint256' }]
}
]
const account = privateKeyToAccount('0x...')
const tokenAddress = '0x...' // Token to swap FROM
const routerAddress = '0x10ED43C718714eb63d5aA57B78B54704E256024E'
const publicClient = createPublicClient({
chain: bsc,
transport: http()
})
const walletClient = createWalletClient({
account,
chain: bsc,
transport: http()
})
// Check current allowance
const allowance = await publicClient.readContract({
address: tokenAddress,
abi: ERC20_ABI,
functionName: 'allowance',
args: [account.address, routerAddress]
})
// If allowance is 0, approve
if (allowance === 0n) {
const hash = await walletClient.writeContract({
address: tokenAddress,
abi: ERC20_ABI,
functionName: 'approve',
args: [routerAddress, maxUint256]
})
console.log('Approval tx:', hash)
}
2. Calculate Slippage
// Calculate minimum output with slippage tolerance
function calculateMinOutput(
expectedOutput: bigint,
slippagePercent: number
): bigint {
const slippageBps = BigInt(Math.floor(slippagePercent * 100)) // Convert to basis points
const minOutput = expectedOutput - (expectedOutput * slippageBps / 10000n)
return minOutput
}
// Example: 1% slippage on 100 USDT expected
const expected = parseUnits('100', 18)
const minOutput = calculateMinOutput(expected, 1) // 1% slippage
console.log('Min output:', formatUnits(minOutput, 18)) // 99 USDT
3. Multi-Hop Swap (Token A → Token B → Token C)
// Sometimes direct pair doesn't exist, need to route through intermediate token
const CAKE = '0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82'
const WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
const USDT = '0x55d398326f99059fF775485246999027B3197955'
// Swap CAKE → USDT via WBNB
const multiHopPath = [CAKE, WBNB, USDT]
const amounts = await publicClient.readContract({
address: PANCAKE_ROUTER,
abi: PANCAKE_ROUTER_ABI,
functionName: 'getAmountsOut',
args: [parseUnits('10', 18), multiHopPath]
})
console.log('CAKE in:', formatUnits(amounts[0], 18))
console.log('WBNB intermediate:', formatUnits(amounts[1], 18))
console.log('USDT out:', formatUnits(amounts[2], 18))
4. Check Token Price
// Get token price in terms of another token
async function getTokenPrice(
publicClient: any,
routerAddress: string,
tokenA: string,
tokenB: string,
decimalsA: number,
decimalsB: number
): Promise<string> {
const ROUTER_ABI = [{
name: 'getAmountsOut',
type: 'function',
inputs: [
{ name: 'amountIn', type: 'uint256' },
{ name: 'path', type: 'address[]' }
],
outputs: [{ name: 'amounts', type: 'uint256[]' }]
}]
const amountIn = parseUnits('1', decimalsA)
try {
const amounts = await publicClient.readContract({
address: routerAddress,
abi: ROUTER_ABI,
functionName: 'getAmountsOut',
args: [amountIn, [tokenA, tokenB]]
})
return formatUnits(amounts[1], decimalsB)
} catch {
return 'No liquidity'
}
}
// Example: Get BNB price in USDT
const price = await getTokenPrice(
publicClient,
PANCAKE_ROUTER,
WBNB,
USDT,
18,
18
)
console.log('1 BNB =', price, 'USDT')
Swap Workflow
When a user requests a swap, follow this workflow:
Step 1: Gather Information
Please provide:
1. Network (e.g., BNB Chain, Ethereum)
2. Token to swap FROM (name or address)
3. Token to swap TO (name or address)
4. Amount to swap
5. Slippage tolerance (default: 0.5%)
Step 2: Get Quote and Preview
🔄 Swap Preview
═══════════════════
Network: BNB Smart Chain
DEX: PancakeSwap V2
📥 Input:
Token: BNB
Amount: 1.0 BNB
📤 Output:
Token: USDT
Expected: 612.45 USDT
Minimum (0.5% slippage): 609.38 USDT
💱 Rate: 1 BNB = 612.45 USDT
📊 Price Impact: 0.12%
⛽ Estimated Gas: ~0.001 BNB
⚠️ Slippage tolerance: 0.5%
If price moves more than this, transaction will revert.
Proceed with swap? (yes/no)
Step 3: Check Approval (if needed)
🔐 Token Approval Required
The router needs permission to spend your BNB.
This is a one-time approval for this token.
Approve unlimited amount? (yes/no)
Or specify a specific amount:
Step 4: Execute and Confirm
✅ Swap Initiated!
Transaction Hash: 0x8a2f...b4c1
Status: Pending...
[Waiting for confirmation...]
✅ Swap Confirmed!
Block: 31234567
Input: 1.0 BNB
Output: 611.89 USDT
Gas Used: 152,000
Explorer: https://bscscan.com/tx/0x8a2f...b4c1
Slippage Guide
| Slippage | Use Case |
|---|---|
| 0.1-0.5% | Stable pairs (USDT/USDC), high liquidity |
| 0.5-1% | Major tokens (BNB, ETH), normal market |
| 1-3% | Smaller tokens, moderate volatility |
| 3-5% | Low liquidity tokens, high volatility |
| 5%+ | Meme coins, very low liquidity (risky!) |
Error Handling
Common Errors
| Error | Cause | Solution |
|---|---|---|
| INSUFFICIENT_OUTPUT_AMOUNT | Price moved beyond slippage | Increase slippage or retry |
| TRANSFER_FAILED | Token transfer issue | Check approval, balance |
| EXPIRED | Transaction took too long | Retry with new deadline |
| K | Constant product invariant | Liquidity issue, try smaller amount |
Example Error Handling
try {
const hash = await walletClient.writeContract({
address: PANCAKE_ROUTER,
abi: PANCAKE_ROUTER_ABI,
functionName: 'swapExactETHForTokens',
args: [amountOutMin, path, account.address, deadline],
value: amountIn
})
console.log('Swap successful:', hash)
} catch (error) {
if (error.message.includes('INSUFFICIENT_OUTPUT_AMOUNT')) {
console.log('Error: Price changed too much!')
console.log('Solutions:')
console.log('1. Increase slippage tolerance')
console.log('2. Wait and try again')
console.log('3. Reduce swap amount')
} else if (error.message.includes('EXPIRED')) {
console.log('Error: Transaction expired')
console.log('Please try again with a fresh quote')
} else {
console.log('Swap failed:', error.message)
}
}
Popular Token Pairs
BNB Smart Chain
- BNB/USDT
- BNB/BUSD
- CAKE/BNB
- ETH/BNB
Ethereum
- ETH/USDC
- ETH/USDT
- WBTC/ETH
- UNI/ETH
Best Practices
- Always get fresh quotes - Prices change rapidly
- Start with small amounts - Test the swap works
- Use appropriate slippage - Too low fails, too high loses money
- Check price impact - Large swaps can move the market
- Verify token contracts - Avoid scam tokens
- Consider timing - Gas fees vary, wait for lower fees