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

# Stable AMM コード例

> API から Stable AMM プールを識別する方法、Liquidity モジュール経由でスワップする方法（version=5 プールをネイティブに処理）、およびオフチェーン安定曲線ヘルパーの使用方法。

<Info>
  **このページは AI による自動翻訳です。すべての内容は英語版を正とします。**

  [英語版を表示 →](/products/stable/code-demos)
</Info>

<Info>
  **バージョン情報**

  * SDK: `@raydium-io/raydium-sdk-v2@0.2.64-alpha`
  * クラスタ: Solana `mainnet-beta`
  * Stable AMM プログラム ID: `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h`（[`reference/program-addresses`](/ja/reference/program-addresses) を参照）
  * 最終確認: **2026-09-09** SDK `0.2.64-alpha` ソースおよび `raydium-sdk-V2-demo` amm/trade デモに対して

  SDK の `liquidity` モジュールは Stable AMM プールをネイティブに処理します。Stable プールは `ApiV3PoolInfoStandardItem` 上で **`version: 5`**（または `pooltype: "StablePool"`）として表示されます。AMM v4（`version: 4`）定数積プールと同じ `addLiquidity` / `removeLiquidity` / スワップヘルパーが機能します。SDK は変種を検出し、正しい命令を自動的に発行します。オフチェーン安定曲線の数学は `src/raydium/liquidity/stable.ts` に実装されています。
</Info>

## セットアップ

```bash theme={null}
npm install @raydium-io/raydium-sdk-v2 @solana/web3.js @solana/spl-token
```

```ts theme={null}
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" });

// Stable プール見積もり前に必須。initLayout() はオンチェーン
// ModelDataInfo ルックアップテーブルを raydium.liquidity.stableLayout にフェッチします。
await raydium.liquidity.initLayout();
```

<Warning>
  **`initLayout()` は Stable プールでは必須です。** `liquidity.computeAmountOut` は `poolInfo.version` で分岐します。version 4 の場合は定数積公式を使用し、その他の場合は `this.stableLayout.stableModelData` を読み込んでルックアップテーブルを補間します。このキャッシュは `initLayout()` が実行されるまで空のため、`initLayout()` なしで v5 プールを見積もるとエラーではなくゴミ値が返されます。べき等で低コストです。起動時に 1 回呼び出してください。

  トランザクションビルダー（`swap`、`addLiquidity`、`removeLiquidity`）は不要です。`pooltype.includes("StablePool")` で分岐し、`AmmV5*` 命令を発行します。渡す金額の上限は既に計算されています。
</Warning>

<Warning>
  **`liquidity.computeAmountIn` は Stable プールをサポートしていません。** `computeAmountOut` と異なり、version 分岐がなく、常に定数積の逆関数を適用するため、v5 プールでは間違った `maxAmountIn` が返されます。Stable プールに対する正確な出力スワップの場合、`getDxByDyBaseIn` で自分で逆算し（下の [オフチェーン見積もりヘルパー](#オフチェーン見積もりヘルパーstabletsを参照)、結果を `fixedSide: "out"` で `swap` に渡してください。
</Warning>

## Stable プールの識別

`ApiV3PoolInfoStandardItem` 上の 2 つの同等のシグナル：

```ts theme={null}
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`）の両方は SDK 上の同じ `LiquidityModule` API を通じて流れます。内部的にモジュールは以下に分岐します：

* v4 プール用の `InstructionType.AmmV4AddLiquidity` / `AmmV4RemoveLiquidity`
* v5（Stable）プール用の `InstructionType.AmmV5AddLiquidity` / `AmmV5RemoveLiquidity`

プールの `programId`（プールキーと共に返される）は SDK にどのプログラムに CPI するかを伝えます。ハードコードする必要はありません。

## ミントペアでプールを検索

```ts theme={null}
import { PublicKey } from "@solana/web3.js";
import type { ApiV3PoolInfoStandardItem } from "@raydium-io/raydium-sdk-v2";

// 例として使用する 2 つの一般的なミント
const mintA = new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"); // USDT — reference/program-addresses を参照
const mintB = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); // USDC

// fetchPoolByMints はページ付きエンベロープを返します: { count, data, hasNextPage }
const res = await raydium.api.fetchPoolByMints({
  mint1: mintA.toBase58(),
  mint2: mintB.toBase58(),
});

const stablePool = res.data.find(
  (p) => p.version === 5 || p.pooltype.includes("StablePool"),
) as ApiV3PoolInfoStandardItem | undefined;

if (!stablePool) {
  throw new Error("このミントペアに対する Stable プールが存在しません");
}

console.log("Stable プール ID:", stablePool.id);
console.log("Stable プログラム ID:", stablePool.programId);
console.log("TVL:", stablePool.tvl);
```

ミントペアが v4（定数積）プールと v5（安定）プールの両方を持つ場合、レスポンスには両方が含まれます。フローが必要なものを選択するか、[AMM ルーティング](/ja/products/routing)プログラムに渡して最適なルートを選択させてください。

## Stable プール経由でスワップ

`LiquidityModule.swap` フローは v4 プールと同じ形状です。v5 プールオブジェクトを渡すだけです。間違いやすい 2 つの詳細があります：`computeAmountOut` はプールの **ライブリザーブ** をプール情報に接ぎ木する必要があります（API アイテムだけでは持っていません）。また、その `slippage` は `Percent` ではなく、プレーンな **数値** です：

```ts theme={null}
import BN from "bn.js";

const amountIn = new BN(1_000_000); // 1 USDT（6 デシマル）、生単位

// ライブリザーブ + ステータス。mainnet では poolKeys を
// getAmmPoolKeys(poolId) から、reserves を getRpcPoolInfo(poolId) から取得することもできます。
const rpcData  = await raydium.liquidity.getRpcPoolInfo(stablePool.id);
const poolKeys = await raydium.liquidity.getAmmPoolKeys(stablePool.id);

const out = raydium.liquidity.computeAmountOut({
  poolInfo: {
    ...stablePool,
    baseReserve:  rpcData.baseReserve,
    quoteReserve: rpcData.quoteReserve,
    status:       rpcData.status.toNumber(),
    version:      5, // 5 = Stable; 曲線分岐はこれで選択されます
  },
  amountIn,
  mintIn:  stablePool.mintA.address,
  mintOut: stablePool.mintB.address,
  slippage: 0.005, // プレーン数値: 0.005 = 0.5%（範囲 1 ~ 0.0001）
});

// amountOut / minAmountOut は生単位の BN で、TokenAmount ではありません。
console.log("予想出力:", out.amountOut.toString());
console.log("最小出力:", out.minAmountOut.toString());

// スワップトランザクションをビルド & サイン。`inputMint` は必須です。
// これなしでは SDK はプールのどちら側を売却しているかを判断できません。
const { transaction, execute } = await raydium.liquidity.swap({
  poolInfo:  stablePool,
  poolKeys,
  amountIn,
  amountOut: out.minAmountOut, // out.amountOut はスリッページ前の数値
  inputMint: stablePool.mintA.address,
  fixedSide: "in",
  txVersion: TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Stable スワップ tx:", txId);
```

SDK はプールキーからプールの `programId` を読み込み、Stable AMM プログラムに分岐します。特別な `programId` 引数は不要です。

## リクイディティの追加と削除

`addLiquidity` と `removeLiquidity` は v4 と v5 プール全体で同じように機能します：

```ts theme={null}
import { Percent, TokenAmount, toToken } from "@raydium-io/raydium-sdk-v2";
import Decimal from "decimal.js";

const inputAmount = "100"; // 100 USDT、人間単位で — computePairAmount は 10 進数文字列を取得

// このサイズの A に対して曲線が必要とする一致する B 金額を計算します。
// 注: computePairAmount のスリッページは Percent です（computeAmountOut のプレーン数値とは異なります）。
const r = raydium.liquidity.computePairAmount({
  poolInfo: stablePool,
  amount:   inputAmount,
  baseIn:   true,
  slippage: new Percent(50, 10_000), // 0.5%
});

const { execute } = await raydium.liquidity.addLiquidity({
  poolInfo: stablePool,
  poolKeys,
  amountInA: new TokenAmount(
    toToken(stablePool.mintA),
    new Decimal(inputAmount).mul(10 ** stablePool.mintA.decimals).toFixed(0),
  ),
  amountInB: new TokenAmount(
    toToken(stablePool.mintB),
    new Decimal(r.maxAnotherAmount.toExact()).mul(10 ** stablePool.mintB.decimals).toFixed(0),
  ),
  otherAmountMin: r.minAnotherAmount,
  fixedSide:      "a",
  txVersion:      TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("リクイディティ追加 tx:", txId);
```

内部的に SDK は `pooltype.includes("StablePool")` が true であるため `InstructionType.AmmV5AddLiquidity` を発行します。対応する `removeLiquidity` フローは対称です。`lpAmount` と各側で受け入れる最小金額を入力してください。

## オフチェーン見積もりヘルパー（stable.ts）

サーバー側の見積もりまたはバックテストの場合、SDK は基礎となる安定曲線の数学を公開します：

```ts theme={null}
import {
  getStablePrice,
  getDxByDyBaseIn,
  getDyByDxBaseIn,
} from "@raydium-io/raydium-sdk-v2";

// これらを使用する前に initLayout() を 1 回呼び出す必要があります
// （オンチェーン `ModelDataInfo` PDA を SDK の StableLayout キャッシュにロード）。
await raydium.liquidity.initLayout();

// initLayout() は StableLayout インスタンスを設定します。以下の 3 つのヘルパーが
// 期待するプレーンデータオブジェクトはインスタンスではなく、その `stableModelData` ゲッターです。
const modelData = raydium.liquidity.stableLayout.stableModelData;

// リザーブは人間単位のプレーン数値で渡されます（BN ではなく、生単位ではなく）。
const coinReserve = 1_200_000; // プールのコイン側リザーブ
const pcReserve   = 1_150_000; // プールの pc 側リザーブ

// プールの現在のリザーブでのスポット価格。4 番目の引数は `baseCoin` です：
// true はコイン/pc を返し、false は逆数を返します。
const price = getStablePrice(modelData, coinReserve, pcReserve, true);
console.log("スポット価格:", price);

// 見積もり: dx が与えられた場合、どのくらいの dy が出力されるか（手数料は適用されません）？
const dyOut = getDyByDxBaseIn(modelData, coinReserve, pcReserve, 1_000);

// 見積もり: dy 出力ターゲットが与えられた場合、どのくらいの dx が必要ですか？
const dxIn  = getDxByDyBaseIn(modelData, coinReserve, pcReserve, 1_000);
```

これらは純粋な関数です。RPC なし、署名なし。オンチェーン `ModelDataInfo` は `initLayout()` で 1 回フェッチされ、`raydium.liquidity.stableLayout` 内にキャッシュされ、`.stableModelData` として読み取り可能です。`initStableModelLayout()` はべき等です。`validDataCount === 0` の間のみ再フェッチするため、`initLayout()` を再度呼び出すのは無料です。現在のリザーブ（`x`、`y`）を渡すと、ヘルパーはルックアップテーブルをバイナリサーチし、周囲の 2 つの `DataElement` 行の間で線形補間することで計算します。基礎となるアルゴリズムについては [`products/stable/math`](/ja/products/stable/math) を参照してください。

## AMM ルーティング経由でのルーティング（マルチホップ / 最適価格）

会場を自分で選択したくない場合、[AMM ルーティング](/ja/products/routing)プログラムはすべての Raydium AMM（v4 / CPMM / CLMM / Stable）を検討し、最適な組み合わせを通じてルーティングします：

ルーターは単一の `swap()` ではなく 5 呼び出しのパイプラインであり、本番環境で使用可能にするキャッシングアドバイスと共に完全に記述されています。[`products/routing/code-demos`](/ja/products/routing/code-demos) を参照してください。形状は以下の通りです：

```ts theme={null}
import { Router } from "@raydium-io/raydium-sdk-v2";

const poolData = await raydium.tradeV2.fetchRoutePoolBasicInfo(); // これをキャッシュ
const routes   = raydium.tradeV2.getAllRoute({ inputMint: mintA, outputMint: mintB, ...poolData });
const ctx      = await raydium.tradeV2.fetchSwapRoutesData({ routes, inputMint: mintA, outputMint: mintB });
const quotes   = raydium.tradeV2.getAllRouteComputeAmountOut({ /* ...ctx, amount, slippage, ... */ });

const best = quotes[0]; // 最適順でソート
if (!best) throw new Error("スワップルートが見つかりません");

// best.poolInfoList エントリは `version` を持ちます。5 はパス内の Stable プールをマーク。
console.log(best.routeType, best.poolInfoList.map((p) => p.version));

const poolKeys = await raydium.tradeV2.computePoolToPoolKeys({
  pools: best.poolInfoList,
  ammRpcData:  ctx.ammPoolsRpcInfo,
  clmmRpcData: ctx.clmmPoolsRpcInfo,
});

const { execute } = await raydium.tradeV2.swap({
  routeProgram: Router,
  swapInfo:     best,
  swapPoolKeys: poolKeys,
  ownerInfo:    { associatedOnly: true, checkCreateATAOwner: true },
  txVersion:    TxVersion.V0,
});

// tradeV2.swap は複数のトランザクションを返す可能性があります。最初のものは中間 ATA を作成します。
const { txIds } = await execute({ sequentially: true });
```

<Warning>
  `raydium.tradeV2.fetchRoutes` はなく、`tradeV2.swap` は `inputMint` / `outputMint` / `slippage` を受け入れません。既に計算された `getAllRouteComputeAmountOut` からの `swapInfo` を取得します。**単一の** 既知プールの場合、このページの前半で示したようにそのプールタイプ独自のビルダー（AMM v4 と Stable の場合は `raydium.liquidity.swap`、`raydium.cpmm.swap`、`raydium.clmm.swap`）を使用してください。
</Warning>

これは本番環境のスワッパーとアグリゲーターの推奨パスです。Stable プールが存在するかどうか、または今日がより良い会場であるかどうかを手動で決定する必要はありません。

## 推奨事項

1. **エンドユーザースワップの場合**、[`tradeV2`](/ja/products/routing) ルーティングフローを優先してください。Stable を含むすべての Raydium プールタイプを処理します。
2. **プール固有の操作**（既知の Stable プール上の LP 追加/削除）の場合、`LiquidityModule` を直接使用してください。v5 プールを自動検出します。
3. **オフチェーン見積もり / 分析の場合**、`initLayout()` 後に `getStablePrice` / `getDyByDxBaseIn` / `getDxByDyBaseIn` を呼び出してください。モデルデータがキャッシュされた後、見積もりごとに RPC トラフィックはありません。
4. **生の `SwapBaseIn` 命令をハンドコードしないでください。** [2026-06-22 アップグレード](/ja/reference/changelog)は死んだ OpenBook アカウントを削除したため、新しいスワップレイアウトは **9 アカウント** を取得します（古い 18 アカウントレイアウトは後方互換性のために解析されます）。`Deposit` は現在 12 アカウント（古い 14 互換）、`Withdraw` 12（古い 21/22 互換）、`WithdrawPnl` 10 で **互換性パスなし**。SDK の事前構築ヘルパーは正しいレイアウトと順序を選択します。独自にロールするのはエラーが発生しやすいです。完全なアカウントテーブルについては [`products/stable/instructions`](/ja/products/stable/instructions) を参照してください。

## 次に進む場所

* [Math](/ja/products/stable/math) — ルックアップテーブル補間の仕組み。
* [Instructions](/ja/products/stable/instructions) — 完全な命令リファレンス。
* [AMM ルーティング](/ja/products/routing) — AMM v4、CPMM、CLMM、Stable 全体のマルチプールルーティング。

ソース：

* [`raydium-sdk-V2/src/raydium/liquidity/liquidity.ts`](https://github.com/raydium-io/raydium-sdk-V2/blob/master/src/raydium/liquidity/liquidity.ts) — モジュールエントリポイント; v4 / v5 分岐。
* [`raydium-sdk-V2/src/raydium/liquidity/stable.ts`](https://github.com/raydium-io/raydium-sdk-V2/blob/master/src/raydium/liquidity/stable.ts) — `StableLayout`、`getStablePrice`、`getDxByDyBaseIn`、`getDyByDxBaseIn`。


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