> ## 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 プールをネイティブに処理）、およびオフチェーン stable-curve ヘルパーを使用する方法。

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

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

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

  * SDK: `@raydium-io/raydium-sdk-v2@0.2.42-alpha`
  * クラスタ: Solana `mainnet-beta`
  * Stable AMM プログラム ID: `5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h`（[`reference/program-addresses`](/ja/reference/program-addresses) を参照）
  * 最終確認: 2026-04

  SDK の `liquidity` モジュールは Stable AMM プールをネイティブに処理します。Stable プールは `ApiV3PoolInfoStandardItem` 上で **`version: 5`**（または `pooltype: "StablePool"`）として表示されます。同じ `addLiquidity` / `removeLiquidity` / スワップヘルパーが AMM v4（`version: 4`）定数積プールと同じように機能します。SDK は変種を検出し、正しい命令を自動的に発行します。オフチェーン stable-curve 数学は `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",
  // オプション: `liquidity/stable.ts` から直接クォートヘルパーを呼び出す場合は、
  // stable curve モデルレイアウトを読み込みます。プール レベルのスワップ / 追加 / 削除
  // はこれを遅延実行するため、ほとんどの呼び出し元はこのステップをスキップできます。
});

// 1 回限り: オフチェーン stable-curve ヘルパーで使用されるオンチェーン
// モデルデータレイアウトをプリフェッチします。getStablePrice / getDxByDyBaseIn /
// getDyByDxBaseIn を直接呼び出す場合にのみ必要です。addLiquidity / removeLiquidity / swap は不要です。
await raydium.liquidity.initLayout();
```

## 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";

// 例として使用する 2 つの一般的なミント
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("Stable プール ID:", stablePool.id);
console.log("Stable プール programId:", stablePool.programId);
console.log("TVL:", stablePool.tvl);
```

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

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

`LiquidityModule.swap` フローは v4 プールと同じ形状です。v5 プールオブジェクトを渡すだけです:

```ts theme={null}
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 の stable-curve ヘルパーを内部的に使用して予想出力を計算します。
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 スワップ tx:", txId);
```

SDK はプールキーからプールの `programId` を読み取り、Stable AMM プログラムにディスパッチします。特別な `programId` 引数は不要です。

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

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

```ts theme={null}
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%

// このサイズの A に対してカーブが必要とする一致する B 量を計算します。
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("リクイディティ追加 tx:", txId);
```

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

## オフチェーンクォートヘルパー（stable.ts）

サーバー側のクォートまたはバックテストの場合、SDK は基礎となる stable-curve 数学を公開します:

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

// これらを使用する前に initLayout() を 1 回呼び出す必要があります
// （オンチェーン `ModelDataInfo` PDA を SDK の StableLayout キャッシュに読み込みます）。
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()` によって 1 回フェッチされ、`raydium.liquidity.stableLayout` にキャッシュされます。現在のリザーブ（`x`、`y`）を渡すと、ヘルパーはルックアップテーブルをバイナリサーチし、周囲の 2 つの `DataElement` 行の間で線形補間することで計算します。基礎となるアルゴリズムについては [`products/stable/math`](/ja/products/stable/math) を参照してください。

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

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

```ts theme={null}
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`](/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) を参照してください。

## 次のステップ

* [数学](/ja/products/stable/math) — ルックアップテーブル補間がどのように機能するか。
* [命令](/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`。
