490 lines
18 KiB
Markdown
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)
|