> ## 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.

# 从 CLI 执行交换

> 即插即用的 Node 脚本，可用于 CPMM 交换报价和执行。配置四个环境变量后运行。

<Info>
  **本页内容由 AI 自动翻译，所有内容以英文版本为准。**

  [查看英文版 →](/quick-start/swap-from-cli)
</Info>

<Info>
  **这个脚本做什么。** 从 RPC 加载 CPMM 池，以 0.5% 滑点报价，构建交易，用你的密钥对签名，然后提交。全过程用约 30 行代码完成。
</Info>

## 设置

确保你已阅读[快速开始前置条件](/zh/quick-start)，并且已配置 `RPC_URL`、`KEYPAIR` 以及安装了依赖。

## 脚本

保存为 `swap.mjs`：

```ts theme={null}
// 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 池为例：

```bash theme={null}
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...
```

## 刚才发生了什么

1. **`Raydium.load`** 初始化了 SDK — 获取全局配置，设置钱包上下文。
2. **`getPoolInfoFromRpc`** 直接从 RPC 拉取实时池状态（不使用 API 缓存）。对于高价值交换，你总是希望获取最新状态。
3. **`CurveCalculator.swap`** 计算了扣除池手续费后的常数乘积输出。这与程序在链上运行的数学完全相同，因此你可以对比链下和链上的报价。
4. **`raydium.cpmm.swap`** 用 V0 格式（启用地址查询表）构建交易，并添加了明确的计算预算配置。计算预算小费有助于交易在繁忙时段落地。
5. **`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 余额后重试。

## 后续

* [`sdk-api/typescript-sdk`](/zh/sdk-api/typescript-sdk) — 完整 SDK 参考。
* [`products/cpmm/instructions`](/zh/products/cpmm/instructions) — 链上交换指令是什么样子。
* [`integration-guides/priority-fee-tuning`](/zh/integration-guides/priority-fee-tuning) — 为生产环境调整 `computeBudgetConfig` 的大小。
