Files
cryptowallet/docs/plans/2026-03-18-add-tokens-and-bsc.md
2026-04-14 13:30:26 +03:00

490 lines
18 KiB
Markdown

# 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:**
1. Add 6 new Token instances after PEPE:
```ts
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');
```
2. Update `SwapTokenSymbol` type to include new symbols:
```ts
export type SwapTokenSymbol = 'ETH' | 'USDT' | 'USDC' | 'XAUT' | 'UNI' | 'PEPE' | 'stETH' | 'SHIB' | 'LINK' | 'POL' | 'WLFI' | 'AAVE';
```
3. Add entries to `SWAP_TOKENS` record for each new token (same pattern as existing).
4. Update `SWAP_TOKEN_OPTIONS` and `SWAP_TOKEN_OPTIONS_BY_CHAIN.ETH` to include new symbols.
5. Add V3 pool candidates for new tokens (WETH pairs with MEDIUM/HIGH fees):
```ts
// 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 },
```
6. Add V4 pool key candidates similarly.
7. Update `getSlippageBps` to include new volatile tokens:
```ts
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:**
1. Add 6 new entries to `ETH_TOKENS` array (after PEPE):
```ts
{ 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:**
1. Add 6 new token entries under `SEND_CHAINS.ETH.tokens`:
```ts
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 },
```
2. Add corresponding `CONTRACT_TO_SYMBOL` entries (lowercase addresses).
---
## Task 4: Add new SOL tokens to swap constants
**Files:**
- Modify: `apps/web/src/lib/swap/constants.ts`
**Steps:**
1. Add new entries to `SOL_TOKEN_MINTS`:
```ts
WIF: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm',
POPCAT: '7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr',
TRUMP: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN',
PYTH: 'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3',
JTO: 'jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL',
W: '85VBFQZC9TZkfaptBWjvUw7YbZjy52A6mjtPGjstQAmQ',
BONK: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
ORCA: 'orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE',
PENGU: '2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv',
RAY: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
```
2. Add entries to `SOL_TOKEN_DECIMALS`:
```ts
WIF: 6, POPCAT: 9, TRUMP: 6, PYTH: 6, JTO: 9, W: 6, BONK: 5, ORCA: 6, PENGU: 6, RAY: 6,
```
3. Update `SWAP_TOKEN_OPTIONS_BY_CHAIN.SOL`:
```ts
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:**
1. Add 10 new entries to `SOL_TOKENS` array in `sol-balances.ts`:
```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 },
```
2. Add all 10 new mint addresses to `ALLOWED_MINTS` in `sol-swap-proxy.routes.ts`:
```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:**
1. Add 10 new token entries under `SEND_CHAINS.SOL.tokens` (same mint addresses as balance fetcher).
2. Add corresponding `CONTRACT_TO_SYMBOL` entries 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:**
1. In `derive-keys.ts`, update `Chain` type:
```ts
export type Chain = 'ETH' | 'BTC' | 'SOL' | 'TRX' | 'BSC';
```
2. Add BSC derivation path (same as ETH):
```ts
BSC: "m/44'/60'/0'/0/0",
```
3. In `deriveWalletsFromMnemonic`, add BSC wallet. Since BSC uses the same key as ETH:
```ts
const bsc = deriveEthWallet(mnemonic); // same key derivation
// ...
{ chain: 'BSC', address: bsc.address, privateKey: bsc.privateKey, derivationPath: DERIVATION_PATHS.BSC },
```
4. In `types.ts`, update `BalanceChain`:
```ts
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:**
1. Add BSC RPC to `env.ts`:
```ts
bscRpcUrl: readUrlEnv('NEXT_PUBLIC_BSC_RPC_URL', 'https://bsc-dataseed.binance.org'),
```
2. Create `bsc-balances.ts` — copy `eth-balances.ts` pattern with:
- `BSC_CHAIN_ID = 56`
- `BSC_RPC_CANDIDATES`: `webEnv.bscRpcUrl`, `https://bsc-dataseed1.defibit.io`, `https://bsc-dataseed1.ninicoin.io`
- `BSC_TOKENS`: BNB native (18 dec, coinGeckoId `binancecoin`) + DOGE BEP-20 (8 dec, `0xbA2aE424d960c26247Dd6c32edC70B295c744C43`, coinGeckoId `dogecoin`)
- `fetchBscBalances(address)` — same logic as `fetchEthBalances` but with BSC provider
- All internal references use `chain: 'BSC'`
3. Register in `balances/index.ts`:
```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:**
1. Create `bsc-swap-proxy.routes.ts` — PancakeSwap V2 swap proxy (same pattern as `tron-swap-proxy.routes.ts` but 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? }
```
2. Register in `app.ts`:
```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:**
1. Update `SwapChain`:
```ts
export type SwapChain = 'ETH' | 'SOL' | 'TRX' | 'BSC';
```
2. Add BSC token configs:
```ts
export const BSC_TOKEN_ADDRESSES: Record<string, string> = {
BNB: 'native',
DOGE: '0xbA2aE424d960c26247Dd6c32edC70B295c744C43',
};
export const BSC_TOKEN_DECIMALS: Record<string, number> = {
BNB: 18,
DOGE: 8,
};
```
3. Add BSC to `SWAP_TOKEN_OPTIONS_BY_CHAIN`:
```ts
BSC: ['BNB', 'DOGE'],
```
4. Add BSC to `CHAIN_DEFAULT_TOKENS`:
```ts
BSC: { from: 'BNB', to: 'DOGE' },
```
5. Update `getSlippageBpsForChain` to handle BSC:
```ts
if (chain === 'BSC') return 50; // 0.50%
```
6. Update `getExplorerTxUrl`:
```ts
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:**
1. Create `bsc/execute.ts`:
```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 }
```
2. Update swap page `CHAINS` array:
```ts
const CHAINS: SwapChain[] = ['ETH', 'SOL', 'TRX', 'BSC'];
```
3. Update `useSwap` hook to handle BSC chain (dispatch to `executeBscSwap`).
---
## 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:**
1. In `send/constants.ts`:
- Update `SendChain`: `'ETH' | 'SOL' | 'TRX' | 'BTC' | 'BSC'`
- Add BSC config:
```ts
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`
2. In `send/execute.ts`:
- Add BSC case — same as ETH but with BSC provider:
```ts
case 'BSC':
return executeBscSend(params);
```
- `executeBscSend`: create `ethers.providers.StaticJsonRpcProvider(bscRpcUrl, 56)`, use `ethers.Wallet` for native BNB or BEP-20 transfer (identical to ETH logic).
3. 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)
4. In `qr/generate.ts`:
- Add BSC case using `ethereum:` URI scheme with `@56` chain discriminator:
```ts
case 'BSC':
return generateBscUri(address, token, amount);
```
- `generateBscUri`: `ethereum:${address}@56` for native, `ethereum:${contract}@56/transfer?address=${to}` for BEP-20
5. In `qr/parse.ts`:
- Handle `@56` chain discriminator in ethereum: URIs to distinguish BSC from ETH
---
## Task 13: Run typecheck and verify
**Steps:**
1. Run `pnpm typecheck` from monorepo root
2. Fix any TypeScript errors
3. 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)