Passer au contenu principal

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.

Cette page est traduite automatiquement par IA. La version anglaise fait foi.Voir la version anglaise →
Le Stable AMM partage la structure des comptes au niveau de la pool du AMM v4 (AmmInfo, coffres-forts, autorité) et exige en outre un compte ModelDataInfo qui stocke la table de consultation. Cette page couvre les deux.

Inventaire

Une pool Stable AMM est liée à exactement un marché OpenBook. L’inventaire complet ressemble étroitement à celui du AMM v4 :
CatégorieComptePropriétaireRôle
PoolAmmInfoProgramme StableÉtat de la pool, références aux coffres-forts, OpenBook et compte de données du modèle.
Poolamm_authorityProgramme StablePDA appartenant au programme qui signe les mouvements de coffre-fort. Partagé entre toutes les pools Stable AMM.
Poolamm_open_ordersOpenBookLe compte OpenOrders OpenBook de la pool.
Poolamm_target_ordersProgramme StableGrille au niveau de la pool pour les ordres limites.
Poolpool_coin_token_accountSPL TokenCoffre-fort du côté coin de la pool.
Poolpool_pc_token_accountSPL TokenCoffre-fort du côté pc de la pool.
Poollp_mintSPL TokenMint LP interchangeable.
Modèlemodel_data_accountProgramme StableLa table de consultation : 50 000 × DataElement.
Marchéserum_marketOpenBookMarché OpenBook.
Marchéserum_bids, serum_asksOpenBookFiles d’attente des enchères/offres.
Marchéserum_event_queueOpenBookFile d’attente des événements.
Marchéserum_coin_vault, serum_pc_vaultSPL TokenCoffres-forts au niveau du marché OpenBook.
Marchéserum_vault_signerOpenBookSignataire du coffre-fort au niveau du marché.

AmmInfo

Compte d’état racine. La disposition est presque identique à celle du AMM v4 — paramètres de la pool, décimales, frais, références aux coffres-forts/mint — avec un ajout : un champ model_data_key pointant vers la table de consultation.
// raydium-stable/program/src/state.rs (abridged)
pub struct AmmInfo {
    pub account_type: u64,              // = 0 (AmmAccount)
    pub status: u64,                    // bitmask: swap/deposit/withdraw/crank enabled
    pub nonce: u64,                     // bump for amm_authority
    pub order_num: u64,
    pub depth: u64,
    pub coin_decimals: u64,
    pub pc_decimals: u64,
    pub state: u64,                     // state machine (IdleState, etc.)
    pub reset_flag: u64,
    pub min_size: u64,
    pub vol_max_cut_ratio: u64,
    pub amount_wave: u64,
    pub coin_lot_size: u64,             // mirrors OpenBook
    pub pc_lot_size: u64,
    pub min_price_multiplier: u64,
    pub max_price_multiplier: u64,
    pub sys_decimal_value: u64,
    pub abort_trade_factor: u64,
    pub price_tick_multiplier: u64,
    pub price_tick: u64,
    
    pub fees: Fees,                     // see below
    pub out_put: OutPutData,            // PnL, swaps, punish amounts
    
    pub coin_vault: Pubkey,
    pub pc_vault: Pubkey,
    pub coin_mint: Pubkey,
    pub pc_mint: Pubkey,
    pub lp_mint: Pubkey,
    pub model_data_key: Pubkey,         // ← THE LOOKUP TABLE
    pub open_orders: Pubkey,            // OpenBook OpenOrders
    pub serum_market: Pubkey,
    pub serum_program: Pubkey,
    pub target_orders: Pubkey,
    pub amm_admin: Pubkey,              // admin key
    pub client_order_id: u64,
    pub lp_amount: u64,                 // LP supply
    pub lp_net: u64,                    // LP value metric
    pub padding: [u64; 61],
}

pub struct Fees {
    pub min_separate_numerator: u64,
    pub min_separate_denominator: u64,
    pub trade_fee_numerator: u64,       // 25
    pub trade_fee_denominator: u64,     // 10_000 → 0.25%
    pub pnl_numerator: u64,             // 12
    pub pnl_denominator: u64,           // 100 → 12% of fee = 0.03% of volume
    pub swap_fee_numerator: u64,        // 25
    pub swap_fee_denominator: u64,      // 10_000
}

pub struct OutPutData {
    pub need_take_pnl_coin: u64,        // accrued protocol fee (coin)
    pub need_take_pnl_pc: u64,          // accrued protocol fee (pc)
    pub total_pnl_pc: u64,
    pub total_pnl_coin: u64,
    pub pool_open_time: u64,
    pub punish_pc_amount: u64,
    pub punish_coin_amount: u64,
    pub orderbook_to_init_time: u64,
    pub swap_coin_in_amount: u128,
    pub swap_pc_out_amount: u128,
    pub swap_pc_in_amount: u128,
    pub swap_coin_out_amount: u128,
    pub swap_pc_fee: u64,
    pub swap_coin_fee: u64,
}
Champs clés pour les intégrateurs :
  • model_data_key — l’adresse de la table de consultation. Doit être transmise à chaque instruction.
  • fees — structure identique au AMM v4. Par défaut : frais commerciaux de 0,25 %, répartition LP / protocole de 0,22 % / 0,03 %.
  • coin_vault, pc_vault — les coffres-forts de la pool.
  • status — masque de bits contrôlant l’activation de swap/depot/retrait/crank.
  • out_put.need_take_pnl_* — balayés par WithdrawPnl.

ModelDataInfo

La table de consultation. Un grand tableau creux de points prix/quantité.
// raydium-stable/program/src/state.rs
pub const ELEMENT_SIZE: usize = 50000;

pub struct DataElement {
    pub x: u64,         // table X (e.g., coin amount)
    pub y: u64,         // table Y (e.g., pc amount)
    pub price: u64,     // price at (x, y)
}

pub struct ModelDataInfo {
    pub account_type: u64,              // = 2 (ModleDataAccount)
    pub status: u64,                    // Initialized or Uninitialized
    pub multiplier: u64,                // scale factor for x, y (e.g., 10^6)
    pub valid_data_count: u64,          // how many elements are populated
    pub elements: [DataElement; 50000], // the table itself
}
Cycle de vie :
  1. InitModelData crée le compte et définit status = Initialized, multiplier = <admin-provided>, valid_data_count = 0.
  2. UpdateModelData (invoquée jusqu’à 5 fois par transaction) remplit les éléments via :
    • Entrée : tableau de paires (index: u64, DataElement).
    • Écrit chacune en elements[index].
    • Incrémente valid_data_count si index >= valid_data_count.
  3. Swap/depot/retrait appellent des fonctions de consultation qui effectuent une recherche binaire et une interpolation dans elements[0..valid_data_count].

DataElement

L’entrée atomique de la table. Doit être triée (x croissant, y décroissant, prix croissant) pour que la recherche binaire fonctionne.
pub struct DataElement {
    pub x: u64,         // X coordinate (e.g., token_a balance, scaled by multiplier)
    pub y: u64,         // Y coordinate (e.g., token_b balance, scaled by multiplier)
    pub price: u64,     // price (x/y in scaled form, scaled by multiplier)
}
Lors du remplissage de la table, l’administrateur spécifie ces valeurs pré-échelles. Le programme ne valide pas l’ordre de tri en chaîne (pour la rapidité), donc un tri incorrect provoque des devis erronés.

Autorité et coffres-forts

Identique au AMM v4 :
  • amm_authority est une seule PDA à l’échelle du programme dérivée avec la graine ["amm authority"]. Elle possède tous les coffres-forts de la pool et signe leurs mouvements.
  • Les coffres-forts sont des comptes SPL Token dont le propriétaire est amm_authority, pas des ATA.
Token-2022 n’est pas pris en charge.

Masque de bits de statut

Identique au AMM v4. Contrôle si swap/depot/retrait/crank sont activés.

Suivi des frais et du PnL

Identique au AMM v4. La struct out_put suit :
  • need_take_pnl_coin, need_take_pnl_pc — frais de protocole accumulés mais non encore balayés. WithdrawPnl les déplace.
  • swap_coin_in_amount, swap_pc_in_amount, etc. — compteurs d’analytique.

Taille du compte

Le ModelDataInfo est volumineux (~1,2 Mo, puisque 50 000 éléments × 24 octets par élément). C’est pourquoi la création d’une pool Stable exige une pré-allocation explicite de loyer et de compte. Le SDK Raydium et les outils gèrent cela de manière transparente ; les intégrateurs n’ont rarement besoin d’allouer manuellement.

Dérivation des comptes à partir de zéro

Comme le AMM v4, le Stable AMM utilise des clés amorcées (pas des PDA pures). L’identité canonique de la pool est dérivée via :
ammId = createWithSeed(
  owner: ammAuthority,
  seed: marketPubkey.toBase58().slice(0, 32),
  programId: STABLE_PROGRAM_ID,
)
De la même manière pour les coffres-forts, le mint LP, les ordres cibles, etc. En pratique, utilisez le SDK ou l’API pour récupérer les adresses pré-calculées.

Où lire quoi

Sources :