244 lines
7.2 KiB
Markdown
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.
|