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

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のプログラムIDとPDAシードは reference/program-addresses に正規に記載されています。このページは各アカウントの役割と維持する不変量に焦点を当てており、ハードコードされたアドレスについては扱いません。

CPMMプールの6つのアカウント

すべてのCPMMプールは、CPMMプログラム傘下の6つのプログラム派生アドレス(PDA)と、その1つが参照する共有AmmConfigアカウントで完全に記述されます。2つのミントがあれば、ネットワークに接触することなく、すべてを決定論的に導き出せます。
アカウントシード所有者目的
authority"vault_and_lp_mint_auth_seed"CPMMすべてのボルト移動とすべてのLPミント/バーン操作の署名者。すべてのCPMMプール間で共有。
poolState"pool"ammConfigtoken0Minttoken1Mint または 任意の署名者提供のランダムキーペアCPMMプールの状態構造体 — ミントペア、ボルト残高、LP供給量、フィーの蓄積、observationポインタ。CPMM Initialize 命令は、4つのシードから導き出された正規PDA または 作成者が署名した任意のキーペアのいずれかを受け入れます。ランダムキーペアパスは、敵がメモプールを監視して正規PDAを正当な作成者より先に占有しようとするフロントランニング攻撃を回避するために存在します。
lpMint"pool_lp_mint"poolStateSPL TokenプールのLPトークン。供給量 = 発行済みLP総額。ミント権限 = CPMMのauthority PDA。
vault0"pool_vault"poolStatetoken0MintSPL Token / Token-2022プールのtoken0残高を保有。authorityPDAが所有。
vault1"pool_vault"poolStatetoken1MintSPL Token / Token-2022プールのtoken1残高を保有。authorityPDAが所有。
observation"observation"poolStateCPMMTWAPに使用される価格サンプルのリングバッファ。すべてのスワップで書き込み。
共有設定:
アカウントシード所有者目的
ammConfig"amm_config"index: u16CPMMトレード/プロトコル/ファンド/クリエイターのフィーレートと管理者キーを保有。「フィーティア」ごと1つ。PoolStateは作成時に1つにバインドされ、その後変更できない。

2つのミントだけからプールを導き出す

import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";

const CPMM_PROGRAM_ID = new PublicKey(
  "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"
); // mainnet — see reference/program-addresses

function u16ToBytes(n: number): Buffer {
  const b = Buffer.alloc(2);
  b.writeUInt16BE(n);
  return b;
}

// token0 < token1 by byte order. Getting this wrong yields a valid PDA
// that points at a nonexistent pool.
function sortMints(a: PublicKey, b: PublicKey): [PublicKey, PublicKey] {
  return Buffer.compare(a.toBuffer(), b.toBuffer()) < 0 ? [a, b] : [b, a];
}

export function deriveCpmmAccounts(
  mintA: PublicKey,
  mintB: PublicKey,
  ammConfigIndex = 0,
) {
  const [token0Mint, token1Mint] = sortMints(mintA, mintB);

  const [ammConfig] = PublicKey.findProgramAddressSync(
    [Buffer.from("amm_config"), u16ToBytes(ammConfigIndex)],
    CPMM_PROGRAM_ID,
  );
  const [authority] = PublicKey.findProgramAddressSync(
    [Buffer.from("vault_and_lp_mint_auth_seed")],
    CPMM_PROGRAM_ID,
  );
  const [poolState] = PublicKey.findProgramAddressSync(
    [
      Buffer.from("pool"),
      ammConfig.toBuffer(),
      token0Mint.toBuffer(),
      token1Mint.toBuffer(),
    ],
    CPMM_PROGRAM_ID,
  );
  const [lpMint] = PublicKey.findProgramAddressSync(
    [Buffer.from("pool_lp_mint"), poolState.toBuffer()],
    CPMM_PROGRAM_ID,
  );
  const [vault0] = PublicKey.findProgramAddressSync(
    [Buffer.from("pool_vault"), poolState.toBuffer(), token0Mint.toBuffer()],
    CPMM_PROGRAM_ID,
  );
  const [vault1] = PublicKey.findProgramAddressSync(
    [Buffer.from("pool_vault"), poolState.toBuffer(), token1Mint.toBuffer()],
    CPMM_PROGRAM_ID,
  );
  const [observation] = PublicKey.findProgramAddressSync(
    [Buffer.from("observation"), poolState.toBuffer()],
    CPMM_PROGRAM_ID,
  );

  return {
    ammConfig,
    authority,
    poolState,
    lpMint,
    token0Mint,
    token1Mint,
    vault0,
    vault1,
    observation,
  };
}
プールPDAを導き出す前に必ずミントをソートしてください。 シードはユーザー順ではなく、バイト順で2つのミントをハッシュします。(A, B)(B, A) を持つ2つのプールはオンチェーンで衝突し、ソートはプログラムがマッピングを正規にする方法です。
プールIDは必ずしも正規PDAではありません。 Initialize は、上記のPDAに加えて、任意の署名者キーペアを pool_state として受け入れます。渡されたアカウントが正規PDAと一致しない場合、プログラムは署名者である必要があります。つまり、作成者は署名する新しいキーペアを渡します。これはフロントラン対策です:正規PDAをつかもうとしているサードパーティは、正当な作成者がランダムキーペアを代わりに使用することで回避できます。下流のPDA(lpMintvault0vault1observation)はまだ poolState.key() から導き出されるため、使用されたアドレスに関わらず一意のままです。プールにインデックスを付けるときは、正規PDAを導き出すことではなく、オンチェーン状態からプールIDを常に検出してください(例:CPMMプログラム傘下の PoolState アカウント)。後者はランダムキーペアプールを見逃します。

アカウントレイアウト

完全なRust定義は raydium-cp-swap ソースに存在します。以下のフィールドは、統合時に読み取るフィールドです。

PoolState

// programs/cp-swap/src/states/pool.rs
pub struct PoolState {
    pub amm_config: Pubkey,               // binds this pool to an AmmConfig
    pub pool_creator: Pubkey,             // who ran initialize
    pub token_0_vault: Pubkey,            // == vault0 PDA
    pub token_1_vault: Pubkey,            // == vault1 PDA

    pub lp_mint: Pubkey,
    pub token_0_mint: Pubkey,
    pub token_1_mint: Pubkey,

    pub token_0_program: Pubkey,          // SPL Token or Token-2022 program
    pub token_1_program: Pubkey,

    pub observation_key: Pubkey,          // == observation PDA
    pub auth_bump: u8,
    pub status: u8,                       // bitmask: deposit | withdraw | swap
    pub lp_mint_decimals: u8,
    pub mint_0_decimals: u8,
    pub mint_1_decimals: u8,

    pub lp_supply: u64,                   // mirrors lp_mint supply
    pub protocol_fees_token_0: u64,
    pub protocol_fees_token_1: u64,
    pub fund_fees_token_0: u64,
    pub fund_fees_token_1: u64,

    pub open_time: u64,                   // unix; swaps rejected before this
    pub recent_epoch: u64,

    // Creator-fee state (added after the original layout):
    pub creator_fee_on: u8,               // 0=BothToken, 1=OnlyToken0, 2=OnlyToken1
    pub enable_creator_fee: bool,
    pub padding1: [u8; 6],
    pub creator_fees_token_0: u64,
    pub creator_fees_token_1: u64,

    pub padding: [u64; 28],
}
実際に読み取るもの:
  • lp_supply — プールのLPミント供給量の内部ミラー。LP シェア計算に使用します。値はミントのオンチェーン供給量と一致するはずですが、PoolState から読み取ることで、追加のアカウント取得を回避できます。
  • protocol_fees_token{0,1}fund_fees_token{0,1}蓄積された未実行フィー。これらはスワップ価格に影響しません。CollectProtocolFee / CollectFundFee が呼び出されるまでボルトに残ります。
  • statusSwapDepositWithdraw が許可されているかどうかを制御するビットマスク。UpdatePoolStatus 経由で管理者が更新。SDKはトランザクション構築前にこれをチェックします。直接CPIを実行している場合は、自分でチェックしてください。
  • token0_program / token1_program — 各ボルトのためにCPIを実行するトークンプログラム。1つはSPL Tokenで、もう1つはToken-2022の場合があります。これらは独立しています。
  • open_time — Unixタイムスタンプ。この時刻前のスワップは失敗します。デポジットは open_time 前に許可されるため、プールをシードできます。
  • creator_fee_on / enable_creator_fee — クリエイターフィーがこのプール用にアクティブなかどうか、およびスワップのどちら側から集められるかを制御します。enable_creator_fee == false はクリエイターフィーパスを完全にゼロにします。有効な場合、creator_fee_on は以下を選択します:0 = スワップ入力であるトークンからのフィー取得(BothToken);1 = token_0 のみからのフィー取得(token_1 → token_0 スワップをスキップ);2 = token_1 のみからのフィー取得。プール作成時に InitializeWithPermission で設定;その後変更不可。
  • creator_fees_token_{0,1} — 蓄積されたクリエイターフィー。CollectCreatorFee で実行。

AmmConfig

pub struct AmmConfig {
    pub bump: u8,
    pub disable_create_pool: bool,
    pub index: u16,                       // matches the seed
    pub trade_fee_rate: u64,              // e.g., 2500 = 0.25%
    pub protocol_fee_rate: u64,           // fraction of trade fee to protocol
    pub fund_fee_rate: u64,               // fraction of trade fee to fund
    pub create_pool_fee: u64,             // paid once at init (in SOL or token)
    pub protocol_owner: Pubkey,           // can call CollectProtocolFee
    pub fund_owner: Pubkey,               // can call CollectFundFee
    pub creator_fee_rate: u64,            // optional pool-creator fee rate (1/1_000_000 of volume)
    pub padding: [u64; 15],
}
3つの注意点:
  1. trade_fee_ratecreator_fee_rate は取引量の分数で、両者とも 1/1_000_000 単位で表示されます。2500 は取引量の0.25%を意味します。protocol_fee_ratefund_fee_rateトレード フィーの分数 (取引量の分数ではなく)で、同じ 1/1_000_000 分母を使用します。クリエイターフィーはトレード フィーの分数ではなく、独立したレートです。完全な計算は products/cpmm/fees にあります。
  2. indexu16 であるため、シードハッシュは2バイトのビッグエンディアンを使用します。バイト順の1ずれは一般的な統合バグです。
  3. AmmConfig はプールレベルで不変です。 プールは作成時に1つの AmmConfig を指してから、切り替わることはありません。フィー変更は、プールがスワップのたびに設定を読み取るため伝播しますが、プールはフィーティア間で移動できません。
クリエイターフィーについての注記:レート自体creator_fee_rate)は AmmConfig に存在し、フィーティア間で共有されます。特定のプールが実際にそれを請求するかどうか(enable_creator_fee)、およびスワップのどちら側に着地するか(creator_fee_on)は PoolState に存在します。クリエイターフィーはトレード フィーの独立したもので、独立したレート、独立したカウンター(creator_fees_token_{0,1})を備えており、LP/プロトコル/ファンドのトレード フィーシェアを削減することはありません。実行は CollectCreatorFee を通じて行われます。完全なメカニクスについては products/cpmm/fees を参照してください。

Permission

InitializeWithPermission で使用される小さなアクセス制御アカウント。CPMMプログラムは、他のプログラム(例えば、トークンをCPMMに卒業させるときのLaunchLab)が与えられた AmmConfig に対してプールを作成できることを証明するための、許可されたプール作成パスをサポートしています。
pub struct Permission {
    pub authority: Pubkey,    // who is allowed to call InitializeWithPermission
    pub padding: [u64; 8],
}
PermissionPDAはCPMM管理者が CreatePermissionPda を通じて作成され、ClosePermissionPda を通じて取り消されます。エンドユーザーはこのアカウントと直接やり取りしません。これはクロスプログラムフロー用の配管です。

ボルトとToken-2022

vault0vault1 はCPMMのauthority PDAが所有し、それらのトークンプログラム所有者(token_program)はSPL TokenまたはToken-2022で、プール作成時にミントのプログラムによって決定されます。プールは2つのケースを透過的に処理し、Swap / Deposit / Withdraw 命令アカウントで各側の正しいトークンプログラムIDを渡します。 CPMMはプール作成時に厳密な拡張許可リストを強制します(utils/token.rsis_supported_mint)。Token-2022ミントはCPMMプールで使用でき、それがすべての拡張機能がこのリストに含まれている場合に限ります:
  • TransferFeeConfig ミントが転送のたびに適用。プールは SwapBaseInput デポジット側の受信側で、引き出し側の送信側です。プログラムはボルトに着地するネット金額を計算し、曲線をそれに応じて設定します。algorithms/token-2022-transfer-fees を参照してください。
  • MetadataPointer および TokenMetadata ミント上の標準メタデータ。スワップ計算への影響なし。
  • InterestBearingConfig ミントのUI金額は利息が蓄積。ボルトは生の金額を格納し、曲線は生の金額のみで動作します。APRを表示するUI は、Token-2022ヘルパーを呼び出してUI金額をレンダリングする必要があります。
  • ScaledUiAmount UI表示スケーリング拡張機能。InterestBearingConfig と同じ扱い — 曲線は生の金額を使用します。
他の拡張機能 — PermanentDelegateTransferHookDefaultAccountStateNonTransferableConfidentialTransferGroup/GroupMemberMintCloseAuthority など — は InitializeNotSupportMint で拒否されます。例外は、プログラムのハードコードされた小さなミントホワイトリスト(いくつかの特定のpubkeys)で、拡張チェックをバイパスします。これはケースバイケースで特定のミントをオンボードするために使用されます。 ベットされた拡張リストとミントホワイトリストは、CP-Swapソースの programs/cp-swap/src/utils/token.rs に存在し、将来のプログラムアップグレードで変更される可能性があります。

Observation

observationアカウントは ObservationState エントリのリングバッファで、各エントリは block_timestamp累積価格を格納します。スワップのたびに、最後のスワップ以降に十分な時間が経過している場合、プログラムは新しいobservationを追加します。TWAPは2つのobservationを読み、Δcumulative / Δtime を計算することで計算されます。
// OBSERVATION_NUM is hardcoded in the program to 100.
pub const OBSERVATION_NUM: usize = 100;

pub struct Observation {
    pub block_timestamp:              u64,
    pub cumulative_token_0_price_x32: u128,   // Q32.32, top 64 bits left for overflow
    pub cumulative_token_1_price_x32: u128,
}

pub struct ObservationState {
    pub initialized:           bool,
    pub observation_index:     u16,                            // circular index
    pub pool_id:               Pubkey,
    pub observations:          [Observation; OBSERVATION_NUM], // 100 entries
    pub last_update_timestamp: u64,                            // timestamp of the most recent append
    pub padding:               [u64; 3],
}
リングバッファは100 observations サイズです。各observationは40バイトなので、配列のみで4,000バイトです。周囲のフィールドとdiscriminatorの後、完全な ObservationState PDAは約4,100バイトです。 2つのコンシューマー規則:
  • 単一observationを価格として使用しないでください。 それは累積であって、スポット価格ではありません。TWAPを計算するため、2つを使用してください。
  • 少なくとも1ブロック離れたobservationを選択してください。 同じブロック内のスワップは新しいobservationを生成しない場合があります。連続読み取りは同じレコードを返すことがあります。
その他の計算は products/clmm/accounts にあります。

アカウントライフサイクル

イベント作成されたアカウント削除されたアカウント
InitializepoolStatelpMintvault0vault1observation
Deposit— (ユーザーLP ATAが作成される可能性あり)
Withdraw
Swap— (ユーザー宛先ATAが作成される可能性あり)
CollectProtocolFee
CollectFundFee
UpdatePoolStatus
CPMMプールとそのPDAは決してクローズされません。流動性がゼロの場合でも、poolState は残ります。これは意図的です:後で同じプールを再シードすることは、その履歴observationバッファを保持し、そのPDA導出の安定性を保ちます。

どこで何を読むか

ソース: