# Delta `0.2.4-pre.007` — Economics simples + réaudit SIMD-0490/0550 ## Base requise Livraison précédente : ```text 0.2.4-pre.006 workspace.package.version = "0.2.4-pre.6" ``` Les validations locales fournies pour cette base sont propres : ```text cargo fmt --all -> terminé cargo check --workspace -> terminé sans warning cargo clippy --workspace --all-targets -> terminé sans warning cargo test -p ksp-onchain-transport-lib -> 221 unit tests OK 24 public API tests OK 19 release-completeness tests OK 1 smoke Devnet ignoré comme prévu 0 échec ``` ## Objectif Matérialiser les quatre wrappers Economics simples prévus par le plan `0.2.4` : ```text getInflationGovernor getInflationRate getStakeMinimumDelegation getSupply ``` `getInflationReward` reste volontairement réservé à `pre.008`. Les cinq descriptors Economics sont déjà enregistrés sous : ```text V0_2_4 / Economics / Read / RetrySafe ``` Le registre central n'est pas modifié. ## Réaudit primaire SIMD-0490 — Upgrade BPF Stake Program to v5.0.0 Le document courant reste au statut : ```text Review ``` Il prévoit notamment : ```text minimum delegation : 1 lamport -> 1 SOL validator support : exposer le nouveau minimum via le RPC de minimum delegation ``` Ce statut ne conduit à aucune constante KSP. Le cross-audit Agave stable `v4.2.1` est plus important pour Transport : le runtime `getStakeMinimumDelegation` appelle déjà : ```text stake_utils::get_minimum_delegation( bank.feature_set.snapshot().upgrade_bpf_stake_program_to_v5 ) ``` La valeur RPC est donc déjà sélectionnée par l'état runtime du feature set. Conséquence KSP : ```text aucun minimum 1 lamport codé en dur aucun minimum 1 SOL codé en dur aucune validation locale de la valeur retour exact du u64 fourni par le runtime ``` La fixture HTTP utilise volontairement une valeur arbitraire `42_424_242` lamports pour empêcher une canary de dépendre d'une valeur économique supposée. ## Réaudit primaire SIMD-0550 — Double Disinflation Rate Le document courant reste au statut : ```text Review ``` Il précise explicitement que : ```text getInflationRate getInflationGovernor ``` reflètent la nouvelle schedule lorsqu'elle est active, mais qu'il n'y a : ```text aucun changement d'API ``` Conséquence KSP : - `SolanaInflationGovernor` reste un DTO de valeurs runtime `f64`; - `SolanaInflationRate` reste un DTO de valeurs runtime `f64` + epoch; - Transport ne réimplémente aucune formule d'inflation; - Transport ne code en dur ni `taper = 0.15`, ni `taper = 0.30`; - Transport ne recalcule pas `initial`; - les fixtures utilisent des valeurs non canoniques/arbitraires afin de détecter une future normalisation locale indésirable. Le plan `011` décrivait déjà cette politique correctement et reste byte-identique en version 4. ## Version Cargo Nouvelle prerelease technique : ```text 0.2.4-pre.6 -> 0.2.4-pre.7 ``` Aucune dépendance ni feature Cargo n'est ajoutée ou modifiée. ## `getInflationGovernor` Surface publique : ```text HttpTransportPool::get_inflation_governor( role, Option<&SolanaCommitmentConfig>, ) -> Result ``` Formes wire retenues : ```text None / config vide -> params: [] config commitment -> params: [{"commitment":"..."}] ``` Le runtime accepte son `CommitmentConfig` général. KSP n'invente donc aucune restriction `confirmed/finalized`; une canary envoie explicitement : ```text commitment = processed ``` La réponse est décodée dans : ```text initial terminal taper foundation foundationTerm ``` sans post-traitement économique. ## `getInflationRate` Surface publique : ```text HttpTransportPool::get_inflation_rate( role, ) -> Result ``` La requête est exactement : ```text params: [] ``` La réponse conserve : ```text total validator foundation epoch ``` sans recalcul local. ## `getStakeMinimumDelegation` Surface publique : ```text HttpTransportPool::get_stake_minimum_delegation( role, Option<&SolanaContextConfig>, ) -> Result> ``` Les options stables sont réutilisées depuis le contrat commun : ```text commitment minContextSlot ``` `None` et une config explicitement vide sont canoniquement omis. Une config complète avec : ```text commitment = processed minContextSlot = 431000000 ``` est couverte et la réponse contextualisée conserve : ```text context.slot context.apiVersion value: u64 ``` `MinContextSlotNotReached` reste une erreur RPC applicative et n'est pas convertie en erreur de décodage KSP. ## `getSupply` Surface publique : ```text HttpTransportPool::get_supply( role, Option<&SolanaSupplyConfig>, ) -> Result> ``` La config conserve : ```text commitment excludeNonCirculatingAccountsList ``` Le booléen KSP reste `Option` afin de distinguer dans la requête : ```text omis false true ``` `None` et une config entièrement vide sont canoniquement omis car le runtime leur applique les mêmes défauts. Une valeur `false` explicite reste envoyée comme : ```json {"excludeNonCirculatingAccountsList":false} ``` Une valeur `true` explicite reste envoyée comme : ```json {"excludeNonCirculatingAccountsList":true} ``` Lorsque `true`, Agave retourne volontairement : ```text nonCirculatingAccounts = [] ``` sans modifier la signification des totaux retournés. KSP préserve cette liste vide telle quelle. Le résultat contextualisé conserve : ```text total circulating nonCirculating nonCirculatingAccounts ``` Les adresses de `nonCirculatingAccounts` sont validées/typées en `Pubkey` sans fuite de la valeur fautive dans les diagnostics. Une `ScanError` runtime de `getSupply` reste une erreur RPC applicative. ## Discipline `#[cfg(test)]` La politique introduite par `pre.002-fix.001` est maintenue. Deviennent runtime uniquement parce qu'ils ont maintenant un consommateur réel : ```text SolanaInflationGovernor::decode_wire SolanaInflationRate::decode_wire SolanaSupplyConfig::is_empty SolanaSupplyConfig::to_json_value SolanaSupply::decode_wire WireInflationGovernor WireInflationRate WireSupply WireEconomicsRpcResponse ``` Restent sous `#[cfg(test)]` jusqu'à `pre.008` : ```text SolanaInflationRewardConfig::{is_empty,to_json_value} SolanaInflationReward::decode_wire WireInflationReward ``` Aucun `#[allow(dead_code)]` n'est ajouté. ## Chemin d'exécution Les quatre wrappers utilisent une seule frontière privée : ```text economics_descriptor -> HttpTransportPool::execute_standard_rpc ``` Le helper de descriptor exige : ```text category = Economics coverage_release = V0_2_4 ``` Transport ne crée aucun chemin HTTP parallèle et ne dépend toujours ni de Config, ni Store, ni Program, ni d'un client RPC Solana haut niveau. ## Fixtures et tests Nouvelles fixtures HTTP : ```text get_inflation_governor.success.json get_inflation_rate.success.json get_stake_minimum_delegation.success.json get_stake_minimum_delegation.error_min_context.json get_supply.success.json get_supply.excluded.success.json get_supply.error_scan.json ``` Dix nouveaux tests unitaires couvrent : ```text getInflationGovernor config processed + valeurs runtime getInflationGovernor config absente/vide getInflationRate params vides + valeurs runtime getStakeMinimumDelegation config contextuelle + valeur arbitraire getStakeMinimumDelegation config absente/vide getStakeMinimumDelegation MinContextSlotNotReached getSupply false explicite + liste complète + contexte getSupply true explicite + liste runtime vide getSupply config absente/vide getSupply ScanError ``` Canary public API : ```text public_v0_2_4_pre_007_simple_economics_wrappers_are_available_from_crate_root ``` Canary release : ```text release_v0_2_4_pre_007_simple_economics_subset_is_exact_and_retry_safe ``` Elle fixe exactement les quatre wrappers de cette tranche sans avancer `getInflationReward`. Compteurs attendus après validation locale : ```text 231 unit tests 25 public API tests 20 release-completeness tests 1 smoke Devnet ignoré ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-onchain-transport-lib/src/rpc_economics.rs crates/ksp-onchain-transport-lib/unit_tests/rpc_economics.rs crates/ksp-onchain-transport-lib/tests/public_api.rs crates/ksp-onchain-transport-lib/tests/release_completeness.rs ``` ## Fichiers ajoutés ```text crates/ksp-onchain-transport-lib/fixtures/http/get_inflation_governor.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_inflation_rate.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_stake_minimum_delegation.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_stake_minimum_delegation.error_min_context.json crates/ksp-onchain-transport-lib/fixtures/http/get_supply.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_supply.excluded.success.json crates/ksp-onchain-transport-lib/fixtures/http/get_supply.error_scan.json deltas/0.2.4/pre.007.md ``` ## Non-objectifs Cette tranche n'implémente pas : ```text getInflationReward ``` Elle ne modifie pas non plus : - les 10 wrappers Blocks déjà acquis; - les 37 wrappers `0.2.1`–`0.2.3`; - le registre des 52 current + 14 historical; - les règles de retry; - le smoke Devnet; - les dépendances ou features Cargo; - le plan `011`, déjà correct pour ce scope. ## Validation attendue ```bash cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-onchain-transport-lib ``` Résultat attendu : ```text 0 warning introduit 231 unit tests OK 25 public API tests OK 20 release-completeness tests OK 1 smoke Devnet ignoré 0 échec ``` ## Commit attendu ```text v0.2.4-pre.007 ``` ## Suite `0.2.4-pre.008` reste dédiée à : ```text getInflationReward ``` avec : ```text ordre et cardinalité des adresses null positionnels epoch / commitment / minContextSlot commission nullable commissionBps SIMD-0291 absence de limite d'adresses inventée invariants de réponse ``` Puis `pre.009` effectuera le réaudit SIMD/inventaire et la compliance HTTP finale `52/52 + 14/14`.