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.
Требования
npm install @raydium-io/raydium-sdk-v2 @solana/web3.js @solana/spl-token bn.js decimal.js
Каждый пример на этой странице соответствует файлу в raydium-sdk-V2-demo/src/cpmm; ссылка на GitHub находится рядом с каждым разделом. Инициализация следует config.ts.template из репозитория демонстрации (источник):
import { Connection, Keypair, clusterApiUrl } from "@solana/web3.js";
import { Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
import fs from "node:fs";
const connection = new Connection(process.env.RPC_URL ?? clusterApiUrl("mainnet-beta"));
const owner = Keypair.fromSecretKey(
new Uint8Array(JSON.parse(fs.readFileSync(process.env.KEYPAIR!, "utf8"))),
);
const raydium = await Raydium.load({
owner,
connection,
cluster: "mainnet",
disableFeatureCheck: true,
blockhashCommitment: "finalized",
});
Экземпляр Raydium — это фасад SDK’а. Каждый пример ниже использует его. Он ленивым образом загружает списки токенов и конфигурации комиссий из api-v3.raydium.io; вы можете инициализировать его собственными данными в автономных окружениях.
Создание пула CPMM
Источник: src/cpmm/createCpmmPool.ts
import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";
import { getCpmmPdas, CREATE_CPMM_POOL_PROGRAM, CREATE_CPMM_POOL_FEE_ACC }
from "@raydium-io/raydium-sdk-v2";
const mintA = new PublicKey("So11111111111111111111111111111111111111112"); // wSOL
const mintB = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); // USDC
// 1. Выберите конфигурацию комиссии. index=0 — это уровень 0,25%.
const feeConfigs = await raydium.api.getCpmmConfigs();
const feeConfig = feeConfigs.find((c) => c.index === 0)!;
// 2. Получите метаданные мит, чтобы SDK мог обрабатывать расширения Token-2022.
const mintAInfo = await raydium.token.getTokenInfo(mintA);
const mintBInfo = await raydium.token.getTokenInfo(mintB);
// 3. Постройте транзакцию.
const { execute, extInfo } = await raydium.cpmm.createPool({
programId: CREATE_CPMM_POOL_PROGRAM,
poolFeeAccount: CREATE_CPMM_POOL_FEE_ACC,
mintA: mintAInfo,
mintB: mintBInfo,
mintAAmount: new BN(1_000_000_000), // 1 SOL (assuming 9 decimals)
mintBAmount: new BN( 160_000_000), // 160 USDC (at 160/SOL)
startTime: new BN(0), // open immediately
feeConfig,
associatedOnly: false,
ownerInfo: { useSOLBalance: true },
txVersion: TxVersion.V0,
});
const { txId } = await execute({ sendAndConfirm: true });
console.log("Pool created at", extInfo.address.poolId.toBase58());
console.log("Tx:", txId);
Несколько операций, которые SDK выполняет автоматически:
- Сортирует миты в порядок token0/token1 перед получением PDA.
- Платит единовременную
create_pool_fee в poolFeeAccount.
- Создаёт связанные токен-счета вызывающей стороны, если они отсутствуют.
- Выбирает правильную программу токенов (SPL Token или Token-2022) для каждой стороны.
После подтверждения вы можете получить состояние активного пула:
const { poolKeys, poolInfo, rpcData } = await raydium.cpmm.getPoolInfoFromRpc(
extInfo.address.poolId,
);
Источник: src/cpmm/swap.ts
import { CurveCalculator } from "@raydium-io/raydium-sdk-v2";
const poolId = new PublicKey("<POOL_ID>");
// 1. Загрузите состояние пула напрямую с RPC (не из API).
const { poolInfo, poolKeys, rpcData } = await raydium.cpmm.getPoolInfoFromRpc(poolId);
const inputMint = new PublicKey(poolInfo.mintA.address); // своп A → B
const amountIn = new BN(100_000_000); // 0.1 SOL
const slippage = 0.005; // 0.5%
// 2. Получите котировку локально. CurveCalculator SDK'а зеркалирует математику на цепи,
// включая комиссии передачи Token-2022 с обеих сторон.
const baseIn = inputMint.equals(new PublicKey(poolInfo.mintA.address));
const swapResult = CurveCalculator.swap(
amountIn,
baseIn ? rpcData.baseReserve : rpcData.quoteReserve,
baseIn ? rpcData.quoteReserve : rpcData.baseReserve,
rpcData.configInfo!.tradeFeeRate,
);
const minimumAmountOut =
swapResult.destinationAmountSwapped.muln(1 - slippage * 100).divn(100);
// 3. Постройте и отправьте.
const { execute } = await raydium.cpmm.swap({
poolInfo,
poolKeys,
inputAmount: amountIn,
swapResult,
slippage,
baseIn,
txVersion: TxVersion.V0,
});
const { txId } = await execute({ sendAndConfirm: true });
console.log("Swap tx:", txId);
Примечание: SDK всегда повторно получает состояние пула с RPC внутри getPoolInfoFromRpc. Не используйте котировку из api-v3.raydium.io для транзакции, которую вы собираетесь подписать — котировка, которая на один блок устаревшая, может привести к ошибке ExceededSlippage при выполнении.
Своп (base-output)
Источник: src/cpmm/swapBaseOut.ts
const amountOutWanted = new BN(15_000_000); // 15 USDC
const slippage = 0.005;
const baseIn = false; // B - вход, A - выход? зависит от вашего направления
const swapResult = CurveCalculator.swapBaseOutput(
amountOutWanted,
rpcData.baseReserve,
rpcData.quoteReserve,
rpcData.configInfo!.tradeFeeRate,
);
const maxAmountIn = swapResult.sourceAmountSwapped.muln(1 + slippage * 100).divn(100);
const { execute } = await raydium.cpmm.swap({
poolInfo,
poolKeys,
inputAmount: maxAmountIn,
fixedOut: true,
amountOut: amountOutWanted,
baseIn,
slippage,
txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
Внесение ликвидности
Источник: src/cpmm/deposit.ts
const lpAmount = new BN(100_000); // желаемое количество LP токенов
const slippage = 0.01;
const { execute } = await raydium.cpmm.addLiquidity({
poolInfo,
poolKeys,
lpAmount,
slippage,
baseIn: true, // цитата со стороны mintA
txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
SDK преобразует lpAmount в needed_token_0 и needed_token_1, используя текущие резервы пула, увеличивает каждое значение на 1 + slippage для аргументов инструкции maximum_* и при необходимости создаёт ATA.
Вывод ликвидности
Источник: src/cpmm/withdraw.ts
const lpAmount = new BN(100_000); // LP для сжигания
const slippage = 0.01;
const { execute } = await raydium.cpmm.withdrawLiquidity({
poolInfo,
poolKeys,
lpAmount,
slippage,
txVersion: TxVersion.V0,
});
await execute({ sendAndConfirm: true });
Сбор комиссий протокола/фонда/создателя
Источник: src/cpmm/collectCreatorFee.ts, src/cpmm/collectAllCreatorFee.ts
Эти инструкции ограничены администратором или создателем и обычно вызываются подписантом, которого контролирует мультиподпись Raydium или создатель пула. SDK предоставляет их как простые построители:
import {
makeCollectProtocolFeeInstruction,
makeCollectFundFeeInstruction,
makeCollectCreatorFeeInstruction,
} from "@raydium-io/raydium-sdk-v2";
// PDA и полномочия были установлены при создании пула; см. reference/program-addresses
// для канонических seed'ов. SDK предоставляет помощники, если вы их предпочитаете.
Автономно вы можете прочитать накопленные комиссии непосредственно из PoolState:
const pool = await raydium.cpmm.getRpcPoolInfo(poolId);
console.log("Accrued protocol fee token0:", pool.protocolFeesToken0.toString());
console.log("Accrued protocol fee token1:", pool.protocolFeesToken1.toString());
Скелет Rust CPI
Если вы хотите вызвать CPMM из собственной программы Anchor — например, хранилища, которое выполняет свопы от имени своих вкладчиков — контекст CPI выглядит так. Порядок счетов следует products/cpmm/instructions.
// Cargo.toml
// raydium-cp-swap = { git = "https://github.com/raydium-io/raydium-cp-swap" }
// anchor-spl = "0.30"
use anchor_lang::prelude::*;
use anchor_spl::token_interface::{TokenAccount, TokenInterface, Mint};
use raydium_cp_swap::cpi::accounts::Swap;
use raydium_cp_swap::cpi;
use raydium_cp_swap::program::RaydiumCpSwap;
#[derive(Accounts)]
pub struct ProxySwap<'info> {
#[account(mut)]
pub payer: Signer<'info>,
/// CHECK: validated by the CPMM program
pub authority: UncheckedAccount<'info>,
/// CHECK:
pub amm_config: UncheckedAccount<'info>,
#[account(mut)]
/// CHECK:
pub pool_state: UncheckedAccount<'info>,
#[account(mut)]
pub input_token_account: InterfaceAccount<'info, TokenAccount>,
#[account(mut)]
pub output_token_account: InterfaceAccount<'info, TokenAccount>,
#[account(mut)]
pub input_vault: InterfaceAccount<'info, TokenAccount>,
#[account(mut)]
pub output_vault: InterfaceAccount<'info, TokenAccount>,
pub input_token_program: Interface<'info, TokenInterface>,
pub output_token_program: Interface<'info, TokenInterface>,
pub input_token_mint: InterfaceAccount<'info, Mint>,
pub output_token_mint: InterfaceAccount<'info, Mint>,
#[account(mut)]
/// CHECK: ring buffer
pub observation_state: UncheckedAccount<'info>,
pub cpmm_program: Program<'info, RaydiumCpSwap>,
}
pub fn proxy_swap_base_input(
ctx: Context<ProxySwap>,
amount_in: u64,
minimum_amount_out: u64,
) -> Result<()> {
let cpi_accounts = Swap {
payer: ctx.accounts.payer.to_account_info(),
authority: ctx.accounts.authority.to_account_info(),
amm_config: ctx.accounts.amm_config.to_account_info(),
pool_state: ctx.accounts.pool_state.to_account_info(),
input_token_account: ctx.accounts.input_token_account.to_account_info(),
output_token_account: ctx.accounts.output_token_account.to_account_info(),
input_vault: ctx.accounts.input_vault.to_account_info(),
output_vault: ctx.accounts.output_vault.to_account_info(),
input_token_program: ctx.accounts.input_token_program.to_account_info(),
output_token_program: ctx.accounts.output_token_program.to_account_info(),
input_token_mint: ctx.accounts.input_token_mint.to_account_info(),
output_token_mint: ctx.accounts.output_token_mint.to_account_info(),
observation_state: ctx.accounts.observation_state.to_account_info(),
};
let cpi_ctx = CpiContext::new(
ctx.accounts.cpmm_program.to_account_info(),
cpi_accounts,
);
cpi::swap_base_input(cpi_ctx, amount_in, minimum_amount_out)
}
Если ваш CPI подписывает в качестве PDA (например, вы управляете хранилищем от имени вкладчиков), замените CpiContext::new на CpiContext::new_with_signer и передайте ваши seed’ы.
Частые ошибки
Краткий контрольный список перед открытием тикета поддержки:
- Отсортированные миты. Если ваш полученный
poolState PDA не совпадает с пулом на цепи, вы, вероятно, забыли отсортировать миты.
- Устаревшая котировка API. Никогда не передавайте значение резерва из
api-v3.raydium.io в CurveCalculator.swap. Получайте с RPC.
- Неправильная программа токенов. Хранилище мита Token-2022 владеется программой Token-2022, а не SPL Token. Всегда используйте поля
token_0_program / token_1_program пула.
- Проскальзывание недостаточно для мит с комиссией за передачу. Если одна из сторон пула является мита Token-2022 с комиссией за передачу, ваш
minimum_amount_out должен быть выражен в том, что пользователь фактически получает, а не в том, что отправляет хранилище.
NotApproved при свопе. Проверьте PoolState.status — администратор мог приостановить свопы на этом пуле. См. products/cpmm/instructions для битовой маски статуса.
Что дальше
Источники: