Перейти к основному содержанию
Эта страница переведена с помощью ИИ. За эталон принимается английская версия.Открыть английскую версию →
Баннер версии.
  • SDK: @raydium-io/raydium-sdk-v2@0.2.42-alpha
  • Кластер: Solana mainnet-beta
  • ID программы Stable AMM: 5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h (см. reference/program-addresses)
  • Последняя проверка: 2026-04
Модуль liquidity SDK нативно поддерживает пулы Stable AMM. Стабильные пулы отображаются как version: 5 (или pooltype: "StablePool") на ApiV3PoolInfoStandardItem; те же вспомогательные функции addLiquidity / removeLiquidity / swap работают для них, как и для пулов AMM v4 (version: 4) с постоянным произведением — SDK определяет вариант и автоматически генерирует правильные инструкции. Математика стабильной кривой находится в src/raydium/liquidity/stable.ts.

Настройка

npm install @raydium-io/raydium-sdk-v2 @solana/web3.js @solana/spl-token
import { Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
import { Connection, Keypair, clusterApiUrl } from "@solana/web3.js";
import BN from "bn.js";
import bs58 from "bs58";

const connection = new Connection(clusterApiUrl("mainnet-beta"));
const owner = Keypair.fromSecretKey(bs58.decode(process.env.PRIVATE_KEY!));

const raydium = await Raydium.load({
  connection,
  owner,
  cluster: "mainnet",
  // Опционально: загрузите макет модели стабильной кривой, если вы намерены вызывать
  // вспомогательные функции цитирования из `liquidity/stable.ts` напрямую. Своп / добавление / удаление
  // на уровне пула делают это лениво для вас, поэтому большинство вызывающих могут пропустить этот шаг.
});

// Один раз: предварительно загрузите макет данных модели на цепи, используемый
// вспомогательными функциями стабильной кривой. Требуется только если вы вызываете getStablePrice / getDxByDyBaseIn /
// getDyByDxBaseIn напрямую. addLiquidity / removeLiquidity / swap этого не требуют.
await raydium.liquidity.initLayout();

Определение пула Stable

Два эквивалентных сигнала на ApiV3PoolInfoStandardItem:
const isStable =
  pool.version === 5 ||
  pool.pooltype.includes("StablePool"); // SDK использует эту проверку строки внутри

// Альтернативно, по ID программы:
const STABLE_AMM_PROGRAM_ID = "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h";
const isStableByProgram = pool.programId === STABLE_AMM_PROGRAM_ID;
Как AMM v4 (version: 4, постоянное произведение), так и Stable AMM (version: 5) проходят через один и тот же API LiquidityModule на SDK. Внутри модуль отправляет на:
  • InstructionType.AmmV4AddLiquidity / AmmV4RemoveLiquidity для пулов v4
  • InstructionType.AmmV5AddLiquidity / AmmV5RemoveLiquidity для пулов v5 (Stable)
programId пула (возвращаемый с ключами пула) сообщает SDK, в какую программу выполнить CPI; вам не нужно жестко кодировать его.

Поиск пула по паре монет

import { PublicKey } from "@solana/web3.js";

// Две распространённые монеты для использования в качестве примера
const mintA = new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"); // USDT
const mintB = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); // USDC

const pools = await raydium.api.fetchPoolByMintPair({
  mint1: mintA.toBase58(),
  mint2: mintB.toBase58(),
});

const stablePool = pools.find(
  (p) => p.version === 5 || p.pooltype.includes("StablePool"),
);

if (!stablePool) {
  throw new Error("Для этой пары монет не существует пула Stable");
}

console.log("ID пула Stable:", stablePool.id);
console.log("ID программы пула Stable:", stablePool.programId);
console.log("TVL:", stablePool.tvl);
Если пара монет имеет как пул v4 (постоянное произведение), так и пул v5 (stable), ответ включает оба — выберите тот, который нужен вашему потоку, или передайте их программе AMM Routing и позвольте ей выбрать лучший маршрут.

Своп через пул Stable

Поток LiquidityModule.swap имеет ту же форму, что и для пулов v4 — просто передайте ему объект пула v5:
import { Percent, TokenAmount, toToken } from "@raydium-io/raydium-sdk-v2";

const inputAmount = new TokenAmount(toToken(stablePool.mintA), 1_000_000); // 1 USDT
const slippage = new Percent(50, 10_000); // 0.5%

// Вычислите ожидаемый выход, используя вспомогательные функции стабильной кривой SDK внутри.
const { amountOut, minAmountOut } = raydium.liquidity.computeAmountOut({
  poolInfo: stablePool,
  amountIn: inputAmount,
  mintIn:  stablePool.mintA.address,
  mintOut: stablePool.mintB.address,
  slippage,
});

console.log("Ожидаемый выход:", amountOut.toSignificant());
console.log("Минимальный выход:", minAmountOut.toSignificant());

// Создайте и подпишите транзакцию своп.
const { transaction, execute } = await raydium.liquidity.swap({
  poolInfo: stablePool,
  amountIn:    inputAmount.raw,
  amountOut:   minAmountOut.raw,
  fixedSide:   "in",
  txVersion:   TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Транзакция Stable swap:", txId);
SDK читает programId пула из ключей пула и отправляет в программу Stable AMM. Специальный аргумент programId не требуется.

Добавление и удаление ликвидности

addLiquidity и removeLiquidity работают одинаково для пулов v4 и v5:
import { Percent, TokenAmount, toToken } from "@raydium-io/raydium-sdk-v2";

const amountInA = new TokenAmount(toToken(stablePool.mintA), 100_000_000); // 100 USDT
const slippage  = new Percent(50, 10_000); // 0.5%

// Вычислите соответствующую сумму B, которую требует кривая для этого размера A.
const { anotherAmount, minAnotherAmount } = raydium.liquidity.computePairAmount({
  poolInfo: stablePool,
  amount:   amountInA.toSignificant(),
  baseIn:   true,
  slippage,
});

const { execute } = await raydium.liquidity.addLiquidity({
  poolInfo: stablePool,
  amountInA,
  amountInB:      anotherAmount,
  otherAmountMin: minAnotherAmount,
  fixedSide:      "a",
  txVersion:      TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Транзакция добавления ликвидности:", txId);
Внутри SDK генерирует InstructionType.AmmV5AddLiquidity, потому что pooltype.includes("StablePool") истинно. Соответствующий поток removeLiquidity симметричен — передайте lpAmount и минимальные суммы, которые вы примете с каждой стороны.

Вспомогательные функции для цитирования вне цепи (stable.ts)

Для цитирования на стороне сервера или бэктестирования SDK предоставляет базовую математику стабильной кривой:
import {
  getStablePrice,
  getDxByDyBaseIn,
  getDyByDxBaseIn,
} from "@raydium-io/raydium-sdk-v2";

// Вы должны вызвать initLayout() один раз перед использованием этих функций (загружает
// PDA `ModelDataInfo` на цепи в кэш StableLayout SDK).
await raydium.liquidity.initLayout();

const modelData = raydium.liquidity.stableLayout;

// Спотовая цена при текущих резервах пула.
const price = getStablePrice(modelData, /* x */, /* y */, /* withFee */);
console.log("Спотовая цена:", price);

// Цитирование: при заданном dx входа, сколько dy выхода (без применения комиссии)?
const dyOut = getDyByDxBaseIn(modelData, /* x */, /* y */, /* dx */);

// Цитирование: при заданной цели dy выхода, сколько dx входа требуется?
const dxIn  = getDxByDyBaseIn(modelData, /* x */, /* y */, /* dy */);
Это чистые функции — без RPC, без подписания. ModelDataInfo на цепи загружается один раз initLayout() и кэшируется в raydium.liquidity.stableLayout. Передайте текущие резервы (x, y) и вспомогательные функции вычисляют путём двоичного поиска в таблице поиска и линейной интерполяции между двумя окружающими строками DataElement. См. products/stable/math для базового алгоритма.

Маршрутизация через AMM Routing (многоскачковые / лучшая цена)

Если вы не хотите выбирать площадку самостоятельно, программа AMM Routing рассмотрит каждый Raydium AMM (v4 / CPMM / CLMM / Stable) и маршрутизирует через любую комбинацию, которая лучше всего:
const route = await raydium.tradeV2.fetchRoutes({
  inputMint:  mintA,
  outputMint: mintB,
  amount:     new BN(1_000_000),
  slippage,
});

// route.routes[0].poolType сообщает вам, какие программы использует лучший маршрут;
// "Stable" появляется здесь всякий раз, когда пул Stable является частью оптимального пути.
console.log(route.routes[0]);

const { execute } = await raydium.tradeV2.swap({
  inputMint:    mintA,
  outputMint:   mintB,
  inputAmount:  new BN(1_000_000),
  swapResult:   route.routes[0],
  slippage,
  txVersion:    TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
Это рекомендуемый путь для производственных свопов и агрегаторов — вам никогда не нужно вручную решать, существует ли пул Stable или является ли он лучшей площадкой сегодня.

Рекомендации

  1. Для свопов конечных пользователей предпочитайте поток маршрутизации tradeV2. Он обрабатывает каждый тип пула Raydium, включая Stable.
  2. Для операций, специфичных для пула (добавление / удаление LP в известном пуле Stable), используйте LiquidityModule напрямую — он автоматически определяет пулы v5.
  3. Для цитирования вне цепи / аналитики вызывайте getStablePrice / getDyByDxBaseIn / getDxByDyBaseIn после initLayout(). Нет трафика RPC за цитирование после кэширования данных модели.
  4. Не кодируйте вручную необработанные инструкции SwapBaseIn. Обновление от 2026-06-22 удалило мёртвые учётные записи OpenBook, поэтому новый макет своп принимает 9 учётных записей (старый макет из 18 учётных записей всё ещё парсится для обратной совместимости). Deposit теперь 12 учётных записей (старые 14 совместимы), Withdraw 12 (старые 21/22 совместимы), и WithdrawPnl 10 без пути совместимости. Предварительно созданные вспомогательные функции SDK выбирают правильный макет и порядок для вас; самостоятельное написание подвержено ошибкам. См. products/stable/instructions для полных таблиц учётных записей.

Что дальше

  • Math — как работает интерполяция таблицы поиска.
  • Instructions — полный справочник инструкций.
  • AMM Routing — маршрутизация между несколькими пулами через AMM v4, CPMM, CLMM, Stable.
Источники: