1import { createPublicClient, createWalletClient, custom, erc20Abi, http, parseAbi, parseUnits } from 'viem'2import { base } from 'viem/chains'34const USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'5const WETH = '0x4200000000000000000000000000000000000006'6const ROUTER = '0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43' // Aerodrome Router7const FACTORY = '0x420DD381b31aEf6683db6B902084cB0FFECe40Da' // Aerodrome classic pools8const routerAbi = parseAbi([9 'function getAmountsOut(uint256 amountIn, (address from, address to, bool stable, address factory)[] routes) view returns (uint256[] amounts)',10 'function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, (address from, address to, bool stable, address factory)[] routes, address to, uint256 deadline) returns (uint256[] amounts)',11])1213const wallet = createWalletClient({ chain: base, transport: custom(window.ethereum!) })14const client = createPublicClient({ chain: base, transport: http() })15const [account] = await wallet.requestAddresses()16const amountIn = parseUnits('1000', 6)17const routes = [{ from: USDC, to: WETH, stable: false, factory: FACTORY }] as const1819// Quote through the volatile USDC/WETH pool.20const amounts = await client.readContract({21 address: ROUTER, abi: routerAbi, functionName: 'getAmountsOut', args: [amountIn, routes],22})23const quoted = amounts[amounts.length - 1]2425// Let the router pull the USDC.26const approval = await wallet.writeContract({27 account, address: USDC, abi: erc20Abi, functionName: 'approve', args: [ROUTER, amountIn],28})29await client.waitForTransactionReceipt({ hash: approval })3031// Swap, accepting no less than 99.5% of the quote, within ten minutes.32const { timestamp } = await client.getBlock()33const swap = await wallet.writeContract({34 account, address: ROUTER, abi: routerAbi, functionName: 'swapExactTokensForTokens',35 args: [amountIn, quoted * 9950n / 10000n, routes, account, timestamp + 600n],36})37await client.waitForTransactionReceipt({ hash: swap })