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 →
Cette page décrit la structure et le rôle de chaque compte. Les seeds canoniques sont répertoriées dans reference/program-addresses. Un pool CLMM mobilise davantage de comptes qu’un pool CPMM, car la liquidité est stockée de façon clairsemée sur l’ensemble de la plage de ticks ; comprendre cette dispersion constitue l’essentiel de cette page.

Inventaire des comptes

Un pool CLMM actif est décrit par les familles de comptes suivantes. Tous appartiennent au programme CLMM, à l’exception des deux mints et de leurs vaults.
CompteRôleNombre par pool
AmmConfigPalier de frais : taux de frais de trading, quote-part protocole, quote-part fund, espacement de ticks par défaut. Partagé par tous les pools de ce palier.1 (partagé)
PoolStatesqrt_price_x64 courant, tick courant, liquidité totale, croissance globale des frais, infos de récompense, pointeur d’observation.1
TickArrayStateUn bloc de TICK_ARRAY_SIZE ticks adjacents. Initialisé uniquement à la demande.0 ≤ N ≤ plage
TickArrayBitmapExtensionBitmap de débordement indiquant quels tableaux de ticks existent au-delà du bitmap inline de PoolState.0 ou 1
PersonalPositionStateUn par position LP. Stocke la plage, la liquidité et la dernière croissance de frais/récompenses observée. Autorité = propriétaire du NFT.1 par position
Mint du NFT de positionMint de supply 1, associé à PersonalPositionState. Transférer le NFT transfère la position.1 par position
ObservationStateBuffer circulaire d’observations de prix pour le TWAP.1
token_0_vault, token_1_vaultComptes de tokens détenant les soldes du pool. Détenus par l’autorité du pool.2
DynamicFeeConfigEnsemble de paramètres réutilisables pour le mécanisme de frais dynamiques. Les pools créés via create_customizable_pool peuvent y adhérer. Géré par l’administrateur.partagé (par index)
LimitOrderStateUn par ordre limite ouvert. Enregistre le propriétaire, le tick, le sens, le montant total et le snapshot de l’output réglé.1 par ordre
LimitOrderNonceCompteur par (wallet, nonce_index) qui dérive des PDAs d’ordres uniques.1 par (wallet, index)

PoolState

L’état en temps réel du pool, lu à chaque swap et à chaque modification de position.
// programs/amm/src/states/pool.rs
pub struct PoolState {
    pub bump:           [u8; 1],
    pub amm_config:     Pubkey,            // fee tier binding
    pub owner:          Pubkey,            // admin (multisig)
    pub token_mint_0:   Pubkey,
    pub token_mint_1:   Pubkey,
    pub token_vault_0:  Pubkey,
    pub token_vault_1:  Pubkey,
    pub observation_key: Pubkey,

    pub mint_decimals_0: u8,
    pub mint_decimals_1: u8,
    pub tick_spacing:   u16,               // inherited from amm_config at init

    pub liquidity:      u128,              // total active (in-range) liquidity
    pub sqrt_price_x64: u128,              // Q64.64 of sqrt(price)
    pub tick_current:   i32,               // current tick index

    pub padding3:       u16,
    pub padding4:       u16,

    // Global fee growth per unit of liquidity, Q64.64.
    pub fee_growth_global_0_x64: u128,
    pub fee_growth_global_1_x64: u128,

    // Accrued-but-not-swept protocol fees (per mint).
    pub protocol_fees_token_0: u64,
    pub protocol_fees_token_1: u64,

    // Reserved padding for future upgrades.
    pub padding5: [u128; 4],

    // Status bitmask. Bits 0-5: open-position, decrease-liquidity,
    // collect-fee, collect-reward, swap, limit-order. A set bit disables
    // the corresponding operation.
    pub status:  u8,

    // Fee-collection mode (CollectFeeOn).
    //   0 = FromInput (deduct fee from the swap input — Uniswap-V3 default)
    //   1 = Token0Only (always deduct fee from token0 vault)
    //   2 = Token1Only (always deduct fee from token1 vault)
    pub fee_on: u8,
    pub padding: [u8; 6],

    // Live reward streams (up to REWARD_NUM = 3).
    pub reward_infos: [RewardInfo; 3],

    // Inline bitmap tracking initialized tick-arrays in the primary range.
    pub tick_array_bitmap: [u64; 16],

    // Reserved padding for future upgrades.
    pub padding6: [u64; 4],

    pub fund_fees_token_0: u64,
    pub fund_fees_token_1: u64,

    pub open_time:    u64,                 // currently disabled by the program
    pub recent_epoch: u64,

    // Per-pool dynamic-fee state. Zero-valued unless the pool was
    // created with `enable_dynamic_fee = true` via create_customizable_pool.
    pub dynamic_fee_info: DynamicFeeInfo,

    // Reserved for future upgrades.
    pub padding1: [u64; 14],
    pub padding2: [u64; 32],
}
Champs avec lesquels vous interagirez réellement :
  • sqrt_price_x64 et tick_current représentent l’état de prix du pool. Ils sont mis à jour ensemble à chaque swap. tick_current est la partie entière inférieure de log_{1.0001}(price).
  • liquidity est la liquidité active — la somme des valeurs L de toutes les positions dont la plage contient tick_current. Elle change à chaque fois qu’un swap franchit un tick et à chaque ouverture, fermeture ou redimensionnement de position.
  • fee_growth_global_{0,1}_x64 représentent les frais cumulés par unité de liquidité sur toute l’histoire du pool. Les positions les consultent pour calculer ce qui leur est dû.
  • tick_spacing est figé à la valeur de AmmConfig lors de l’initialisation et ne change jamais. Il détermine quels indices de ticks sont autorisés comme extrémités de position.
  • tick_array_bitmap est un bitmap inline couvrant la plage de ticks communément utilisée autour du prix spot. Pour les pools dont les positions s’étendent loin, le suivi du débordement est délégué au compte séparé TickArrayBitmapExtension.
  • fee_on est fixé à la création du pool. 0 (FromInput) reproduit le comportement classique d’Uniswap-V3. 1 et 2 dirigent les frais de swap vers un seul côté du carnet — voir products/clmm/fees pour les compromis associés.
  • dynamic_fee_info porte l’état de volatilité pour la majoration de frais dynamiques. Lorsqu’il est activé, chaque swap recalcule un dynamic_fee_component en plus de AmmConfig.trade_fee_rate. La structure est documentée sous DynamicFeeInfo ci-dessous ; les pools sans frais dynamiques laissent l’intégralité de cette struct à zéro.

AmmConfig

pub struct AmmConfig {
    pub bump: u8,
    pub index: u16,                       // uses "amm_config"+u16 seed

    pub owner:             Pubkey,        // admin
    pub protocol_fee_rate: u32,           // fraction of trade fee to protocol, denom 1e6
    pub trade_fee_rate:    u32,           // trade fee in 1e6ths of volume
    pub tick_spacing:      u16,           // default spacing for pools using this config
    pub fund_fee_rate:     u32,           // fraction of trade fee to fund, denom 1e6
    pub padding_u32: u32,

    pub fund_owner: Pubkey,
    pub padding: [u64; 3],
}
Exemple de paliers de frais CLMM publiés (à vérifier via GET https://api-v3.raydium.io/main/clmm-config) :
Indextrade_fee_rateEspacement de ticksUsage typique
0100 (0.01%)1Paires stables, USDC/USDT
1500 (0.05%)10Blue-chips corrélées
22_500 (0.25%)60Paires standard
310_000 (1.00%)120Actifs volatils ou longue traîne
protocol_fee_rate et fund_fee_rate sont des fractions du frais de trading ; même convention que pour le CPMM. Voir products/clmm/fees.

TickArrayState

Le CLMM ne stocke pas un enregistrement par tick — cela représenterait des milliards de comptes. Il regroupe plutôt TICK_ARRAY_SIZE ticks adjacents (initialisés ou non, typiquement 60 ou 88 selon la version du programme) dans un TickArrayState créé paresseusement à la première utilisation.
pub const TICK_ARRAY_SIZE: usize = 60;
pub const TICK_ARRAY_SIZE_USIZE: usize = 60;

pub struct TickArrayState {
    pub pool_id:                Pubkey,
    pub start_tick_index:       i32,                            // lowest tick in this array
    pub ticks:                  [TickState; TICK_ARRAY_SIZE],   // 60 entries
    pub initialized_tick_count: u8,
    pub recent_epoch:           u64,
    pub padding:                [u8; 107],
}

pub struct TickState {
    pub tick:                       i32,
    pub liquidity_net:              i128,                       // ΔL when crossing this tick upward
    pub liquidity_gross:            u128,                       // total L referencing this tick
    pub fee_growth_outside_0_x64:   u128,                       // see math.mdx
    pub fee_growth_outside_1_x64:   u128,
    pub reward_growths_outside_x64: [u128; 3],

    // Limit-order bookkeeping. All zero for ticks that have never carried
    // a limit order. See products/clmm/math for the matching algorithm.
    pub order_phase:                  u64,                      // monotonic FIFO cohort id
    pub orders_amount:                u64,                      // unfilled tokens in current cohort
    pub part_filled_orders_remaining: u64,                      // remaining tokens of partially-filled cohort
    pub unfilled_ratio_x64:           u128,                     // Q64.64; starts at 1.0 and shrinks as fills occur

    pub padding:                    [u32; 3],
}
Les quatre champs d’ordre limite sont à zéro pour tout tick n’ayant jamais servi à un ordre limite. Lorsque des ordres sont ouverts sur un tick, le programme les suit sous forme de séquence de cohortes :
  • order_phase est l’identifiant de cohorte. Il s’incrémente à chaque fois qu’une cohorte passe de « entièrement non exécutée » à « partiellement exécutée ».
  • orders_amount est le total en token d’entrée de la cohorte courante (la plus récente).
  • part_filled_orders_remaining suit la cohorte précédente en cours d’exécution par les swaps en cours.
  • unfilled_ratio_x64 est un multiplicateur Q64.64 porté par la cohorte : lorsqu’un swap exécute X% de la cohorte, le ratio est multiplié par (1 − X). Chaque ordre ouvert stocke son propre snapshot (order_phase, unfilled_ratio_x64) au moment de l’ouverture, ce qui ramène le calcul de règlement à une simple comparaison de snapshots.
Règles :
  • Un tick extrémité de position t doit satisfaire t % tick_spacing == 0. Le programme rejette les positions dont les extrémités ne sont pas alignées sur l’espacement.
  • Le tableau du tick est localisé à floor(t / (TICK_ARRAY_SIZE * tick_spacing)) * (TICK_ARRAY_SIZE * tick_spacing).
  • Un tableau de ticks est initialisé paresseusement : la première position ou le premier swap qui touche un tableau non initialisé le crée, en payant le rent.
  • Un tableau de ticks n’est jamais fermé par le programme. Une fois alloué, il persiste pour toute la durée de vie du pool, même après que tous les ticks qu’il contient sont revenus à liquidity_gross == 0. Les positions et swaps ultérieurs réutilisent le compte existant sans rent supplémentaire. Il n’existe aucun mécanisme de nettoyage des tableaux de ticks déclenché par ClosePosition.

TickArrayBitmapExtension

PoolState.tick_array_bitmap (inline) couvre la plage « proche du prix spot » — ±1 024 tableaux de ticks. Au-delà de cette plage (pour des valeurs de ticks extrêmes), le programme maintient un compte d’extension :
pub struct TickArrayBitmapExtension {
    pub pool_id: Pubkey,
    pub positive_tick_array_bitmap: [[u64; 8]; 14],
    pub negative_tick_array_bitmap: [[u64; 8]; 14],
}
Si votre plage de position est « normale », vous n’aurez jamais à vous préoccuper du compte d’extension. Les positions pleine plage (par ex. (MIN_TICK, MAX_TICK)) en ont besoin ; le SDK le résout pour vous.

Positions

Une position CLMM est un ensemble de trois comptes plus un mint :

Mint du NFT de position

Un mint SPL Token de supply 1. L’adresse du mint est un PDA déterministe ; le NFT de position dans le wallet du propriétaire n’est qu’un ATA détenant ce token unique. Transférer le NFT est la façon dont une position change de mains — le programme conditionne l’autorisation au détenteur actuel du solde ATA du NFT, et non à une Pubkey stockée dans l’état.

PersonalPositionState

Un par position ouverte. Indexé sur le mint du NFT.
pub struct PersonalPositionState {
    pub bump: [u8; 1],
    pub nft_mint: Pubkey,                 // this position's NFT mint
    pub pool_id:  Pubkey,

    pub tick_lower_index: i32,
    pub tick_upper_index: i32,

    pub liquidity: u128,                  // this position's L

    // Fee-growth snapshots at last time the position was touched.
    pub fee_growth_inside_0_last_x64: u128,
    pub fee_growth_inside_1_last_x64: u128,
    pub token_fees_owed_0: u64,           // accrued since last collect
    pub token_fees_owed_1: u64,

    pub reward_infos: [PositionRewardInfo; 3],
    pub recent_epoch: u64,
    pub padding: [u64; 7],
}

pub struct PositionRewardInfo {
    pub growth_inside_last_x64: u128,
    pub reward_amount_owed: u64,
}

ProtocolPositionState (déprécié)

Les versions antérieures du CLMM stockaient la comptabilité agrégée par (pool, tick_lower, tick_upper) dans un PDA ProtocolPositionState. Les versions récentes ne créent plus ni ne lisent ce compte. L’emplacement figure toujours dans les listes de comptes des instructions OpenPosition / IncreaseLiquidity / DecreaseLiquidity en tant qu’UncheckedAccount pour la compatibilité ABI, mais le programme n’y écrit plus. Les comptes existants on-chain sont des vestiges ; l’administrateur peut appeler CloseProtocolPosition pour en récupérer le rent.La comptabilité agrégée de plage est désormais dérivée directement des deux ticks extrémités (liquidity_gross, liquidity_net et les fee_growth_outside_* / reward_growths_outside_x64 par tick) dans TickArrayState. La formule de croissance des frais inside fee_growth_inside = global − outside_lower − outside_upper continue de fonctionner sans compte de position agrégé.

Observation

pub const OBSERVATION_NUM: usize = 100;

pub struct Observation {
    pub block_timestamp: u32,
    pub tick_cumulative: i64,                            // Σ tick_current × Δt
    pub padding:         [u64; 4],
}

pub struct ObservationState {
    pub initialized:       bool,
    pub recent_epoch:      u64,
    pub observation_index: u16,
    pub pool_id:           Pubkey,
    pub observations:      [Observation; OBSERVATION_NUM], // 100 entries
    pub padding:           [u64; 4],
}
Le buffer d’observation du CLMM stocke un tick cumulatif, et non un prix cumulatif. Les consommateurs externes calculent le prix moyen géométrique sur un intervalle à partir de (tick_cumulative[t1] − tick_cumulative[t0]) / (t1 − t0), puis appliquent price = 1.0001 ** tick. Voir algorithms/clmm-math.

DynamicFeeConfig et DynamicFeeInfo

Les paramètres de frais dynamiques se trouvent à deux endroits. Le modèle réutilisable — DynamicFeeConfig — est géré par l’administrateur et partagé entre les pools qui y adhèrent. L’état d’exécution par pool — DynamicFeeInfo — est intégré dans PoolState et mis à jour à chaque swap.

DynamicFeeConfig

// programs/amm/src/states/pool_fee.rs
pub struct DynamicFeeConfig {
    pub index:                       u16,    // identifier; PDA seed component
    pub filter_period:               u16,    // seconds — within this window the volatility reference is held
    pub decay_period:                u16,    // seconds — beyond this window the reference fully decays
    pub reduction_factor:            u16,    // fixed-point in [1, 10_000); applied at decay
    pub dynamic_fee_control:         u32,    // fixed-point in (0, 100_000); fee-rate gain
    pub max_volatility_accumulator:  u32,    // ceiling on the volatility accumulator
    pub padding:                     [u64; 8],
}
Seed PDA : ["dynamic_fee_config", index.to_be_bytes()]. Créé via create_dynamic_fee_config (réservé à l’administrateur) et modifié via update_dynamic_fee_config. Un pool créé avec enable_dynamic_fee = true copie les cinq paramètres de calibration de la config (filter_period, decay_period, reduction_factor, dynamic_fee_control, max_volatility_accumulator) dans son propre DynamicFeeInfo à la création ; les modifications ultérieures de DynamicFeeConfig n’affectent pas rétroactivement les pools existants.

DynamicFeeInfo (intégré dans PoolState)

pub struct DynamicFeeInfo {
    pub filter_period:                u16,
    pub decay_period:                 u16,
    pub reduction_factor:             u16,
    pub dynamic_fee_control:          u32,
    pub max_volatility_accumulator:   u32,
    pub tick_spacing_index_reference: i32,    // tick-spacing-units; reference for next swap
    pub volatility_reference:         u32,    // running floor for the accumulator
    pub volatility_accumulator:       u32,    // current cumulative volatility (capped)
    pub last_update_timestamp:        u64,
    pub padding:                      [u8; 46],
}
Les quatre derniers champs sont des données d’état ; les cinq premiers sont des paramètres de calibration copiés depuis DynamicFeeConfig. Le calcul des frais et les règles de décroissance sont documentés dans products/clmm/math et products/clmm/fees. Constantes utilisées par la formule :
ConstanteValeurSignification
VOLATILITY_ACCUMULATOR_SCALE10_000Granularité de l’accumulateur de volatilité
REDUCTION_FACTOR_DENOMINATOR10_000Dénominateur pour reduction_factor
DYNAMIC_FEE_CONTROL_DENOMINATOR100_000Dénominateur pour dynamic_fee_control
MAX_FEE_RATE_NUMERATOR100_000Plafond strict de 10% sur le taux de frais résultant

LimitOrderState

Un compte par ordre limite ouvert.
// programs/amm/src/states/limit_order.rs
pub struct LimitOrderState {
    pub pool_id:            Pubkey,
    pub owner:              Pubkey,
    pub tick_index:         i32,
    pub zero_for_one:       bool,    // direction: true sells token0 for token1
    pub order_phase:        u64,     // snapshot of TickState.order_phase at open time
    pub total_amount:       u64,     // input-token amount placed
    pub filled_amount:      u64,     // informational; computed precisely on settle
    pub settle_base:        u64,     // unfilled remainder at last settle/decrease
    pub settled_output:     u64,     // cumulative output-token paid to owner
    pub open_time:          u64,
    pub unfilled_ratio_x64: u128,    // Q64.64 snapshot of TickState.unfilled_ratio_x64 at open
    pub padding:            [u64; 4],
}
Cycle de vie :
  1. Ouverture — l’utilisateur appelle open_limit_order, dépose total_amount du token d’entrée ; l’ordre est lié à une cohorte TickState.
  2. (optionnel) Augmentation / Diminutionincrease_limit_order ajoute au total_amount ; decrease_limit_order restitue les tokens non exécutés (et tout output réglé jusqu’à ce point).
  3. Règlement — lorsque la cohorte est entièrement ou partiellement exécutée, le propriétaire ou le keeper opérationnel appelle settle_limit_order pour transférer les tokens de sortie vers l’ATA du propriétaire.
  4. Fermeture — une fois que unfilled_amount == 0, le compte peut être fermé. Le rent est toujours restitué au owner.
Seed PDA : [owner.as_ref(), limit_order_nonce.key().as_ref(), limit_order_nonce.order_nonce.to_be_bytes().as_ref()]. Le PDA d’ordre est donc unique par (owner, nonce_index, order_nonce).

LimitOrderNonce

Compteur par (wallet, nonce_index) permettant à un même utilisateur de gérer plusieurs pipelines parallèles d’ordres limites sans collision de PDAs.
pub struct LimitOrderNonce {
    pub user_wallet: Pubkey,
    pub nonce_index: u8,             // user-chosen, 0..255
    pub order_nonce: u64,            // monotonic, incremented every time a new order is opened
    pub padding:     [u64; 4],
}
Seed PDA : [user_wallet.as_ref(), &[nonce_index]]. La plupart des clients utilisent nonce_index = 0 et laissent order_nonce porter la cardinalité.

Dériver les comptes clés

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

const CLMM_PROGRAM_ID = new PublicKey(
  "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK"
); // see reference/program-addresses

function i32ToBytes(n: number): Buffer {
  const b = Buffer.alloc(4);
  b.writeInt32BE(n);
  return b;
}

export function deriveClmmAccounts(
  ammConfig: PublicKey,
  token0Mint: PublicKey,           // must already be sorted
  token1Mint: PublicKey,
) {
  const [poolState] = PublicKey.findProgramAddressSync(
    [Buffer.from("pool"), ammConfig.toBuffer(),
     token0Mint.toBuffer(), token1Mint.toBuffer()],
    CLMM_PROGRAM_ID,
  );
  const [observation] = PublicKey.findProgramAddressSync(
    [Buffer.from("observation"), poolState.toBuffer()],
    CLMM_PROGRAM_ID,
  );
  const [tickArrayBitmapExtension] = PublicKey.findProgramAddressSync(
    [Buffer.from("pool_tick_array_bitmap_extension"), poolState.toBuffer()],
    CLMM_PROGRAM_ID,
  );
  return { poolState, observation, tickArrayBitmapExtension };
}

export function deriveTickArray(
  pool: PublicKey,
  startTickIndex: number,
) {
  const [tickArray] = PublicKey.findProgramAddressSync(
    [Buffer.from("tick_array"), pool.toBuffer(), i32ToBytes(startTickIndex)],
    CLMM_PROGRAM_ID,
  );
  return tickArray;
}

export function deriveDynamicFeeConfig(index: number) {
  const idx = Buffer.alloc(2);
  idx.writeUInt16BE(index);
  const [pda] = PublicKey.findProgramAddressSync(
    [Buffer.from("dynamic_fee_config"), idx],
    CLMM_PROGRAM_ID,
  );
  return pda;
}

export function deriveLimitOrderNonce(
  wallet: PublicKey,
  nonceIndex: number,
) {
  const [pda] = PublicKey.findProgramAddressSync(
    [wallet.toBuffer(), Buffer.from([nonceIndex & 0xff])],
    CLMM_PROGRAM_ID,
  );
  return pda;
}

export function deriveLimitOrder(
  wallet: PublicKey,
  nonceAccount: PublicKey,
  orderNonce: bigint,
) {
  const nonceBytes = Buffer.alloc(8);
  nonceBytes.writeBigUInt64BE(orderNonce);
  const [pda] = PublicKey.findProgramAddressSync(
    [wallet.toBuffer(), nonceAccount.toBuffer(), nonceBytes],
    CLMM_PROGRAM_ID,
  );
  return pda;
}

export function derivePersonalPosition(nftMint: PublicKey) {
  const [personalPosition] = PublicKey.findProgramAddressSync(
    [Buffer.from("position"), nftMint.toBuffer()],
    CLMM_PROGRAM_ID,
  );
  return personalPosition;
}
Les chaînes de seeds exactes doivent toujours être vérifiées par rapport à l’IDL on-chain et à reference/program-addresses.

Référence rapide du cycle de vie

ÉvénementComptes créésComptes détruits
CreatePoolpoolState, observation, token_0_vault, token_1_vault
OpenPosition[WithToken22Nft]Mint NFT + ATA, personalPosition, éventuellement nouveaux tickArrayState(s), tickArrayBitmapExtension si inexistant
IncreaseLiquidityÉventuellement nouveaux tickArrayState(s)
DecreaseLiquidityEfface éventuellement des entrées de ticks (mais le tickArrayState lui-même n’est pas fermé)
ClosePositionMint NFT, personalPosition
SwapV2Éventuellement nouveau tickArrayState
OpenLimitOrderlimitOrderState, éventuellement limitOrderNonce (init-if-needed), éventuellement nouveau tickArrayState
IncreaseLimitOrder
DecreaseLimitOrderFerme limitOrderState si l’ordre est entièrement consommé
SettleLimitOrder
CloseLimitOrderlimitOrderState (rent → owner)
CreateDynamicFeeConfigdynamicFeeConfig
CreateCustomizablePoolpoolState, observation, vaults — identique à CreatePool. Copie dynamicFeeConfig si enable_dynamic_fee = true.
CollectRewards
UpdateRewardInfos
CloseProtocolPosition (admin)protocolPositionState vestigial (rent → admin)
Les comptes TickArrayState ne sont jamais fermés par le programme — ils persistent pour toute la durée de vie du pool. Une fois initialisé, un tableau de ticks reste on-chain même lorsque tous les ticks qu’il contient reviennent à liquidity_gross == 0. La réutilisation d’un tableau existant est gratuite ; seule la première position à toucher un tableau jamais initialisé acquitte son rent.

Où trouver quoi

Sources :