8.0 KiB
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 :
0.2.11-pre.6
Version Cargo de sortie :
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 :
Birdeye Standard
MarketPriceProviderRegistry
MarketPriceProviderRegistryEntry
availability générique consultable
metadata de coût provider informatif
La tranche n'ajoute pas encore :
refresh(provider_id)
refresh multiple/all
service de dispatch provider
Config Off-chain Transport
smoke live
fallback/consensus
3. Birdeye Standard
Ajout de :
market_price_birdeye.rs
unit_tests/market_price_birdeye.rs
MarketPriceBirdeyeSettings
MarketPriceBirdeyeProvider
Le réaudit officiel courant confirme :
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 :
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 :
MarketPriceSemantics::SolanaSpot
La provenance sûre est :
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 :
ComputeUnits
MarketPriceProviderRequestCost représente un coût unitaire documenté pour l'opération SOL/USD courante.
Le descriptor Birdeye expose :
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 :
market_price_registry.rs
unit_tests/market_price_registry.rs
MarketPriceProviderRegistry
MarketPriceProviderRegistryEntry
ERROR_CODE_MARKET_PRICE_REGISTRY_INVALID
Une entrée contient seulement :
MarketPriceProviderDescriptor
MarketPriceProviderState
Le registry :
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é :
birdeye
coinbase_exchange
coingecko
coinmarketcap
coinpaprika
dexscreener
jupiter
kraken
6. Availability générique
MarketPriceProviderAvailability gagne deux helpers publics provider-neutral :
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 :
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 :
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 :
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 :
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
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
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
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.