Documentation Index
Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
Use this file to discover all available pages before exploring further.
这个脚本做什么。 从 RPC 加载 CPMM 池,以 0.5% 滑点报价,构建交易,用你的密钥对签名,然后提交。全过程用约 30 行代码完成。
确保你已阅读快速开始前置条件,并且已配置 RPC_URL、KEYPAIR 以及安装了依赖。
保存为 swap.mjs:
// swap.mjs
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { Raydium, TxVersion, CurveCalculator } from "@raydium-io/raydium-sdk-v2";
import BN from "bn.js";
import fs from "node:fs";
// ── Config from env ──────────────────────────────────────────────
const RPC_URL = process.env.RPC_URL ?? "https://api.mainnet-beta.solana.com";
const KEYPAIR = process.env.KEYPAIR ?? `${process.env.HOME}/.config/solana/id.json`;
const POOL_ID = process.env.POOL_ID; // required, base58
const INPUT_MINT = process.env.INPUT_MINT; // required, base58
const AMOUNT_RAW = process.env.AMOUNT_RAW; // required, integer in raw units (e.g. 1_000_000_000 for 1 SOL)
if (!POOL_ID || !INPUT_MINT || !AMOUNT_RAW) {
console.error("Set POOL_ID, INPUT_MINT, AMOUNT_RAW env vars.");
process.exit(1);
}
// ── Setup ────────────────────────────────────────────────────────
const connection = new Connection(RPC_URL, "confirmed");
const owner = Keypair.fromSecretKey(
new Uint8Array(JSON.parse(fs.readFileSync(KEYPAIR, "utf8"))),
);
const raydium = await Raydium.load({
owner,
connection,
cluster: "mainnet",
disableFeatureCheck: true,
blockhashCommitment: "finalized",
});
// ── Load pool ────────────────────────────────────────────────────
const { poolInfo, poolKeys, rpcData } =
await raydium.cpmm.getPoolInfoFromRpc(new PublicKey(POOL_ID));
const baseIn = poolInfo.mintA.address === INPUT_MINT;
// ── Quote ────────────────────────────────────────────────────────
const inputAmount = new BN(AMOUNT_RAW);
const swapResult = CurveCalculator.swap(
inputAmount,
baseIn ? rpcData.baseReserve : rpcData.quoteReserve,
baseIn ? rpcData.quoteReserve : rpcData.baseReserve,
rpcData.configInfo.tradeFeeRate,
);
console.log(`Quote: ${inputAmount.toString()} -> ${swapResult.destinationAmountSwapped.toString()}`);
console.log(`Fee: ${swapResult.tradeFee.toString()}`);
// ── Build and execute ────────────────────────────────────────────
const { execute } = await raydium.cpmm.swap({
poolInfo,
poolKeys,
inputAmount,
swapResult,
slippage: 0.005, // 0.5%
baseIn,
txVersion: TxVersion.V0,
computeBudgetConfig: {
units: 250_000,
microLamports: 50_000,
},
});
const { txId } = await execute({ sendAndConfirm: true });
console.log(`Swap landed: https://solscan.io/tx/${txId}`);
运行它
选择任何你有流动性的 CPMM 池。以标准的 SOL/USDC CPMM 池为例:
export POOL_ID="<粘贴一个 CPMM 池 ID — 在 Raydium UI 的 Pools 标签中找一个>"
export INPUT_MINT="So11111111111111111111111111111111111111112"
export AMOUNT_RAW="10000000" # 0.01 SOL
node swap.mjs
预期输出:
Quote: 10000000 -> 1640000
Fee: 25000
Swap landed: https://solscan.io/tx/4Z9...
刚才发生了什么
Raydium.load 初始化了 SDK — 获取全局配置,设置钱包上下文。
getPoolInfoFromRpc 直接从 RPC 拉取实时池状态(不使用 API 缓存)。对于高价值交换,你总是希望获取最新状态。
CurveCalculator.swap 计算了扣除池手续费后的常数乘积输出。这与程序在链上运行的数学完全相同,因此你可以对比链下和链上的报价。
raydium.cpmm.swap 用 V0 格式(启用地址查询表)构建交易,并添加了明确的计算预算配置。计算预算小费有助于交易在繁忙时段落地。
execute({ sendAndConfirm: true }) 签名、发送并等待确认。
常见错误
Pool not found — POOL_ID 错误,或指向了错误的集群(将 mainnet 池 ID 用于 devnet RPC,等等)。
Insufficient funds for transaction — 钱包中 SOL 不足,无法支付交换输入 + 手续费 + ATA 租金。
Slippage tolerance exceeded — 池价格在报价和执行之间变动。重新运行;或提高 slippage 参数;或使用 SDK 的 computeAmountOut,它总是重新获取准备金。
Token account not initialized — 输出代币的 ATA 不存在,隐式创建指令落地但因某种原因失败;检查钱包的 SOL 余额后重试。