メインコンテンツへスキップ

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.

このページは AI による自動翻訳です。すべての内容は英語版を正とします。英語版を表示 →
サポートマトリックス:CPMM は Token-2022 をフル対応しており、トランスファーフィー付きミントも含みます。CLMM は明示的な SwapV2 アカウントを介して、トランスファーフィー付き Token-2022 に対応しています。AMM v4 は Token-2022 に対応していません。LaunchLab はベースミント向けに Token-2022 に対応していません(クラシック SPL ミントを生成します)。Farm v6 はステーキングおよびリワードミントの両方で Token-2022 に対応しています。

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

Token-2022 は第2の SPL Token プログラムです(TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DATokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb)。その拡張機能の中でも、トランスファーフィー拡張機能は、あるトークンミント上のすべての 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 では:
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 経由):
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_outuser_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 を受け取ります。

ポインタ

ソース: