Files
khadhroony-solana-project/deltas/0.2.11/pre.007.md
2026-08-26 10:06:21 +02:00

281 lines
8.0 KiB
Markdown

<!-- file: deltas/0.2.11/pre.007.md -->
<!-- version: 1 -->
# Delta `0.2.11-pre.007` — Birdeye + registry + availability
## 1. Base requise
Cette tranche s'applique exclusivement après `0.2.11-pre.006` accepté par l'opérateur.
Version Cargo attendue à l'entrée :
```text
0.2.11-pre.6
```
Version Cargo de sortie :
```text
0.2.11-pre.7
```
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 à 120 tables / 111 fichiers, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test -p ksp-offchain-transport-lib` avec 43 unitaires + 4 boundary + 5 public API. `cargo test --workspace` n'a pas été rejoué sur l'état exact `pre.006` avant le passage explicite à cette tranche.
## 2. Objet strict de la tranche
`pre.007` ferme l'inventaire V1 des huit providers et matérialise le registry provider-neutral :
```text
Birdeye Standard
MarketPriceProviderRegistry
MarketPriceProviderRegistryEntry
availability générique consultable
metadata de coût provider informatif
```
La tranche n'ajoute pas encore :
```text
refresh(provider_id)
refresh multiple/all
service de dispatch provider
Config Off-chain Transport
smoke live
fallback/consensus
```
## 3. Birdeye Standard
Ajout de :
```text
market_price_birdeye.rs
unit_tests/market_price_birdeye.rs
MarketPriceBirdeyeSettings
MarketPriceBirdeyeProvider
```
Le réaudit officiel courant confirme :
```text
base URL https://public-api.birdeye.so
endpoint GET /defi/price
mint SOL So11111111111111111111111111111111111111112
chain header x-chain: solana
auth header X-API-KEY
Standard 0 USD, 30 000 compute units inclus
limite compte 1 RPS
Price Single 3 compute units par appel
```
Une clé Birdeye est obligatoire lorsque le provider est activé. Un provider désactivé peut être construit sans secret afin que Config et le futur service puissent représenter un état non actif sans inventer de credential.
La clé reste dans `MarketPriceApiKey`, n'est jamais lue directement depuis l'environnement par Off-chain Transport et n'apparaît ni dans `Debug`, ni dans les logs, ni dans les erreurs.
Le request builder utilise uniquement l'origine officielle fixe, le mint WSOL fixe et `x-chain = solana`.
La réponse Price Single est normalisée depuis :
```text
data.value
data.updateUnixTime
success
```
`data.value` passe par `serde_json::RawValue` puis `MarketPriceDecimal` sans round-trip `f64`. `updateUnixTime` devient un vrai `provider_timestamp` en secondes Unix converties en millisecondes.
La sémantique retenue est :
```text
MarketPriceSemantics::SolanaSpot
```
La provenance sûre est :
```text
birdeye:solana:wsol:value
```
Une réponse `success = false`, un prix absent/null, un timestamp absent/pathologique ou un JSON incompatible sont rejetés sans copier le body distant dans les diagnostics.
## 4. Quota et coût provider informatifs
Birdeye utilise des compute units. Pour ne pas les confondre avec des crédits abstraits ou des requêtes HTTP, `MarketPriceProviderQuotaUnit` gagne :
```text
ComputeUnits
```
`MarketPriceProviderRequestCost` représente un coût unitaire documenté pour l'opération SOL/USD courante.
Le descriptor Birdeye expose :
```text
long_term_quota = 30 000 ComputeUnits / Month
sol_usd_request_cost = 3 ComputeUnits
```
Ces valeurs sont informatives. KSP ne décrémente pas localement le quota et ne prétend pas connaître un solde authoritative : un autre processus ou une autre API du même compte peut consommer les mêmes compute units.
`MarketPriceProviderDescriptor::with_sol_usd_request_cost` vérifie que le coût et le quota utilisent la même unité lorsqu'un quota est présent.
## 5. Registry provider-neutral
Ajout de :
```text
market_price_registry.rs
unit_tests/market_price_registry.rs
MarketPriceProviderRegistry
MarketPriceProviderRegistryEntry
ERROR_CODE_MARKET_PRICE_REGISTRY_INVALID
```
Une entrée contient seulement :
```text
MarketPriceProviderDescriptor
MarketPriceProviderState
```
Le registry :
```text
est borné à 64 entrées
trie les entrées par provider_id
rejette les provider_id dupliqués
permet lookup descriptor/state/entry par identifiant opaque
expose une slice déterministe d'entrées
ne contient aucun nom ou dispatch provider spécifique
```
Le constructeur reste public et provider-neutral, comme `MarketPriceProviderDescriptor::new` déjà existant. Cela ne donne aucun accès à un endpoint ou à un client HTTP. Le futur service `pre.008` possédera les transitions runtime et le dispatch des adapters ; la HID ne devra pas construire ou matcher des providers spécifiques.
Un canari de complétude construit les huit adapters V1 en mode désactivé et vérifie l'inventaire ordonné :
```text
birdeye
coinbase_exchange
coingecko
coinmarketcap
coinpaprika
dexscreener
jupiter
kraken
```
## 6. Availability générique
`MarketPriceProviderAvailability` gagne deux helpers publics provider-neutral :
```text
is_refresh_eligible()
retry_at()
```
Ils permettent à un consumer d'interpréter `Ready`, `CoolingDown` ou `TemporarilyUnavailable` sans parser des erreurs ni connaître le fournisseur.
Les catégories existantes restent distinctes :
```text
AuthenticationUnavailable
CoolingDown
Disabled
Misconfigured
QuotaUnavailable
Ready
TemporarilyUnavailable
```
`pre.007` ne relie pas encore automatiquement les erreurs d'un refresh à ces transitions. Cette mutation runtime appartient au service de `pre.008`.
## 7. Façade publique
La taxonomie reste capability-scoped :
```text
MarketPriceBirdeye*
MarketPriceProviderRegistry*
MarketPriceProviderRequestCost
```
Aucun DTO wire Birdeye, `HttpRestClient`, limiter interne ou primitive `reqwest` n'est exporté.
Le registry public reste générique ; aucun consumer n'a besoin d'un enum CoinGecko/Birdeye/Jupiter pour l'inspecter.
## 8. Tests déterministes ajoutés
Les nouveaux canaries couvrent :
```text
Birdeye API key obligatoire si enabled
redaction du secret Birdeye
endpoint fixe et headers attendus
mint WSOL fixe
1 RPS par compte
30 000 compute units informatifs
3 compute units par Price Single
prix exact via RawValue
updateUnixTime -> provider_timestamp
success false rejeté
prix null rejeté
timestamp absent rejeté
request cost nul rejeté
mismatch unité quota/coût rejeté
registry des huit providers complet
ordre déterministe du registry
doublons provider_id rejetés
lookup descriptor/state générique
availability is_refresh_eligible/retry_at
absence de noms provider dans le module registry
```
## 9. 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 le réaudit Birdeye courant et précise que quotas/cost metadata restent non-authoritative.
## 10. Fichiers ajoutés
```text
crates/ksp-offchain-transport-lib/src/market_price_birdeye.rs
crates/ksp-offchain-transport-lib/src/market_price_registry.rs
crates/ksp-offchain-transport-lib/unit_tests/market_price_birdeye.rs
crates/ksp-offchain-transport-lib/unit_tests/market_price_registry.rs
deltas/0.2.11/pre.007.md
```
## 11. Fichiers modifiés
```text
Cargo.toml
crates/ksp-offchain-transport-lib/src/error.rs
crates/ksp-offchain-transport-lib/src/lib.rs
crates/ksp-offchain-transport-lib/src/market_price_provider.rs
crates/ksp-offchain-transport-lib/tests/dependency_boundary.rs
crates/ksp-offchain-transport-lib/tests/public_api.rs
crates/ksp-offchain-transport-lib/unit_tests/market_price_provider.rs
docs/plans/018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md
docs/validation/014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md
```
## 12. 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.008` ne doit commencer qu'après un gate propre de `pre.007` ou un delta fix explicite.