// file: crates/ksp-offchain-transport-lib/tests/public_api.rs // version: 10 #![warn(missing_docs)] #![deny(unreachable_pub)] #![forbid(unsafe_code)] //! Public API canaries for the market-price foundation and stable Off-chain Transport error-code surface. #[test] fn public_pre_002_market_price_foundation_is_available_from_crate_root() -> ksp_core_lib::Result<()> { assert_eq!(ksp_offchain_transport_lib::MarketPricePair::SolUsd.code(), "SOL/USD"); assert_eq!(ksp_offchain_transport_lib::MARKET_PRICE_DECIMAL_MAX_SCALE, 18); let price = match ksp_offchain_transport_lib::MarketPriceDecimal::parse("201.2500") { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(price.to_canonical_string(), "201.25"); let id = match ksp_offchain_transport_lib::MarketPriceProviderId::new("provider-canary") { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let common = ksp_offchain_transport_lib::MarketPriceProviderCommonSettings::new(id.clone(), true); assert_eq!(common.provider_id(), &id); let rate_limit = match ksp_offchain_transport_lib::MarketPriceProviderRateLimit::fixed( 1, 1, std::option::Option::None, ksp_offchain_transport_lib::MarketPriceProviderRateLimitScope::Ip, ) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let descriptor = match ksp_offchain_transport_lib::MarketPriceProviderDescriptor::new( id.clone(), "Provider Canary", ksp_offchain_transport_lib::MarketPriceSemantics::AggregatedMarket, ksp_offchain_transport_lib::MarketPriceProviderAuthMode::None, rate_limit, std::option::Option::None, true, ) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert!(descriptor.supports_sol_usd()); let provenance = match ksp_offchain_transport_lib::MarketPriceProvenance::new("canary") { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let timestamp = ksp_offchain_transport_lib::MarketPriceTimestamp::from_unix_millis(1); let observation = match ksp_offchain_transport_lib::MarketPriceObservation::new( id, price, ksp_offchain_transport_lib::MarketPriceSemantics::AggregatedMarket, timestamp, timestamp, std::option::Option::None, provenance, ) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(observation.price(), price); return std::result::Result::Ok(()); } #[test] fn public_pre_004_aggregator_settings_and_adapters_are_available_from_crate_root() -> ksp_core_lib::Result<()> { let coingecko = match ksp_offchain_transport_lib::MarketPriceCoinGeckoSettings::keyless(false) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let coingecko_provider = match ksp_offchain_transport_lib::MarketPriceCoinGeckoProvider::new(coingecko) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(coingecko_provider.descriptor().id().as_str(), "coingecko"); let coinmarketcap = match ksp_offchain_transport_lib::MarketPriceCoinMarketCapSettings::keyless(false) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let coinmarketcap_provider = match ksp_offchain_transport_lib::MarketPriceCoinMarketCapProvider::new(coinmarketcap) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(coinmarketcap_provider.descriptor().id().as_str(), "coinmarketcap"); let coinpaprika = match ksp_offchain_transport_lib::MarketPriceCoinPaprikaSettings::new(false) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let coinpaprika_provider = match ksp_offchain_transport_lib::MarketPriceCoinPaprikaProvider::new(coinpaprika) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(coinpaprika_provider.descriptor().id().as_str(), "coinpaprika"); return std::result::Result::Ok(()); } #[test] fn public_pre_005_exchange_settings_and_adapters_are_available_from_crate_root() -> ksp_core_lib::Result<()> { let kraken = match ksp_offchain_transport_lib::MarketPriceKrakenSettings::new(false) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let kraken_provider = match ksp_offchain_transport_lib::MarketPriceKrakenProvider::new(kraken) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(kraken_provider.descriptor().id().as_str(), "kraken"); assert_eq!(kraken_provider.descriptor().semantics(), ksp_offchain_transport_lib::MarketPriceSemantics::ExchangeLastTrade); let coinbase = match ksp_offchain_transport_lib::MarketPriceCoinbaseExchangeSettings::new(false) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let coinbase_provider = match ksp_offchain_transport_lib::MarketPriceCoinbaseExchangeProvider::new(coinbase) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(coinbase_provider.descriptor().id().as_str(), "coinbase_exchange"); assert_eq!(coinbase_provider.descriptor().semantics(), ksp_offchain_transport_lib::MarketPriceSemantics::ExchangeLastTrade); return std::result::Result::Ok(()); } #[test] fn public_pre_006_jupiter_and_dexscreener_settings_and_adapters_are_available_from_crate_root() -> ksp_core_lib::Result<()> { let jupiter = match ksp_offchain_transport_lib::MarketPriceJupiterSettings::keyless(false) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let jupiter_provider = match ksp_offchain_transport_lib::MarketPriceJupiterProvider::new(jupiter) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(jupiter_provider.descriptor().id().as_str(), "jupiter"); assert_eq!(jupiter_provider.descriptor().semantics(), ksp_offchain_transport_lib::MarketPriceSemantics::SolanaHeuristic); let dexscreener = match ksp_offchain_transport_lib::MarketPriceDexScreenerSettings::new(false, std::option::Option::None) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let dexscreener_provider = match ksp_offchain_transport_lib::MarketPriceDexScreenerProvider::new(dexscreener) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(dexscreener_provider.descriptor().id().as_str(), "dexscreener"); assert_eq!(dexscreener_provider.descriptor().semantics(), ksp_offchain_transport_lib::MarketPriceSemantics::DexPairUsd); return std::result::Result::Ok(()); } #[test] fn public_pre_007_birdeye_and_provider_registry_are_available_from_crate_root() -> ksp_core_lib::Result<()> { let settings = match ksp_offchain_transport_lib::MarketPriceBirdeyeSettings::new(false, std::option::Option::None) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let provider = match ksp_offchain_transport_lib::MarketPriceBirdeyeProvider::new(settings) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(provider.descriptor().id().as_str(), "birdeye"); assert_eq!(provider.descriptor().semantics(), ksp_offchain_transport_lib::MarketPriceSemantics::SolanaSpot); let request_cost = match provider.descriptor().sol_usd_request_cost() { std::option::Option::Some(value) => value, std::option::Option::None => { return std::result::Result::Err(ksp_core_lib::Error::new( ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_PROVIDER_DESCRIPTOR_INVALID, "Birdeye descriptor is missing request-cost metadata", )); }, }; assert_eq!(request_cost.amount(), 3); assert_eq!(request_cost.unit(), ksp_offchain_transport_lib::MarketPriceProviderQuotaUnit::ComputeUnits); let ready = ksp_offchain_transport_lib::MarketPriceProviderAvailability::Ready; assert!(ready.is_refresh_eligible()); assert_eq!(ready.retry_at(), std::option::Option::None); let entry = ksp_offchain_transport_lib::MarketPriceProviderRegistryEntry::new(provider.descriptor().clone(), ready); let registry = match ksp_offchain_transport_lib::MarketPriceProviderRegistry::new(std::vec![entry]) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(registry.len(), 1); assert_eq!(registry.entries()[0].descriptor().id().as_str(), "birdeye"); return std::result::Result::Ok(()); } #[tokio::test] async fn public_pre_008_generic_refresh_service_is_available_without_provider_branching_at_callsite() -> ksp_core_lib::Result<()> { let settings = match ksp_offchain_transport_lib::MarketPriceCoinPaprikaSettings::new(false) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let service = match ksp_offchain_transport_lib::MarketPriceService::new(std::vec![ksp_offchain_transport_lib::MarketPriceProviderSetup::CoinPaprika(settings),]) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let registry = service.registry(); let provider_id = registry.entries()[0].descriptor().id().clone(); let outcome = match service.refresh(&provider_id).await { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; assert_eq!(outcome.provider_id(), &provider_id); assert!(!outcome.refreshed()); assert_eq!(outcome.state().availability(), ksp_offchain_transport_lib::MarketPriceProviderAvailability::Disabled); return std::result::Result::Ok(()); } #[test] fn offchain_error_codes_use_owned_domain() { let codes = [ ksp_offchain_transport_lib::ERROR_CODE_HTTP_ACCESS_DENIED, ksp_offchain_transport_lib::ERROR_CODE_HTTP_ADMISSION_DEFERRED, ksp_offchain_transport_lib::ERROR_CODE_HTTP_CLIENT_BUILD_FAILED, ksp_offchain_transport_lib::ERROR_CODE_HTTP_CONNECTION_FAILED, ksp_offchain_transport_lib::ERROR_CODE_HTTP_INVALID_JSON, ksp_offchain_transport_lib::ERROR_CODE_HTTP_RATE_LIMIT_INVALID, ksp_offchain_transport_lib::ERROR_CODE_HTTP_RATE_LIMITED, ksp_offchain_transport_lib::ERROR_CODE_HTTP_REQUEST_FAILED, ksp_offchain_transport_lib::ERROR_CODE_HTTP_REQUEST_INVALID, ksp_offchain_transport_lib::ERROR_CODE_HTTP_RESPONSE_TOO_LARGE, ksp_offchain_transport_lib::ERROR_CODE_HTTP_SETTINGS_INVALID, ksp_offchain_transport_lib::ERROR_CODE_HTTP_TEMPORARY_FAILURE, ksp_offchain_transport_lib::ERROR_CODE_HTTP_TIMEOUT, ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_DECIMAL_INVALID, ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_PROVIDER_DESCRIPTOR_INVALID, ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_PROVIDER_DISABLED, ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_PROVIDER_ID_INVALID, ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_PROVIDER_NOT_FOUND, ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_PROVIDER_RESPONSE_INVALID, ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_OBSERVATION_INVALID, ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_PROVIDER_SETTINGS_INVALID, ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_REFRESH_INVALID, ksp_offchain_transport_lib::ERROR_CODE_MARKET_PRICE_REGISTRY_INVALID, ]; for code in codes { assert_eq!(code.domain(), "offchain_transport"); } }