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

# Token-2022 トランスファーフィー（スワップ時）

> Token-2022 のトランスファーフィー拡張機能がスワップ前後の金額計算にどう影響するか、Raydium のどの製品がサポートしているか、統合業者が処理する必要があるエッジケース（非対称フィー、フィー更新、最大フィー上限、非転送可能拡張機能）について。

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

  [英語版を表示 →](/algorithms/token-2022-transfer-fees)
</Info>

<Info>
  サポートマトリックス：**CPMM** は Token-2022 をフル対応しており、トランスファーフィー付きミントも含みます。**CLMM** は明示的な `SwapV2` アカウントを介して、トランスファーフィー付き Token-2022 に対応しています。**AMM v4** は Token-2022 に対応していません。**LaunchLab** はベースミント向けに Token-2022 に対応していません（クラシック SPL ミントを生成します）。**Farm v6** はステーキングおよびリワードミントの両方で Token-2022 に対応しています。
</Info>

## トランスファーフィーとは

Token-2022 は第2の SPL Token プログラムです（`TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` → `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`）。その拡張機能の中でも、**トランスファーフィー**拡張機能は、あるトークンミント上のすべての `TransferChecked` から転送額からフィーを差し引きます。フィーはミント権限者が指定した受取人にルーティングされ、権限者が更新できます（制限範囲内）。

トランスファーフィー付きミントには、次の 2 つの関連パラメータがあります。

* **`transfer_fee_basis_points`** — レート（例：100 = 1%）。
* **`maximum_fee`** — 転送ごとの絶対上限（クジラが巨額を移動するときにフィーが無制限になるのを防ぐ）。

ミントは同時に **2つ** のアクティブなトランスファーフィー設定を持つことができます。「新しい」設定（現在有効）と「古い」設定（廃止予定）です。これが「エポック遷移」設計であり、トランスファーフィー変更はエポック境界をまたいで有効になり、進行中のトランザクションで驚きを避けます。

## スワップにとって重要な理由

プール資金庫は実際の残高を保有しています。ユーザーが Raydium スワップを実行するとき：

1. ユーザーはプール資金庫に `amount_in` を送信します。**イン・ミント**にトランスファーフィーがある場合、資金庫は `amount_in − fee_in` ではなく `amount_in` を受け取ります。
2. スワップ数学は資金庫で受け取った額に対して動作します。
3. プールはユーザーの ATA に `amount_out` を送信します。**アウト・ミント**にトランスファーフィーがある場合、ユーザーは `amount_out − fee_out` ではなく `amount_out` を受け取ります。

スワッププログラムが素朴で raw の `amount_in` 引数を使用する場合、プログラムが考えているより資金庫が少なく受け取ったため、不変量チェックが失敗します。逆に、アウトバウンドトランスファーフィーを差し引かずに `amount_out` を計算する場合、ユーザーは不足を目にしてプログラムを非難します。

Raydium CPMM と CLMM（`SwapV2` 経由）はこれを以下で処理します：

* **スワップ前**：`in_after_fee = amount_in − transfer_fee_on(amount_in, in_mint)` を計算し、曲線数学で `in_after_fee` を使用します。
* **スワップ後**：`out_gross = amount_out_from_curve` を計算し、`TransferChecked` でユーザーに送信します。Token-2022 プログラムがトランスファーフィーでそれ自体を削減します。

ユーザーの `minAmountOut` スリッページ境界は `out_gross`（プールが送信するもの）に対して確認されます、ユーザーが受け取るものに対してではなく。これはすべての主要なSolana DEXが Token-2022 を処理する方法であり、重要な理由は：

* プール がフィー後を確認した場合、クォートと実行の間のフィー更新によりトレードが返却されるでしょう。
* フィー前を確認することで障害をクォート自体の品質に留め、ユーザーのアウト・オブ・バンドフィー変更ではなく。

UI はユーザーに「受け取り額」を表示するときに、期待される Token-2022 トランスファーフィーを差し引くべきです。

## Token-2022 フィーの計算

SPL Token-2022 プログラムは決定的なヘルパーを公開します。Rust では：

```rust theme={null}
use spl_token_2022::extension::transfer_fee::TransferFeeConfig;
use spl_token_2022::extension::StateWithExtensions;

let mint_data = ...;
let state = StateWithExtensions::<Mint>::unpack(&mint_data)?;
let config = state.get_extension::<TransferFeeConfig>()?;

let epoch = Clock::get()?.epoch;
let fee_bp = config.get_epoch_fee(epoch).transfer_fee_basis_points;
let max_fee = u64::from(config.get_epoch_fee(epoch).maximum_fee);

let fee = (amount as u128 * fee_bp as u128 / 10_000).min(max_fee as u128) as u64;
```

TypeScript では（`@solana/spl-token` 経由）：

```ts theme={null}
import { getTransferFeeConfig, getTransferFeeAmount } from "@solana/spl-token";

const config = getTransferFeeConfig(mintAccount);
const currentEpochFee = config.olderTransferFee.epoch <= currentEpoch
  ? config.newerTransferFee
  : config.olderTransferFee;

const rate   = currentEpochFee.transferFeeBasisPoints;
const maxFee = currentEpochFee.maximumFee;
const fee    = Math.min(Math.floor(amount * rate / 10_000), Number(maxFee));
```

## 調整済みスワップ公式（CPMM、正確入力）

`f_pool` をプール手数料レート、`f_in` をイン・ミント トランスファーフィーレート、`max_in` をその最大上限、`f_out` をアウト・ミント トランスファーフィーレート、`max_out` をその最大上限とします。

```
transfer_fee_in  = min(amount_in · f_in / 10_000, max_in)
vault_received   = amount_in − transfer_fee_in

pool_fee         = ceil(vault_received · f_pool / 1_000_000)
amount_after     = vault_received − pool_fee
amount_out_gross = y · amount_after / (x + amount_after)

transfer_fee_out = min(amount_out_gross · f_out / 10_000, max_out)
user_receives    = amount_out_gross − transfer_fee_out
```

スリッページチェック：`amount_out_gross ≥ min_amount_out`（`user_receives ≥ min_amount_out` ではなく）。ユーザーの `minAmountOut` は SDK により `expected_gross · (1 − slippage)` に設定されます。「送信」側で境界を保つ、「受取」側ではなく。

## 調整済み公式（CPMM、正確出力）

SDK は `user_receives = amount_out_exact` となるよう `amount_in` を見つけるために反復します：

```
# ユーザーはトランスファーフィー後に amount_out_exact を受け取りたい
amount_out_gross = amount_out_exact + transfer_fee_out_for(amount_out_exact)

# その後 CPMM 正確出力を amount_after について解きます：
amount_after     = ceil(x · amount_out_gross / (y − amount_out_gross))

# その後プール手数料を追加します：
vault_received   = ceil(amount_after · 1_000_000 / (1_000_000 − f_pool))

# その後イン トランスファーフィーを追加します：
amount_in = ceil(vault_received · 10_000 / (10_000 − f_in))
# （または反復 — 下記フィー上限エッジケースを参照）
```

`max_in` / `max_out` 上限は計算を非線形にします。上限に達するとフィーの増加が止まるためです。SDK の `computeAmountIn` / `computeAmountOut` はナイーブな公式が上限を超える場合、反復することでこれを処理します。

## エッジケース

### 非対称フィー（一方にフィーがあり、他方にはない）

実務では一般的です。上記の公式はこれを既に処理しています。一方が `f_in = 0` の場合、関連項は折りたたまれます。プログラムに特別なケースはありません。

### スワップ中のフィー更新

クォート時と実行時の間にミントのトランスファーフィーが変わる場合、スワップはわずかに悪い経済学で着地するか（ユーザーはスリッページ許容範囲内の差を負担）、または返却するか（グロス出力が `minAmountOut` 以下に下がる）します。スリッページ境界はこれを吸収します。追加保護は必要ありません。

### 最大フィー上限

トレードが `maximum_fee` に達するのに十分な大きさになると、フィーが飽和し、さらなる成長はゼロです。これは非常に大きなトレードで有効レートを漸近的にゼロにし、深く流動性が不足した市場で奇妙な価格曲線を引き起こす可能性があります。SDK の `computeAmountOut` はこれを考慮します。

### 非転送可能拡張機能

いくつかの Token-2022 ミントは `NonTransferable` 拡張機能を使用します。これはミント権限者との間を除くすべての `Transfer` 呼び出しを拒否します。このようなミント **は** Raydium プールでは全く使用できません。`CreatePool` は初期化時にそれらを拒否します。

### 利息付きミント

Token-2022 は、残高が時間とともに成長するように見えさせる `InterestBearingConfig` 拡張機能もサポートします。Raydium のプールは生の資金庫残高を読み取ります（利息の計上を無視）。利息付きミント付きプールでは、LP がそれらを償却するときに蓄積された利息をキャプチャします（資金庫の残高は LP 供給表現より速く成長）。統合業者はこれを問題なしとして扱いますが、LP 側に文書化するべきです。

### トランスファーフック

Token-2022 の `TransferHook` 拡張機能は、すべての転送で任意の CPI を許可します。Raydium CPMM はこれらをサポートしています。スワップ命令はフック アカウントを転送します。しかし CU オーバーヘッドを追加し、フックが正しく動作する必要があります。CLMM `SwapV2` もフックをサポートします。AMM v4 は Token-2022 に全く対応していないため、質問は生じません。

## 実施例

CPMM プール、`x = 1_000_000 USDY, y = 1_000_000 USDC`、プール手数料 0.25%。

* USDY は 1% のトランスファーフィーを持ち、`max_fee = 10_000`（6 小数点で 0.01 USDY）。
* USDC にはトランスファーフィーがありません。

ユーザーは `amount_in = 1_000 USDY` を USDC に交換します（正確入力）。

```
transfer_fee_in = min(1_000 · 100 / 10_000, 10_000)  = 10     // 1%、上限をはるかに下回る
vault_received  = 1_000 − 10 = 990

pool_fee        = ceil(990 · 2_500 / 1_000_000)  = 3    // 0.25%
amount_after    = 990 − 3 = 987

amount_out_gross = 1_000_000 · 987 / (1_000_000 + 987) = 986_027 / ...  ≈ 985.97
```

≈ 985.97 USDC。アウトバウンドトランスファーフィーなしなので、ユーザーは 985.97 USDC を受け取ります。

## ポインタ

* [`products/cpmm/overview`](/ja/products/cpmm/overview) — CPMM Token-2022 サポート。
* [`products/clmm/instructions`](/ja/products/clmm/instructions) — Token-2022 ルーティング向けの `SwapV2` と `Swap`。
* [`solana-fundamentals/spl-token-and-token-2022`](/ja/solana-fundamentals/spl-token-and-token-2022) — 一般的な Token-2022 拡張機能モデル。

ソース：

* [SPL Token-2022 トランスファーフィー拡張機能ドキュメント](https://spl.solana.com/token-2022/extensions#transfer-fees)
* Raydium CPMM プログラムソース（`SwapBaseInput` / `SwapBaseOutput` Token-2022 処理）。
* Raydium CLMM プログラムソース（`SwapV2`）。
