182 lines
7.4 KiB
Markdown
182 lines
7.4 KiB
Markdown
<!-- file: crates/ksp-offchain-transport-lib/USAGE.md -->
|
|
<!-- version: 2 -->
|
|
|
|
# Usage de ksp-offchain-transport-lib
|
|
|
|
Cette page documente la surface stable préparée pour `0.2.11`. Les credentials et documents runtime doivent normalement être résolus par `ksp-config-lib`; les constructions directes ci-dessous servent surtout aux tests, outils bas niveau et compositions programmatiques maîtrisées.
|
|
|
|
## 1. Construire un service programmatique
|
|
|
|
Un service reçoit une liste de `MarketPriceProviderSetup`. Le setup est provider-specific uniquement au moment de la composition :
|
|
|
|
```rust
|
|
let coingecko = ksp_offchain_transport_lib::MarketPriceCoinGeckoSettings::keyless(true)?;
|
|
let kraken = ksp_offchain_transport_lib::MarketPriceKrakenSettings::new(true)?;
|
|
let service = ksp_offchain_transport_lib::MarketPriceService::new(std::vec![
|
|
ksp_offchain_transport_lib::MarketPriceProviderSetup::CoinGecko(coingecko),
|
|
ksp_offchain_transport_lib::MarketPriceProviderSetup::Kraken(kraken),
|
|
])?;
|
|
```
|
|
|
|
Une application normale n'a pas à reproduire le mapping des huit providers. `ksp-config-lib::ResolvedOffchainTransportConfig` construit cette composition depuis `cfg.std.offchain_transport`.
|
|
|
|
## 2. Découvrir le registry générique
|
|
|
|
Après construction, le consumer travaille sur le registry sans matcher les variants provider :
|
|
|
|
```rust
|
|
for entry in service.registry().entries() {
|
|
let descriptor = entry.descriptor();
|
|
let state = entry.state();
|
|
println!(
|
|
"{} {:?} {:?}",
|
|
descriptor.display_name(),
|
|
descriptor.semantics(),
|
|
state.availability(),
|
|
);
|
|
}
|
|
```
|
|
|
|
Le `provider_id` est opaque. Il sert d'identité stable pour rappeler le service, pas de signal autorisant le consumer à reconstruire un endpoint ou une règle provider.
|
|
|
|
## 3. Rafraîchir un provider
|
|
|
|
```rust
|
|
let provider_id = ksp_offchain_transport_lib::MarketPriceProviderId::new("coingecko")?;
|
|
let outcome = service.refresh(&provider_id).await?;
|
|
```
|
|
|
|
L'outcome expose génériquement l'observation éventuelle et l'état provider. Une erreur provider normalisée n'oblige pas le consumer à parser CoinGecko, Kraken ou Jupiter.
|
|
|
|
Avant un refresh, l'état peut être consulté via le registry. `MarketPriceProviderAvailability::retry_at()` expose le prochain instant connu lorsqu'il existe réellement.
|
|
|
|
## 4. Rafraîchir plusieurs providers
|
|
|
|
```rust
|
|
let ids = service
|
|
.registry()
|
|
.entries()
|
|
.iter()
|
|
.map(|entry| return entry.descriptor().id().clone())
|
|
.collect::<std::vec::Vec<_>>();
|
|
let outcomes = service.refresh_many(ids.as_slice()).await?;
|
|
```
|
|
|
|
La V1 exécute ce batch **séquentiellement**, dans l'ordre demandé. Elle valide les IDs avant le premier dispatch, rejette les doublons, ne dort pas pour un cooldown et produit un outcome générique par provider lorsque l'opération est valide.
|
|
|
|
`refresh_all()` applique le même contrat dans l'ordre stable du registry :
|
|
|
|
```rust
|
|
let outcomes = service.refresh_all().await?;
|
|
```
|
|
|
|
Il n'existe pas de fallback, consensus ou moyenne implicite. Une application voulant comparer les observations doit conserver leurs sémantiques et provenances ; elle ne doit pas présenter leurs différences comme une erreur de KSP.
|
|
|
|
## 5. Construire depuis Config
|
|
|
|
La voie runtime normale est :
|
|
|
|
```rust
|
|
let resolved = engine.load_resolved_offchain_transport_config(
|
|
std::option::Option::None,
|
|
&environment,
|
|
)?;
|
|
let service = resolved.service();
|
|
let registry = service.registry();
|
|
```
|
|
|
|
Le profil `public_keyless` du document standard peut être résolu sans credentials. Le profil `all_free` attend les secrets/public fields inventoriés dans `.env.example` et validés par `ksp-config-lib`.
|
|
|
|
Off-chain Transport ne lit pas l'environnement lui-même. Ne passez pas un credential via une URL, une query arbitraire ou une surface UI libre pour contourner Config.
|
|
|
|
## 6. DexScreener
|
|
|
|
DexScreener doit recevoir la paire SOL/USD Solana explicitement approuvée par la composition lorsqu'il est activé :
|
|
|
|
```rust
|
|
let pair = ksp_core_lib::Pubkey::parse("<PAIR_ADDRESS_APPROUVEE>")?;
|
|
let settings = ksp_offchain_transport_lib::MarketPriceDexScreenerSettings::new(
|
|
true,
|
|
std::option::Option::Some(pair),
|
|
)?;
|
|
```
|
|
|
|
La paire n'est pas un secret. Aucun helper V1 ne découvre automatiquement une autre pool, ne trie par liquidité ou ne remplace la paire configurée.
|
|
|
|
## 7. Exactitude numérique
|
|
|
|
Ne convertissez pas l'observation canonique en `f64` pour la stocker ou la comparer comme vérité KSP. `MarketPriceDecimal` conserve une forme décimale exacte et sérialise une représentation canonique.
|
|
|
|
Pour l'affichage, un consumer peut utiliser sa représentation textuelle publique. Toute conversion approximative éventuelle appartient à une couche de présentation qui accepte explicitement cette perte ; elle ne doit pas remplacer le type canonique dans le transport.
|
|
|
|
## 8. Forward compatibility
|
|
|
|
Les enums publiques susceptibles d'évoluer sont `#[non_exhaustive]`. Hors de la crate, les matches doivent donc prévoir un fallback :
|
|
|
|
```rust
|
|
match entry.state().availability() {
|
|
ksp_offchain_transport_lib::MarketPriceProviderAvailability::Ready => {},
|
|
ksp_offchain_transport_lib::MarketPriceProviderAvailability::Disabled => {},
|
|
_ => {},
|
|
}
|
|
```
|
|
|
|
La branche `_` est intentionnelle : de nouveaux providers, états, sémantiques ou paires pourront être ajoutés sans imposer une rupture source aux consumers bien écrits.
|
|
|
|
## 9. Diagnostics sûrs
|
|
|
|
Les diagnostics applicatifs peuvent journaliser :
|
|
|
|
```text
|
|
provider_id validé
|
|
code d'erreur KSP
|
|
classe d'availability
|
|
retry_at borné lorsqu'il existe
|
|
durée/opération générique
|
|
```
|
|
|
|
Ils ne doivent pas journaliser :
|
|
|
|
```text
|
|
API key
|
|
URL complète sensible
|
|
header provider secret
|
|
body distant brut
|
|
payload de Config secret
|
|
```
|
|
|
|
`ksp-offchain-transport-lib` utilise `ksp-logging-lib` et son `TRACING_TARGET` propriétaire ; une application ne doit pas ajouter un bypass direct `tracing` pour obtenir les payloads rejetés.
|
|
|
|
## 10. Smokes live de release
|
|
|
|
Le smoke keyless final ne requiert aucun secret et couvre les sept modes V1 concernés :
|
|
|
|
```bash
|
|
cargo test -p ksp-offchain-transport-lib \
|
|
--test market_price_live_smoke \
|
|
keyless_market_price_providers_live_smoke \
|
|
-- --ignored --exact --nocapture --test-threads=1
|
|
```
|
|
|
|
Le gate `0.2.11-pre.011-fix.001` a passé ce smoke en `7/7`. Le test ne compare jamais les providers à un prix exact commun : il valide l'identité, la paire SOL/USD, la sémantique, un prix canonique positif et la cohérence des timestamps disponibles.
|
|
|
|
Le smoke keyed reste volontairement distinct. Il lit quatre clés sur `stdin`, dans l'ordre Birdeye, CoinGecko Demo, CoinMarketCap Basic et Jupiter Free :
|
|
|
|
```bash
|
|
printf '%s\n%s\n%s\n%s\n' \
|
|
"$KSP_SECRET_BIRDEYE_API_KEY" \
|
|
"$KSP_SECRET_COINGECKO_DEMO_API_KEY" \
|
|
"$KSP_SECRET_COINMARKETCAP_API_KEY" \
|
|
"$KSP_SECRET_JUPITER_API_KEY" \
|
|
| cargo test -p ksp-offchain-transport-lib \
|
|
--test market_price_live_smoke \
|
|
keyed_market_price_providers_live_smoke \
|
|
-- --ignored --exact --nocapture --test-threads=1
|
|
```
|
|
|
|
Ce second smoke peut être omis si l'opérateur ne possède pas les quatre credentials ; l'absence de credentials doit alors rester explicitement `SKIP opérateur`.
|
|
|
|
## 11. Statut documentaire
|
|
|
|
Ce document est la référence d'usage durable de la surface `market_price` livrée par `0.2.11`. Il ne promet ni prix identique entre providers, ni disponibilité permanente de leurs plans gratuits, ni compatibilité avec une surface provider qui changerait après la release.
|