> ## 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에서 스왑하기

> CPMM 스왑을 견적하고 실행하는 Node 스크립트입니다. 4개의 환경 변수를 설정하고 실행하세요.

<Info>
  **이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.**

  [영문판 보기 →](/quick-start/swap-from-cli)
</Info>

<Info>
  **이 스크립트의 역할.** RPC에서 CPMM 풀을 로드하고, 0.5% 슬리피지로 스왑을 견적하며, 트랜잭션을 구성하고, 키페어로 서명한 후 제출합니다. 약 30줄의 코드로 처음부터 끝까지 완료됩니다.
</Info>

## 설정

[빠른 시작 사전 요구사항](/ko/quick-start)을 읽었는지 확인하고 `RPC_URL`, `KEYPAIR`가 있으며 의존성이 설치되어 있는지 확인하세요.

## 스크립트

`swap.mjs`로 저장하세요:

```ts swap.mjs icon="js" theme={null}
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { Raydium, TxVersion, CurveCalculator, FeeOn } 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 ────────────────────────────────────────────────────
// getPoolInfoFromRpc takes the base58 string directly, not a PublicKey.
const { poolInfo, poolKeys, rpcData } =
  await raydium.cpmm.getPoolInfoFromRpc(POOL_ID);

const baseIn = poolInfo.mintA.address === INPUT_MINT;

// ── Quote ────────────────────────────────────────────────────────
const inputAmount = new BN(AMOUNT_RAW);
const swapResult  = CurveCalculator.swapBaseInput(
  inputAmount,
  baseIn ? rpcData.baseReserve : rpcData.quoteReserve,
  baseIn ? rpcData.quoteReserve : rpcData.baseReserve,
  rpcData.configInfo.tradeFeeRate,
  rpcData.configInfo.creatorFeeRate,
  rpcData.configInfo.protocolFeeRate,
  rpcData.configInfo.fundFeeRate,
  rpcData.feeOn === FeeOn.BothToken || rpcData.feeOn === FeeOn.OnlyTokenB,
);

console.log(`Quote: ${inputAmount.toString()} -> ${swapResult.outputAmount.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 icon="terminal" theme={null}
export POOL_ID="<CPMM 풀 ID를 붙여넣으세요 — Raydium UI의 Pools 탭에서 찾을 수 있습니다>"
export INPUT_MINT="So11111111111111111111111111111111111111112"
export AMOUNT_RAW="10000000"   # 0.01 SOL

node swap.mjs
```

예상 출력:

```text theme={null}
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`이거나 잘못된 클러스터를 가리키고 있습니다 (메인넷 풀 ID를 devnet RPC에 대해 사용하는 등).
* **`Insufficient funds for transaction`** — 지갑에 스왑 입력 + 수수료 + ATA 렌트를 위한 충분한 SOL이 없습니다.
* **`Slippage tolerance exceeded`** — 견적과 실행 사이에 풀의 가격이 변경되었습니다. 다시 실행하거나, `slippage` 매개변수를 높이거나, SDK의 `computeAmountOut`을 사용하세요 (항상 리저브를 다시 가져옵니다).
* **`Token account not initialized`** — 출력 토큰의 ATA가 존재하지 않았고 암시적 생성 명령어가 도착했지만 어떤 이유로 실패했습니다. 지갑의 SOL 잔액을 확인하고 다시 시도하세요.

## 다음 단계

* [`sdk-api/typescript-sdk`](/ko/sdk-api/typescript-sdk) — 전체 SDK 참조.
* [`products/cpmm/instructions`](/ko/products/cpmm/instructions) — 온체인 스왑 명령어의 모습.
* [`integration-guides/priority-fee-tuning`](/ko/integration-guides/priority-fee-tuning) — 프로덕션을 위한 `computeBudgetConfig` 크기 조정.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.