Files
khadhroony-solana-project/deltas/0.2.11/pre.006.md
2026-08-25 23:06:26 +02:00

244 lines
7.2 KiB
Markdown

<!-- file: deltas/0.2.11/pre.006.md -->
<!-- version: 1 -->
# Delta `0.2.11-pre.006` — Jupiter Price V3 + DexScreener
## 1. Base requise
Cette tranche s'applique exclusivement après `0.2.11-pre.005` accepté par l'opérateur.
Version Cargo attendue à l'entrée :
```text
0.2.11-pre.5
```
Version Cargo de sortie :
```text
0.2.11-pre.6
```
Le gate d'entrée ciblé du `2026-08-25` est PASS : `cargo fmt --all`, audit Rust clean avec 0 candidate export, audit Markdown clean à 119 tables / 110 fichiers, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test -p ksp-offchain-transport-lib` avec 37 unitaires + 3 boundary + 4 public API. `cargo test --workspace` n'a pas été rejoué sur l'état exact `pre.005` avant le passage explicite à cette tranche.
## 2. Objet strict de la tranche
`pre.006` ajoute uniquement les deux providers prévus par le forecast :
```text
Jupiter Price V3
DexScreener
```
Le contrat reste :
```text
SOL/USD uniquement
HTTP REST direct via reqwest
aucun SDK provider
aucune découverte automatique de pool
aucun fallback/consensus/agrégation KSP
pas de registry global
pas de Config
pas de refresh multiple
pas de smoke live revendiqué
```
## 3. Jupiter Price V3
Ajout de :
```text
market_price_jupiter.rs
unit_tests/market_price_jupiter.rs
MarketPriceJupiterAccessMode
MarketPriceJupiterSettings
MarketPriceJupiterProvider
```
Le réaudit officiel courant confirme le Developer Platform unifié :
```text
base URL https://api.jup.ag
endpoint /price/v3
mint SOL So11111111111111111111111111111111111111112
keyless 0.5 RPS
Free avec API key 1 RPS
header keyed x-api-key
```
Les deux modes utilisent la même origine officielle. Le mode keyless n'accepte aucun credential ; le mode Free exige une clé lorsqu'il est activé. La clé reste dans `MarketPriceApiKey`, n'est jamais lue depuis l'environnement par cette crate et n'apparaît pas dans `Debug`, les logs ou les erreurs.
Price V3 expose `usdPrice` comme prix USD unique. KSP le lit via `serde_json::RawValue` puis `MarketPriceDecimal`, sans passage canonique par `f64`.
Le contrat V3 expose également `blockId`, qui peut servir à raisonner sur la récence du prix. KSP le conserve uniquement dans la provenance sûre :
```text
jupiter:price_v3:<mint>:block:<blockId>
```
`createdAt` décrit la création du token et n'est pas un timestamp de prix. `blockId` n'est pas un timestamp non plus. L'observation conserve donc explicitement :
```text
provider_timestamp = None
MarketPriceSemantics::SolanaHeuristic
```
Le parser exige la clé exacte du mint WSOL, `decimals = 9`, un `usdPrice` présent et positif, et un `blockId` présent. Une réponse sans prix est une réponse provider non exploitable pour une observation réussie ; le registry/availability générique sera matérialisé en `pre.007`.
## 4. DexScreener
Ajout de :
```text
market_price_dexscreener.rs
unit_tests/market_price_dexscreener.rs
MarketPriceDexScreenerSettings
MarketPriceDexScreenerProvider
```
Le V1 suit strictement la décision opérateur : un client SOL/USD lié à **une paire Solana explicitement configurée**.
L'endpoint officiel utilisé est uniquement :
```text
https://api.dexscreener.com/latest/dex/pairs/solana/{pairId}
```
La documentation DexScreener le borne actuellement à :
```text
300 requêtes / minute
```
Le pair address est validé comme `ksp_core_lib::Pubkey` dans les settings. Le client construit le chemin à partir de l'origine officielle fixe et du seul segment Pubkey validé ; aucune base URL configurable n'est introduite.
Avant d'accepter `priceUsd`, le parser vérifie :
```text
une seule paire retournée
chainId = solana
pairAddress = pair address configuré
baseToken.address = So11111111111111111111111111111111111111112
priceUsd présent et exact
```
KSP ne consulte pas :
```text
/latest/dex/search
/token-pairs/v1
/tokens/v1
```
et ne fait aucun pool discovery, ranking de liquidité, sélection automatique, moyenne ou consensus.
La provenance conserve le pair address, considéré comme sûr :
```text
dexscreener:solana:<pairAddress>:priceUsd
```
La sémantique publique reste :
```text
MarketPriceSemantics::DexPairUsd
provider_timestamp = None
```
## 5. HTTP commun
`HttpGetRequest` gagne uniquement une primitive crate-private :
```text
append_path_segment
```
Elle permet de construire un endpoint provider à origine fixe lorsque le contrat nécessite un segment dynamique validé, ici le Pubkey de la paire DexScreener. Cette évolution ne crée aucune API HTTP publique et ne permet pas au consumer de fournir une URL arbitraire.
## 6. Façade publique
La taxonomie reste capability-scoped :
```text
MarketPriceJupiter*
MarketPriceDexScreener*
```
Aucun type wire provider, client HTTP générique ou primitive d'admission n'est exporté aux consumers.
Le futur `ksp-app-solprices-desk` ne devra pas construire ces settings provider directement ; `pre.009` donnera cette responsabilité à Config et le service générique prévu en `pre.007`/`pre.008` masquera les variantes provider à l'HID.
## 7. Tests déterministes ajoutés
Les nouveaux canaries couvrent :
```text
Jupiter keyless 0.5 RPS
Jupiter Free 1 RPS + API key redacted
query Jupiter fixée au mint WSOL
Jupiter prix exact via RawValue
Jupiter blockId conservé en provenance
Jupiter provider_timestamp absent
Jupiter prix absent rejeté
Jupiter identité/decimals incohérents rejetés
DexScreener pair address Pubkey explicite
URL pair directe construite sans discovery
DexScreener 300 req/min
chainId Solana vérifié
pairAddress retourné vérifié
base token WSOL vérifié
priceUsd exact
réponse multi-pair rejetée
prix absent rejeté
absence des endpoints search/token discovery
façade publique des deux adapters
```
## 8. Documentation réconciliée
Mise à jour de :
```text
docs/plans/018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md
docs/validation/014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md
```
Le plan enregistre également le réaudit Jupiter/DexScreener courant et distingue explicitement `blockId` Jupiter d'un timestamp provider.
## 9. Fichiers ajoutés
```text
crates/ksp-offchain-transport-lib/src/market_price_dexscreener.rs
crates/ksp-offchain-transport-lib/src/market_price_jupiter.rs
crates/ksp-offchain-transport-lib/unit_tests/market_price_dexscreener.rs
crates/ksp-offchain-transport-lib/unit_tests/market_price_jupiter.rs
deltas/0.2.11/pre.006.md
```
## 10. Fichiers modifiés
```text
Cargo.toml
crates/ksp-offchain-transport-lib/src/http_client.rs
crates/ksp-offchain-transport-lib/src/lib.rs
crates/ksp-offchain-transport-lib/tests/dependency_boundary.rs
crates/ksp-offchain-transport-lib/tests/public_api.rs
docs/plans/018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md
docs/validation/014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md
```
## 11. Validation attendue
```bash
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.11
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-offchain-transport-lib
cargo test --workspace
```
`pre.007` ne doit commencer qu'après un gate propre de `pre.006` ou un delta fix explicite.