18 KiB
Add Tokens + BSC Chain Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Add new tokens to ETH/SOL swap+balance+send, add BNB Smart Chain as a new EVM network with PancakeSwap V2 swap.
Architecture: Extend existing multi-chain config-driven architecture. BSC reuses ETH's EVM signing logic (same derivation path, same ethers.Wallet). BSC swap via PancakeSwap V2 Router (Uniswap V2 fork) through a new API proxy. All new SOL tokens go through Jupiter (existing proxy). All new ETH tokens go through Uniswap (existing flow).
Tech Stack: ethers.js v5, Next.js, Express, PancakeSwap V2 ABI, Jupiter API, Uniswap V3/V4 SDK
Token Reference
New ETH Tokens (Uniswap swap)
| Symbol | Contract (checksummed) | Decimals | CoinGecko ID |
|---|---|---|---|
| stETH | 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84 |
18 | staked-ether |
| SHIB | 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE |
18 | shiba-inu |
| LINK | 0x514910771AF9Ca656af840dff83E8264EcF986CA |
18 | chainlink |
| POL | 0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6 |
18 | polygon-ecosystem-token |
| WLFI | 0x66f85e3865D0cFDc009aCF6280A8621f12e46CCf |
18 | world-liberty-financial |
| AAVE | 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9 |
18 | aave |
New SOL Tokens (Jupiter swap)
| Symbol | Mint | Decimals | CoinGecko ID |
|---|---|---|---|
| WIF | EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm |
6 | dogwifcoin |
| POPCAT | 7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr |
9 | popcat |
| TRUMP | 6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN |
6 | official-trump |
| PYTH | HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3 |
6 | pyth-network |
| JTO | jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL |
9 | jito-governance-token |
| W | 85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ |
6 | wormhole |
| BONK | DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263 |
5 | bonk |
| ORCA | orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE |
6 | orca |
| PENGU | 2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv |
6 | pudgy-penguins |
| RAY | 4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R |
6 | raydium |
BSC Chain Config
| Property | Value |
|---|---|
| ChainId | 56 |
| Native | BNB (18 decimals) |
| WBNB | 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c |
| DOGE (BEP-20) | 0xbA2aE424d960c26247Dd6c32edC70B295c744C43 (8 decimals) |
| PancakeSwap V2 Router | 0x10ED43C718714eb63d5aA57B78B54704E256024E |
| Derivation | Same as ETH: m/44'/60'/0'/0/0 |
| RPC | https://bsc-dataseed.binance.org + fallbacks |
| Explorer | https://bscscan.com/tx/ |
Task 1: Add new ETH tokens to swap constants
Files:
- Modify:
apps/web/src/lib/swap/constants.ts
Steps:
- Add 6 new Token instances after PEPE:
const STETH = new Token(ETHEREUM_CHAIN_ID, '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', 18, 'stETH', 'Lido Staked Ether');
const SHIB = new Token(ETHEREUM_CHAIN_ID, '0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE', 18, 'SHIB', 'Shiba Inu');
const LINK = new Token(ETHEREUM_CHAIN_ID, '0x514910771AF9Ca656af840dff83E8264EcF986CA', 18, 'LINK', 'Chainlink');
const POL = new Token(ETHEREUM_CHAIN_ID, '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6', 18, 'POL', 'Polygon');
const WLFI = new Token(ETHEREUM_CHAIN_ID, '0x66f85e3865D0cFDc009aCF6280A8621f12e46CCf', 18, 'WLFI', 'World Liberty Financial');
const AAVE_TOKEN = new Token(ETHEREUM_CHAIN_ID, '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9', 18, 'AAVE', 'Aave');
- Update
SwapTokenSymboltype to include new symbols:
export type SwapTokenSymbol = 'ETH' | 'USDT' | 'USDC' | 'XAUT' | 'UNI' | 'PEPE' | 'stETH' | 'SHIB' | 'LINK' | 'POL' | 'WLFI' | 'AAVE';
-
Add entries to
SWAP_TOKENSrecord for each new token (same pattern as existing). -
Update
SWAP_TOKEN_OPTIONSandSWAP_TOKEN_OPTIONS_BY_CHAIN.ETHto include new symbols. -
Add V3 pool candidates for new tokens (WETH pairs with MEDIUM/HIGH fees):
// stETH
{ tokenA: WETH, tokenB: STETH, fee: FeeAmount.LOW },
{ tokenA: WETH, tokenB: STETH, fee: FeeAmount.MEDIUM },
// SHIB
{ tokenA: WETH, tokenB: SHIB, fee: FeeAmount.MEDIUM },
{ tokenA: WETH, tokenB: SHIB, fee: FeeAmount.HIGH },
// LINK
{ tokenA: WETH, tokenB: LINK, fee: FeeAmount.LOW },
{ tokenA: WETH, tokenB: LINK, fee: FeeAmount.MEDIUM },
// POL
{ tokenA: WETH, tokenB: POL, fee: FeeAmount.MEDIUM },
{ tokenA: WETH, tokenB: POL, fee: FeeAmount.HIGH },
// WLFI
{ tokenA: WETH, tokenB: WLFI, fee: FeeAmount.MEDIUM },
{ tokenA: WETH, tokenB: WLFI, fee: FeeAmount.HIGH },
// AAVE
{ tokenA: WETH, tokenB: AAVE_TOKEN, fee: FeeAmount.LOW },
{ tokenA: WETH, tokenB: AAVE_TOKEN, fee: FeeAmount.MEDIUM },
-
Add V4 pool key candidates similarly.
-
Update
getSlippageBpsto include new volatile tokens:
const volatileTokens: SwapTokenSymbol[] = ['PEPE', 'XAUT', 'UNI', 'SHIB', 'WLFI', 'stETH', 'LINK', 'POL', 'AAVE'];
Task 2: Add new ETH tokens to balance fetcher
Files:
- Modify:
apps/web/src/lib/balances/eth-balances.ts
Steps:
- Add 6 new entries to
ETH_TOKENSarray (after PEPE):
{ chain: 'ETH', symbol: 'stETH', decimals: 18, contractAddress: '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', coinGeckoId: 'staked-ether', isNative: false },
{ chain: 'ETH', symbol: 'SHIB', decimals: 18, contractAddress: '0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE', coinGeckoId: 'shiba-inu', isNative: false },
{ chain: 'ETH', symbol: 'LINK', decimals: 18, contractAddress: '0x514910771AF9Ca656af840dff83E8264EcF986CA', coinGeckoId: 'chainlink', isNative: false },
{ chain: 'ETH', symbol: 'POL', decimals: 18, contractAddress: '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6', coinGeckoId: 'polygon-ecosystem-token', isNative: false },
{ chain: 'ETH', symbol: 'WLFI', decimals: 18, contractAddress: '0x66f85e3865D0cFDc009aCF6280A8621f12e46CCf', coinGeckoId: 'world-liberty-financial', isNative: false },
{ chain: 'ETH', symbol: 'AAVE', decimals: 18, contractAddress: '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9', coinGeckoId: 'aave', isNative: false },
Task 3: Add new ETH tokens to send constants
Files:
- Modify:
apps/web/src/lib/send/constants.ts
Steps:
- Add 6 new token entries under
SEND_CHAINS.ETH.tokens:
stETH: { symbol: 'stETH', contractAddress: '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', decimals: 18 },
SHIB: { symbol: 'SHIB', contractAddress: '0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE', decimals: 18 },
LINK: { symbol: 'LINK', contractAddress: '0x514910771AF9Ca656af840dff83E8264EcF986CA', decimals: 18 },
POL: { symbol: 'POL', contractAddress: '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6', decimals: 18 },
WLFI: { symbol: 'WLFI', contractAddress: '0x66f85e3865D0cFDc009aCF6280A8621f12e46CCf', decimals: 18 },
AAVE: { symbol: 'AAVE', contractAddress: '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9', decimals: 18 },
- Add corresponding
CONTRACT_TO_SYMBOLentries (lowercase addresses).
Task 4: Add new SOL tokens to swap constants
Files:
- Modify:
apps/web/src/lib/swap/constants.ts
Steps:
- Add new entries to
SOL_TOKEN_MINTS:
WIF: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm',
POPCAT: '7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr',
TRUMP: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN',
PYTH: 'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3',
JTO: 'jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL',
W: '85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ',
BONK: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
ORCA: 'orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE',
PENGU: '2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv',
RAY: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
- Add entries to
SOL_TOKEN_DECIMALS:
WIF: 6, POPCAT: 9, TRUMP: 6, PYTH: 6, JTO: 9, W: 6, BONK: 5, ORCA: 6, PENGU: 6, RAY: 6,
- Update
SWAP_TOKEN_OPTIONS_BY_CHAIN.SOL:
SOL: ['SOL', 'USDT', 'USDC', 'PUMP', 'JUP', 'WIF', 'POPCAT', 'TRUMP', 'PYTH', 'JTO', 'W', 'BONK', 'ORCA', 'PENGU', 'RAY'],
Task 5: Add new SOL tokens to balance fetcher + Jupiter whitelist
Files:
- Modify:
apps/web/src/lib/balances/sol-balances.ts - Modify:
apps/api/src/routes/sol-swap-proxy.routes.ts
Steps:
- Add 10 new entries to
SOL_TOKENSarray insol-balances.ts:
{ chain: 'SOL', symbol: 'WIF', decimals: 6, contractAddress: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm', coinGeckoId: 'dogwifcoin', isNative: false },
{ chain: 'SOL', symbol: 'POPCAT', decimals: 9, contractAddress: '7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr', coinGeckoId: 'popcat', isNative: false },
{ chain: 'SOL', symbol: 'TRUMP', decimals: 6, contractAddress: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', coinGeckoId: 'official-trump', isNative: false },
{ chain: 'SOL', symbol: 'PYTH', decimals: 6, contractAddress: 'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3', coinGeckoId: 'pyth-network', isNative: false },
{ chain: 'SOL', symbol: 'JTO', decimals: 9, contractAddress: 'jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL', coinGeckoId: 'jito-governance-token', isNative: false },
{ chain: 'SOL', symbol: 'W', decimals: 6, contractAddress: '85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ', coinGeckoId: 'wormhole', isNative: false },
{ chain: 'SOL', symbol: 'BONK', decimals: 5, contractAddress: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', coinGeckoId: 'bonk', isNative: false },
{ chain: 'SOL', symbol: 'ORCA', decimals: 6, contractAddress: 'orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE', coinGeckoId: 'orca', isNative: false },
{ chain: 'SOL', symbol: 'PENGU', decimals: 6, contractAddress: '2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv', coinGeckoId: 'pudgy-penguins', isNative: false },
{ chain: 'SOL', symbol: 'RAY', decimals: 6, contractAddress: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R', coinGeckoId: 'raydium', isNative: false },
- Add all 10 new mint addresses to
ALLOWED_MINTSinsol-swap-proxy.routes.ts:
const ALLOWED_MINTS = new Set([
'So11111111111111111111111111111111111111112', // SOL
'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', // USDT
'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
'pumpCmXqMfrsAkQ5r49WcJnRayYRqmXz6ae8H7H9Dfn', // PUMP
'JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN', // JUP
'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm', // WIF
'7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr', // POPCAT
'6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', // TRUMP
'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3', // PYTH
'jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL', // JTO
'85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ', // W
'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263', // BONK
'orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE', // ORCA
'2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv', // PENGU
'4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R', // RAY
]);
Task 6: Add new SOL tokens to send constants
Files:
- Modify:
apps/web/src/lib/send/constants.ts
Steps:
-
Add 10 new token entries under
SEND_CHAINS.SOL.tokens(same mint addresses as balance fetcher). -
Add corresponding
CONTRACT_TO_SYMBOLentries for the new SOL mints.
Task 7: Add BSC chain — wallet derivation
Files:
- Modify:
apps/web/src/lib/crypto/derive-keys.ts - Modify:
apps/web/src/lib/balances/types.ts
Steps:
- In
derive-keys.ts, updateChaintype:
export type Chain = 'ETH' | 'BTC' | 'SOL' | 'TRX' | 'BSC';
- Add BSC derivation path (same as ETH):
BSC: "m/44'/60'/0'/0/0",
- In
deriveWalletsFromMnemonic, add BSC wallet. Since BSC uses the same key as ETH:
const bsc = deriveEthWallet(mnemonic); // same key derivation
// ...
{ chain: 'BSC', address: bsc.address, privateKey: bsc.privateKey, derivationPath: DERIVATION_PATHS.BSC },
- In
types.ts, updateBalanceChain:
export type BalanceChain = 'ETH' | 'BTC' | 'SOL' | 'TRX' | 'BSC';
Task 8: Add BSC chain — environment + balance fetcher
Files:
- Modify:
apps/web/src/lib/env.ts - Create:
apps/web/src/lib/balances/bsc-balances.ts - Modify:
apps/web/src/lib/balances/index.ts
Steps:
- Add BSC RPC to
env.ts:
bscRpcUrl: readUrlEnv('NEXT_PUBLIC_BSC_RPC_URL', 'https://bsc-dataseed.binance.org'),
-
Create
bsc-balances.ts— copyeth-balances.tspattern with:BSC_CHAIN_ID = 56BSC_RPC_CANDIDATES:webEnv.bscRpcUrl,https://bsc-dataseed1.defibit.io,https://bsc-dataseed1.ninicoin.ioBSC_TOKENS: BNB native (18 dec, coinGeckoIdbinancecoin) + DOGE BEP-20 (8 dec,0xbA2aE424d960c26247Dd6c32edC70B295c744C43, coinGeckoIddogecoin)fetchBscBalances(address)— same logic asfetchEthBalancesbut with BSC provider- All internal references use
chain: 'BSC'
-
Register in
balances/index.ts:
import { fetchBscBalances } from './bsc-balances';
// ...
const SUPPORTED_CHAINS: BalanceChain[] = ['ETH', 'BTC', 'SOL', 'TRX', 'BSC'];
// ...
BSC: fetchBscBalances,
Task 9: Add BSC chain — swap via PancakeSwap V2 API proxy
Files:
- Create:
apps/api/src/routes/bsc-swap-proxy.routes.ts - Modify:
apps/api/src/app.ts
Steps:
- Create
bsc-swap-proxy.routes.ts— PancakeSwap V2 swap proxy (same pattern astron-swap-proxy.routes.tsbut simpler since it's EVM):
Router endpoints:
GET /quote — calls PancakeSwap V2 Router getAmountsOut via BSC RPC
POST /build — builds swap calldata (approve + swap tx)
Key constants:
PANCAKE_ROUTER = '0x10ED43C718714eb63d5aA57B78B54704E256024E'
WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
DOGE = '0xbA2aE424d960c26247Dd6c32edC70B295c744C43'
BSC_RPC = 'https://bsc-dataseed.binance.org'
Quote logic:
- Create ethers provider with BSC RPC
- Call router.getAmountsOut(amountIn, [fromToken, toToken])
- Return { amountIn, amountOut, from, to }
Build logic:
- For BNB->Token: encode swapExactETHForTokensSupportingFeeOnTransferTokens calldata
- For Token->BNB: check/build approve tx + encode swapExactTokensForETHSupportingFeeOnTransferTokens calldata
- Return { calldata, to, value, approveTx? }
- Register in
app.ts:
import bscSwapProxyRoutes from './routes/bsc-swap-proxy.routes';
// ...
app.use('/api/bsc/swap', bscSwapProxyRoutes);
Task 10: Add BSC to swap constants + UI
Files:
- Modify:
apps/web/src/lib/swap/constants.ts
Steps:
- Update
SwapChain:
export type SwapChain = 'ETH' | 'SOL' | 'TRX' | 'BSC';
- Add BSC token configs:
export const BSC_TOKEN_ADDRESSES: Record<string, string> = {
BNB: 'native',
DOGE: '0xbA2aE424d960c26247Dd6c32edC70B295c744C43',
};
export const BSC_TOKEN_DECIMALS: Record<string, number> = {
BNB: 18,
DOGE: 8,
};
- Add BSC to
SWAP_TOKEN_OPTIONS_BY_CHAIN:
BSC: ['BNB', 'DOGE'],
- Add BSC to
CHAIN_DEFAULT_TOKENS:
BSC: { from: 'BNB', to: 'DOGE' },
- Update
getSlippageBpsForChainto handle BSC:
if (chain === 'BSC') return 50; // 0.50%
- Update
getExplorerTxUrl:
case 'BSC': return `https://bscscan.com/tx/${txHash}`;
Task 11: Add BSC swap execution (client-side)
Files:
- Create:
apps/web/src/lib/swap/bsc/execute.ts - Modify: swap UI hooks/page to add BSC chain option
Steps:
- Create
bsc/execute.ts:
// Similar to TRX swap execute but using ethers.Wallet directly
// 1. Fetch quote from /api/bsc/swap/quote
// 2. Build tx from /api/bsc/swap/build
// 3. If approve needed: sign and send approve tx, wait for confirmation
// 4. Sign and send swap tx via ethers.Wallet connected to BSC RPC
// 5. Return { hash, explorerUrl }
- Update swap page
CHAINSarray:
const CHAINS: SwapChain[] = ['ETH', 'SOL', 'TRX', 'BSC'];
- Update
useSwaphook to handle BSC chain (dispatch toexecuteBscSwap).
Task 12: Add BSC to send/receive
Files:
- Modify:
apps/web/src/lib/send/constants.ts - Modify:
apps/web/src/lib/send/execute.ts - Modify:
apps/web/src/lib/send/validate.ts - Modify:
apps/web/src/lib/qr/generate.ts - Modify:
apps/web/src/lib/qr/parse.ts
Steps:
-
In
send/constants.ts:- Update
SendChain:'ETH' | 'SOL' | 'TRX' | 'BTC' | 'BSC' - Add BSC config:
BSC: { key: 'BSC', label: 'BNB Smart Chain', walletChain: 'BSC', tokens: { BNB: { symbol: 'BNB', contractAddress: null, decimals: 18 }, DOGE: { symbol: 'DOGE', contractAddress: '0xbA2aE424d960c26247Dd6c32edC70B295c744C43', decimals: 8 }, }, explorerTxUrl: 'https://bscscan.com/tx/', },- Add to
SEND_CHAIN_OPTIONS
- Update
-
In
send/execute.ts:- Add BSC case — same as ETH but with BSC provider:
case 'BSC': return executeBscSend(params);executeBscSend: createethers.providers.StaticJsonRpcProvider(bscRpcUrl, 56), useethers.Walletfor native BNB or BEP-20 transfer (identical to ETH logic).
-
In
send/validate.ts:- BSC uses same address format as ETH — add
case 'BSC': return validateEthAddress(address); - Update
detectChainFromAddress— BSC can't be auto-detected (same format as ETH)
- BSC uses same address format as ETH — add
-
In
qr/generate.ts:- Add BSC case using
ethereum:URI scheme with@56chain discriminator:
case 'BSC': return generateBscUri(address, token, amount);generateBscUri:ethereum:${address}@56for native,ethereum:${contract}@56/transfer?address=${to}for BEP-20
- Add BSC case using
-
In
qr/parse.ts:- Handle
@56chain discriminator in ethereum: URIs to distinguish BSC from ETH
- Handle
Task 13: Run typecheck and verify
Steps:
- Run
pnpm typecheckfrom monorepo root - Fix any TypeScript errors
- Verify all imports resolve correctly
Commit Strategy
- After Tasks 1-3 (ETH tokens): commit "feat: add stETH, SHIB, LINK, POL, WLFI, AAVE tokens to ETH swap/balance/send"
- After Tasks 4-6 (SOL tokens): commit "feat: add WIF, POPCAT, TRUMP, PYTH, JTO, W, BONK, ORCA, PENGU, RAY to SOL swap/balance/send"
- After Tasks 7-12 (BSC chain): commit "feat: add BNB Smart Chain with PancakeSwap V2 swap, BNB + DOGE tokens"
- After Task 13: commit "fix: resolve typecheck errors" (if needed)