Install the CLI and interact with pools from your terminal:
# Install CLI curl -sSf https://aex402.com/install.sh | bash # Create a pool (StableSwap, amp=1000, fee=30 bps) aex --network mainnet pool create <token0_mint> <token1_mint> --amp 1000 --fee 30 # Add liquidity (amounts in smallest units) aex pool add-liq <pool_address> <amount0> <amount1> # Swap token0 -> token1 aex pool swap <pool_address> 0to1 <amount> <min_out> # Get a quote (read-only, no TX) aex pool quote <pool_address> 0to1 <amount>
Pool PDAs are derived from: ["pool", token0_mint(32), bump(1)]
No Anchor IDL -- instructions are built manually with 8-byte discriminators:
import { Connection, PublicKey, TransactionInstruction } from "@solana/web3.js"; // Program const PROGRAM_ID = new PublicKey("3AMM53MsJZy2Jvf7PeHHga3bsGjWV4TSaYz29WUtcdje"); // Fetch pool state const POOL_SIZE = 1024; const info = await connection.getAccountInfo(poolAddress); const data = info.data; const balance0 = data.readBigUInt64LE(256); const balance1 = data.readBigUInt64LE(264); const lpSupply = data.readBigUInt64LE(272); const amp = data.readBigUInt64LE(200); const feeBps = data.readBigUInt64LE(240); // Build a swap instruction (token0 -> token1) function makeSwapT0T1(pool, vault0, vault1, lpMint, userT0, userT1, amount, minOut) { const disc = Buffer.alloc(8); disc.writeBigUInt64LE(0x642af2b7e0f14e2an); const data = Buffer.alloc(24); disc.copy(data); data.writeBigUInt64LE(amount, 8); data.writeBigUInt64LE(minOut, 16); return new TransactionInstruction({ keys: [ { pubkey: pool, isSigner: false, isWritable: true }, { pubkey: vault0, isSigner: false, isWritable: true }, { pubkey: vault1, isSigner: false, isWritable: true }, { pubkey: lpMint, isSigner: false, isWritable: false }, { pubkey: userT0, isSigner: false, isWritable: true }, { pubkey: userT1, isSigner: false, isWritable: true }, { pubkey: wallet, isSigner: true, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, ], programId: PROGRAM_ID, data }); }
Every instruction begins with an 8-byte little-endian discriminator, followed by instruction-specific data:
| Instruction | Discriminator | Data Layout |
|---|---|---|
| SwapT0T1 | 0x642af2b7e0f14e2a | disc(8) + amount(8) + min_out(8) |
| SwapT1T0 | 0x3a0e131bac75c4c8 | disc(8) + amount(8) + min_out(8) |
| AddLiquidity | 0xa2e7c4f8b3d1e5a9 | disc(8) + amount0(8) + amount1(8) + min_lp(8) |
| RemoveLiquidity | 0x2e54bc2c75c9f902 | disc(8) + lp_amount(8) + min0(8) + min1(8) |
| CreatePool | 0xf2b9e4d1c8a7e3f9 | disc(8) + amp(8) + fee_bps(2) |
| Instruction | Discriminator | Data Layout |
|---|---|---|
| VpCreate | 0x7670637265617465 | disc(8) + target_sol(8) + creator_pct(1) |
| VpBuy | 0x7670627579000000 | disc(8) + sol_amount(8) + min_tokens(8) |
| VpSell | 0x767073656c6c0000 | disc(8) + token_amount(8) + min_sol(8) |
| VpGrad | 0x7670677261640000 | disc(8) -- triggers graduation to AMM pool |
| Instruction | Discriminator | Data Layout |
|---|---|---|
| CreateFarm | 0x6d7b0c8e2f1a3d5c | disc(8) + reward_rate(8) + duration(8) |
| StakeLP | 0xf8d4e1a7c3b9e2f7 | disc(8) + amount(8) |
| UnstakeLP | 0x4166bf654e34f8bc | disc(8) + amount(8) |
| ClaimFarm | 0x075762b7e0d6ec9b | disc(8) |
// Build an 8-byte LE discriminator buffer function makeDiscriminator(disc) { const buf = Buffer.alloc(8); buf.writeBigUInt64LE(disc); return buf; } // Example: makeDiscriminator(0x642af2b7e0f14e2an)
Pool accounts are 1024 bytes. Key fields at fixed offsets (all integers are little-endian):
| Offset | Size | Field | Type |
|---|---|---|---|
| 0 | 8 | Discriminator | "POOLSWAP" (ASCII) |
| 8 | 32 | Authority | Pubkey |
| 40 | 32 | Token0 Mint | Pubkey |
| 72 | 32 | Token1 Mint | Pubkey |
| 104 | 32 | Vault0 | Pubkey |
| 136 | 32 | Vault1 | Pubkey |
| 168 | 32 | LP Mint | Pubkey |
| 200 | 8 | Amp | u64 |
| 240 | 8 | Fee (bps) | u64 |
| 256 | 8 | Balance0 | u64 |
| 264 | 8 | Balance1 | u64 |
| 272 | 8 | LP Supply | u64 |
| 296 | 1 | Paused | u8 (0=active) |
| 312 | 8 | Trade Count | u64 |
N-token pools ("NPOOLSWA" discriminator) are 2048 bytes and support 2-8 tokens. See Program Reference for the full struct layout.
The RPC proxy at rpc.aex402.com provides Solana JSON-RPC plus aeX402-specific endpoints:
| Method | Endpoint | Description |
|---|---|---|
| POST | / | Solana JSON-RPC proxy (all standard methods) |
| GET | /health | Backend status and connected RPC nodes |
| GET | /tokens | Jupiter token list (cached, refreshed hourly) |
| GET | /v1/replay | Market maker swap history (last 1000 records) |
| POST | /v1/backtest | Strategy backtesting against replay data |
# Example: proxy a getAccountInfo call curl -s https://rpc.aex402.com/ \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["<pool_address>",{"encoding":"base64"}]}' # Example: fetch swap history curl -s https://rpc.aex402.com/v1/replay | jq '.records | length'
Premium API access uses the sola2a credit ledger with x402 payment protocol:
# Check supported payment methods curl -s https://sola2a.com/supported # Top up credits (via CLI) aex topup <amount_sol> # Check wallet credit balance curl -s https://sola2a.com/credits/<wallet_address>
Credits are consumed per-request. Free tier includes basic RPC proxy. Paid endpoints (backtest, AI) require a credit balance.