Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ec040e8
feat: enhance pool storage with token addresses and fees
fengtality Oct 14, 2025
70d9548
feat: add configurable EIP-1559 gas pricing for Ethereum networks
fengtality Oct 15, 2025
1fee81b
test: fix pool routes tests for enhanced Pool interface
fengtality Oct 15, 2025
e7cd5a6
feat: migrate to Etherscan V2 API with unified API key configuration
fengtality Oct 15, 2025
1e572b4
docs: update gas configuration guide for Etherscan V2 API
fengtality Oct 15, 2025
03463a6
docs: update gas config guide to reflect new minimum gas prices
fengtality Oct 15, 2025
366e5da
docs: update Polygon config to 10 GWEI in gas guide
fengtality Oct 15, 2025
ee1fa1b
refactor: clean up CLMM open-position implementations
fengtality Oct 16, 2025
75beff7
chore: update BSC and Polygon gas config to match actual network cond…
fengtality Oct 16, 2025
435d212
refactor: extract getPool schema and fix type enum for Swagger UI
fengtality Oct 16, 2025
008bf12
chore: set default network to mainnet-beta in GetPoolRequestSchema
fengtality Oct 16, 2025
92e9151
fix: set network default to mainnet-beta and change tradingPair example
fengtality Oct 16, 2025
19e21e1
feat: enhance POST /pools to support all pool fields and allow duplic…
fengtality Oct 16, 2025
8c8393a
refactor: make baseTokenAddress and quoteTokenAddress required in POS…
fengtality Oct 16, 2025
6d3bb0c
feat: prevent duplicate pools with identical metadata
fengtality Oct 16, 2025
d0d010a
refactor: match pools by token pair only, ignore fee tier
fengtality Oct 16, 2025
54c8ffe
test: fix pool routes tests for required token address fields
fengtality Oct 16, 2025
a9aedf0
fix: remove incorrect priority fee parameter in closePosition
fengtality Oct 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,63 @@ This file provides guidance to AI coding assistants when working with code in th
- RPC provider configs: `src/templates/rpc/{provider}.yml`
- All configs validated against JSON schemas in `src/templates/namespace/`

### Pool Storage Format
Gateway stores pool configurations for each connector in `src/templates/pools/{connector}.json`. The pool storage format includes complete pool information fetched from on-chain data to ensure token ordering and fees match the actual pool state.

#### Pool Object Structure
Each pool entry contains:
```typescript
{
type: 'amm' | 'clmm', // Pool type: AMM (V2) or CLMM (V3)
network: string, // Network name (e.g., 'mainnet-beta', 'mainnet')
baseSymbol: string, // Base token symbol (e.g., 'SOL')
quoteSymbol: string, // Quote token symbol (e.g., 'USDC')
baseTokenAddress: string, // Base token contract address (authoritative)
quoteTokenAddress: string, // Quote token contract address (authoritative)
feePct: number, // Pool fee percentage (e.g., 0.25 for 0.25%)
address: string // Pool contract address
}
```

#### Adding Pools via API
Use `POST /pools` to add a new pool. The route automatically:
1. Fetches pool-info from the connector (authoritative source)
2. Extracts baseTokenAddress, quoteTokenAddress, and feePct
3. Resolves token symbols from addresses (if not provided)
4. Validates all required fields
5. Stores the enhanced pool object

Example request:
```bash
curl -X POST http://localhost:15888/pools \
-H "Content-Type: application/json" \
-d '{
"connector": "raydium",
"type": "amm",
"network": "mainnet-beta",
"address": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"
}'
```

The API will fetch pool-info and store complete pool data including token addresses and fees.

#### Pool Template Migration
To migrate existing pool templates from the old format (symbol-only) to the new format (with token addresses and fees):

```bash
# Ensure RPC endpoints are configured in conf/rpc/*.yml
npx ts-node scripts/migrate-pool-templates.ts
```

The migration script:
- Processes raydium.json, meteora.json, and uniswap.json
- Fetches pool-info for each pool address
- Extracts baseTokenAddress, quoteTokenAddress, and feePct from on-chain data
- Writes updated template files with the new format
- Reports success/failure counts for each connector

After migration, review the updated template files before committing to ensure all pools were migrated successfully.

### RPC Provider Configuration
Gateway supports optimized RPC providers for enhanced performance:
- **Infura** (Ethereum): `conf/rpc/infura.yml` - Set `rpcProvider: infura` in network configs
Expand Down
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,34 @@ Gateway uses [Swagger](https://swagger.io/) for API documentation. When running
- `DELETE /wallet/remove` - Remove wallet
- `POST /wallet/setDefault` - Set default wallet per chain

#### Pool Management Routes (`/pools/*`)
- `GET /pools` - List all configured pools for a connector
- `POST /pools` - Add a new pool (automatically fetches token addresses and fees from pool-info)
- `PUT /pools` - Update an existing pool
- `DELETE /pools` - Remove a pool

**Pool Storage Format:**
Pools are stored with complete on-chain information to ensure accurate token ordering and fees:
```json
{
"type": "amm",
"network": "mainnet-beta",
"baseSymbol": "SOL",
"quoteSymbol": "USDC",
"baseTokenAddress": "So11111111111111111111111111111111111111112",
"quoteTokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"feePct": 0.25,
"address": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"
}
```

When adding a pool via `POST /pools`, Gateway automatically:
1. Fetches pool-info from the DEX connector
2. Extracts authoritative baseTokenAddress, quoteTokenAddress, and feePct
3. Resolves token symbols from addresses
4. Validates and stores the enhanced pool object

This ensures stored pool data always matches the actual on-chain pool state.

## Installation from Source

Expand Down Expand Up @@ -390,6 +418,36 @@ Here are some ways that you can contribute to Gateway:

- For each supported chain, token lists that translate address to symbols for each chain are stored in `/conf/tokens`. Use the `/tokens` API endpoints to manage tokens - changes require a Gateway restart to take effect.

### Pool Configuration and Migration

Gateway stores pool configurations for AMM and CLMM connectors in `src/templates/pools/{connector}.json`. These pool templates include complete on-chain information (token addresses and fees) to ensure accurate trading operations.

**Pool Template Files:**
- `src/templates/pools/raydium.json` - Raydium AMM and CLMM pools
- `src/templates/pools/meteora.json` - Meteora DLMM pools
- `src/templates/pools/uniswap.json` - Uniswap V2 and V3 pools

**Migrating Pool Templates:**

If you need to migrate pool templates from an older format (without token addresses and fees) to the new format, use the migration script:

```bash
# Ensure RPC endpoints are configured in conf/rpc/*.yml
# Raydium/Meteora require Helius or standard Solana RPC
# Uniswap requires Infura or standard Ethereum RPC

npx ts-node scripts/migrate-pool-templates.ts
```

The migration script will:
1. Read existing pool templates from `src/templates/pools/`
2. Fetch pool-info for each pool address from the respective connector
3. Extract authoritative baseTokenAddress, quoteTokenAddress, and feePct
4. Write updated template files with enhanced pool data
5. Report success/failure counts for each connector

After migration, review the updated template files to ensure all pools were successfully migrated before committing changes.

### RPC Provider Configuration

Gateway supports optimized RPC providers for enhanced performance:
Expand Down
118 changes: 118 additions & 0 deletions scripts/add-bsc-tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { Contract } from '@ethersproject/contracts';
import { logger } from '../src/services/logger';
import { Ethereum } from '../src/chains/ethereum/ethereum';
import * as fs from 'fs';
import * as path from 'path';

const TOKEN_ADDRESSES = [
'0x000Ae314E2A2172a039B26378814C252734f556A', // ASTER
'0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82', // CAKE
'0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56', // BUSD
];

const NETWORK = 'bsc';
const BSC_CHAIN_ID = 56;
const TOKEN_FILE = path.join(__dirname, '../src/templates/tokens/ethereum/bsc.json');

const ERC20_ABI = [
{
constant: true,
inputs: [],
name: 'name',
outputs: [{ name: '', type: 'string' }],
type: 'function',
},
{
constant: true,
inputs: [],
name: 'symbol',
outputs: [{ name: '', type: 'string' }],
type: 'function',
},
{
constant: true,
inputs: [],
name: 'decimals',
outputs: [{ name: '', type: 'uint8' }],
type: 'function',
},
];

async function fetchTokenMetadata(address: string) {
try {
const ethereum = await Ethereum.getInstance(NETWORK);
const contract = new Contract(address, ERC20_ABI, ethereum.provider);

const [name, symbol, decimals] = await Promise.all([
contract.name(),
contract.symbol(),
contract.decimals(),
]);

return {
chainId: BSC_CHAIN_ID,
name,
symbol,
address,
decimals,
};
} catch (error: any) {
logger.error(`Error fetching token metadata for ${address}: ${error.message}`);
return null;
}
}

async function addTokens() {
logger.info('Fetching token metadata from BSC...\n');

// Load existing tokens
const existingTokens = JSON.parse(fs.readFileSync(TOKEN_FILE, 'utf8'));
const existingAddresses = new Set(existingTokens.map((t: any) => t.address.toLowerCase()));

const newTokens: any[] = [];

for (const address of TOKEN_ADDRESSES) {
logger.info(`Processing: ${address}`);

// Skip if token already exists
if (existingAddresses.has(address.toLowerCase())) {
logger.info(` ⊘ Already exists, skipping\n`);
continue;
}

const metadata = await fetchTokenMetadata(address);

if (metadata) {
logger.info(` ✓ Success`);
logger.info(` Name: ${metadata.name}`);
logger.info(` Symbol: ${metadata.symbol}`);
logger.info(` Decimals: ${metadata.decimals}\n`);
newTokens.push(metadata);
} else {
logger.error(` ✗ Failed\n`);
}
}

if (newTokens.length === 0) {
logger.info('No new tokens to add.');
return;
}

// Merge and sort by symbol
const allTokens = [...existingTokens, ...newTokens].sort((a, b) =>
a.symbol.localeCompare(b.symbol)
);

// Write updated token list
fs.writeFileSync(TOKEN_FILE, JSON.stringify(allTokens, null, 2));

logger.info('========================================');
logger.info(`Added ${newTokens.length} new tokens to bsc.json`);
logger.info(`Total tokens: ${allTokens.length}`);
logger.info('========================================');
}

addTokens().catch((error) => {
logger.error('Fatal error:', error);
process.exit(1);
});
Loading