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

# AMM v4 コード例

> 既存の AMM v4 プールに対するスワップとリクイディティ提供の TypeScript サンプル。新しいプール作成はスコープ外です — CPMM を使用してください。

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

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

<Info>
  **バージョン情報。** すべてのサンプルは `@raydium-io/raydium-sdk-v2@0.2.42-alpha` を対象とし、Solana mainnet-beta に対して検証済み（2026年4月）。プログラム ID：`675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`（[`reference/program-addresses`](/ja/reference/program-addresses) を参照）。
</Info>

<Info>
  **新しいプール作成はここでは説明していません。** Raydium UI は AMM v4 プール作成をサポートしなくなりました — 新しいペアはデフォルトで [CPMM](/ja/products/cpmm/code-demos) になります。AMM v4 プログラム自体はオンチェーンで `Initialize2` を受け付けますが、推奨されるパスではありません。以下のサンプルはすべてのインテグレータが必要とするライブプール操作（スワップ、デポジット、ウィズドロー）をカバーしています。
</Info>

## セットアップ

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

## ID でプールを取得

```ts theme={null}
import { PublicKey } from "@solana/web3.js";

const poolId = new PublicKey("<AMM_V4_POOL_ID>");

// SDK 正規化済みプールオブジェクトを取得します。AMM v4 の場合、
// これはインストラクション ビルダーが必要とする OpenBook アカウントを含みます。
const data = await raydium.liquidity.getPoolInfoFromRpc({ poolId });
const { poolInfo, poolKeys, poolRpcData } = data;

console.log("Pair:", poolInfo.mintA.symbol, "/", poolInfo.mintB.symbol);
console.log("Version:", poolInfo.version);       // 4 for AMM v4
console.log("Market:", poolKeys.marketId.toBase58());
```

`poolKeys` はインストラクション ビルダーが消費する構造体です。プログラムが期待する順序で、すべての AMM v4 および OpenBook アカウントを含みます。

## スワップ（ベースイン）

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

const amountIn = new BN(1_000_000);            // 1 USDC (6-decimal quote)
const inputMint = new PublicKey(poolInfo.mintB.address);  // USDC
const slippage  = 0.005;

const computed = raydium.liquidity.computeAmountOut({
  poolInfo,
  amountIn,
  mintIn: inputMint,
  mintOut: new PublicKey(poolInfo.mintA.address),
  slippage,
});

const { execute } = await raydium.liquidity.swap({
  poolInfo,
  poolKeys,
  amountIn,
  amountOut: computed.minAmountOut,
  fixedSide: "in",
  inputMint,
  txVersion: TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Swap tx:", txId);
```

SDK はすべての OpenBook アカウントを自動的に追加します。手動で置き換えないでください — プログラムはすべてのスロットを検証します。

## スワップ（ベースアウト）

```ts theme={null}
const amountOut = new BN(1_000_000_000);       // 1 SOL (9-decimal base)
const slippage  = 0.005;

const computed = raydium.liquidity.computeAmountIn({
  poolInfo,
  amountOut,
  mintOut: new PublicKey(poolInfo.mintA.address),
  mintIn: new PublicKey(poolInfo.mintB.address),
  slippage,
});

const { execute } = await raydium.liquidity.swap({
  poolInfo,
  poolKeys,
  amountIn: computed.maxAmountIn,
  amountOut,
  fixedSide: "out",
  inputMint: new PublicKey(poolInfo.mintB.address),
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
```

## リクイディティを追加

```ts theme={null}
const amountA = new BN(100_000_000);           // 0.1 SOL

const { anotherAmount, maxAnotherAmount } = raydium.liquidity.computePairAmount({
  poolInfo,
  amount: amountA,
  baseIn: true,
  slippage: 0.01,
});

const { execute } = await raydium.liquidity.addLiquidity({
  poolInfo,
  poolKeys,
  amountInA: amountA,
  amountInB: maxAnotherAmount,
  fixedSide: "a",
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
```

`fixedSide: "a"` は、正確な `amountInA` を指定し、`amountInB` は最大で `maxAnotherAmount` であることを SDK に指示します。プールのオンブック リクイディティはプロラタ計算前に決済されるため、デポジット比率は最新の準備金と一致します。

## リクイディティを削除

```ts theme={null}
const lpAmount = new BN(50_000);               // バーンする LP

const { execute } = await raydium.liquidity.removeLiquidity({
  poolInfo,
  poolKeys,
  lpAmount,
  baseAmountMin: new BN(0),
  quoteAmountMin: new BN(0),
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
```

スリッページ最小値は、プリクォートと着地時間の間にプールの状態が変わるのを防ぎます。

## コンピュートユニット／プライオリティフィーの調整

AMM v4 スワップは、すべてのインストラクションが完全な OpenBook 状態を検証するため、コンピュート量が多くなります。一般的なスワップは、経由で決済する必要があるオープンオーダーの数に応じて、180k～250k CU を使用します。常にコンピュートユニット制限を渡してください：

```ts theme={null}
import { ComputeBudgetProgram } from "@solana/web3.js";

const { execute, innerTransactions } = await raydium.liquidity.swap({
  /* ...params... */
  computeBudgetConfig: {
    units: 400_000,
    microLamports: 50_000,       // priority fee
  },
});
```

`computeBudgetConfig` を省略した場合、SDK は引き続き独自のデフォルトを使用する可能性があります。確認するには `innerTransactions` を検査してください。[`integration-guides/priority-fee-tuning`](/ja/integration-guides/priority-fee-tuning) を参照してください。

## 直接 Rust CPI

独自の Anchor プログラムから AMM v4 に CPI する必要がある場合、`SwapBaseIn` のアカウント リストを逐語的にモデル化する必要があります。最小限のスケッチ：

```rust theme={null}
use anchor_lang::prelude::*;
use anchor_lang::solana_program::program::invoke_signed;
use anchor_lang::solana_program::instruction::Instruction;

const AMM_V4_PROGRAM_ID: Pubkey = pubkey!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8");

#[derive(Accounts)]
pub struct ProxyAmmV4Swap<'info> {
    /// CHECK:
    pub token_program: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm:          UncheckedAccount<'info>,
    /// CHECK:
    pub amm_authority: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm_open_orders: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub amm_target_orders: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub pool_coin_token_account: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub pool_pc_token_account: UncheckedAccount<'info>,
    /// CHECK:
    pub market_program: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_bids: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_asks: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_event_queue: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_coin_vault: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub market_pc_vault: UncheckedAccount<'info>,
    /// CHECK:
    pub market_vault_signer: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub user_source: UncheckedAccount<'info>,
    #[account(mut)] /// CHECK:
    pub user_dest: UncheckedAccount<'info>,
    pub user_owner: Signer<'info>,
}

pub fn proxy_swap(
    ctx: Context<ProxyAmmV4Swap>,
    amount_in: u64,
    minimum_amount_out: u64,
) -> Result<()> {
    // Instruction discriminator for SwapBaseIn is 9 on AMM v4.
    let mut data = vec![9u8];
    data.extend_from_slice(&amount_in.to_le_bytes());
    data.extend_from_slice(&minimum_amount_out.to_le_bytes());

    let ix = Instruction {
        program_id: AMM_V4_PROGRAM_ID,
        accounts: vec![
            AccountMeta::new_readonly(ctx.accounts.token_program.key(), false),
            AccountMeta::new(ctx.accounts.amm.key(), false),
            AccountMeta::new_readonly(ctx.accounts.amm_authority.key(), false),
            AccountMeta::new(ctx.accounts.amm_open_orders.key(), false),
            AccountMeta::new(ctx.accounts.amm_target_orders.key(), false),
            AccountMeta::new(ctx.accounts.pool_coin_token_account.key(), false),
            AccountMeta::new(ctx.accounts.pool_pc_token_account.key(), false),
            AccountMeta::new_readonly(ctx.accounts.market_program.key(), false),
            AccountMeta::new(ctx.accounts.market.key(), false),
            AccountMeta::new(ctx.accounts.market_bids.key(), false),
            AccountMeta::new(ctx.accounts.market_asks.key(), false),
            AccountMeta::new(ctx.accounts.market_event_queue.key(), false),
            AccountMeta::new(ctx.accounts.market_coin_vault.key(), false),
            AccountMeta::new(ctx.accounts.market_pc_vault.key(), false),
            AccountMeta::new_readonly(ctx.accounts.market_vault_signer.key(), false),
            AccountMeta::new(ctx.accounts.user_source.key(), false),
            AccountMeta::new(ctx.accounts.user_dest.key(), false),
            AccountMeta::new_readonly(ctx.accounts.user_owner.key(), true),
        ],
        data,
    };
    invoke_signed(&ix, &ctx.accounts.to_account_infos(), &[])?;
    Ok(())
}
```

AMM v4 には CPI 用の Anchor クレートはありません。上記のスケッチは手動で構築された `Instruction` を使用しています。

## よくある落とし穴

* **OpenBook アカウントの欠落。** すべての 8 つの OpenBook サイド アカウントはすべてのスワップ、デポジット、ウィズドローで必須です。SDK はこれを処理しますが、手動構築されたインストラクションではしばしば処理されません。
* **生のボルト残高の読み取り。** オンブック エスクロー済み額またはリアルタイムの PnL を反映しません。SDK のクォートまたは `api-v3.raydium.io/pools/info/ids` を使用してください。
* **OpenBook イベント キューがいっぱい。** プールのマーケットのイベント キューをクランクする必要がある場合、プールは `SerumOrderError` でスワップを失敗させる可能性があります。クランクはパーミッションレス（マーケットの OpenBook アカウント上の `MonitorStep`）です。
* **Token-2022 ミント。** サポートされていません。AMM v4 プールは Token-2022 ミントに対して作成できません。すべての Token-2022 ペアは CPMM または CLMM にあるべきです。

## 次に進むこと

* [`products/amm-v4/instructions`](/ja/products/amm-v4/instructions) — これらのサンプルの背後にあるインストラクション レベルのサーフェス。
* [`user-flows/migrate-amm-v4-to-cpmm`](/ja/user-flows/migrate-amm-v4-to-cpmm) — マイグレーションを検討している LP の場合。
* [`integration-guides/priority-fee-tuning`](/ja/integration-guides/priority-fee-tuning) — 重い AMM v4 スワップ用のプライオリティフィーサイジング。

ソース：

* [Raydium SDK v2](https://github.com/raydium-io/raydium-sdk-V2)
* [Raydium AMM program](https://github.com/raydium-io/raydium-amm)
