v0.2.11-pre.009

This commit is contained in:
2026-08-26 11:23:01 +02:00
parent 2fdff17651
commit 69294a153f
27 changed files with 1864 additions and 133 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-offchain-transport-lib/src/market_price_dexscreener.rs
// version: 1
// version: 2
//! DexScreener SOL/USD adapter bound to one explicitly configured Solana pair address.
@@ -11,19 +11,26 @@ const DEXSCREENER_SOL_MINT: &str = "So11111111111111111111111111111111111111112"
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MarketPriceDexScreenerSettings {
common: crate::MarketPriceProviderCommonSettings,
pair_address: ksp_core_lib::Pubkey,
pair_address: std::option::Option<ksp_core_lib::Pubkey>,
}
impl crate::MarketPriceDexScreenerSettings {
/// Creates DexScreener settings for one explicit Solana pair address.
pub fn new(enabled: bool, pair_address: impl std::convert::Into<std::string::String>) -> ksp_core_lib::Result<Self> {
/// Creates DexScreener settings for one optional explicit Solana pair address.
///
/// An enabled provider requires a valid pair address. A disabled provider may omit it so Config does not need to fabricate provider data merely to keep the
/// provider visible in the generic registry.
pub fn new(enabled: bool, pair_address: std::option::Option<std::string::String>) -> ksp_core_lib::Result<Self> {
let provider_id = match crate::MarketPriceProviderId::new(DEXSCREENER_PROVIDER_ID) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let pair_address = match pair_address.into().parse::<ksp_core_lib::Pubkey>() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return std::result::Result::Err(provider_settings_error("pair_address")),
let pair_address = match pair_address {
std::option::Option::Some(value) => match value.parse::<ksp_core_lib::Pubkey>() {
std::result::Result::Ok(value) => std::option::Option::Some(value),
std::result::Result::Err(_) => return std::result::Result::Err(provider_settings_error("pair_address")),
},
std::option::Option::None if enabled => return std::result::Result::Err(provider_settings_error("pair_address")),
std::option::Option::None => std::option::Option::None,
};
let common = crate::MarketPriceProviderCommonSettings::new(provider_id, enabled);
return std::result::Result::Ok(Self { common, pair_address });
@@ -35,10 +42,10 @@ impl crate::MarketPriceDexScreenerSettings {
return &self.common;
}
/// Returns the explicit Solana pair address used by this adapter.
/// Returns the explicit Solana pair address when one is configured.
#[must_use]
pub const fn pair_address(&self) -> &ksp_core_lib::Pubkey {
return &self.pair_address;
pub const fn pair_address(&self) -> std::option::Option<&ksp_core_lib::Pubkey> {
return self.pair_address.as_ref();
}
}
@@ -84,11 +91,15 @@ impl crate::MarketPriceDexScreenerProvider {
if let std::result::Result::Err(error) = crate::admit_request(DEXSCREENER_PROVIDER_ID, &self.admission) {
return std::result::Result::Err(error);
}
let pair_address = match self.settings.pair_address() {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(provider_settings_error("pair_address")),
};
let request_started_at = match crate::current_timestamp() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let request = match build_request(self.settings.pair_address()) {
let request = match build_request(pair_address) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
@@ -100,13 +111,7 @@ impl crate::MarketPriceDexScreenerProvider {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return parse_response(
document.as_bytes(),
self.settings.common().provider_id().clone(),
self.settings.pair_address(),
request_started_at,
received_at,
);
return parse_response(document.as_bytes(), self.settings.common().provider_id().clone(), pair_address, request_started_at, received_at);
}
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-offchain-transport-lib/tests/public_api.rs
// version: 9
// version: 10
#![warn(missing_docs)]
#![deny(unreachable_pub)]
@@ -134,7 +134,7 @@ fn public_pre_006_jupiter_and_dexscreener_settings_and_adapters_are_available_fr
};
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, "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE") {
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),
};

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-offchain-transport-lib/unit_tests/market_price_dexscreener.rs
// version: 1
// version: 2
const TEST_PAIR: &str = "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE";
@@ -35,13 +35,26 @@ fn dexscreener_fixture_validates_chain_pair_and_sol_identity_and_maps_exact_pair
#[test]
fn dexscreener_settings_and_descriptor_keep_pair_explicit_and_pair_endpoint_rate_limited() -> ksp_core_lib::Result<()> {
assert!(crate::MarketPriceDexScreenerSettings::new(true, "not-a-pubkey").is_err());
let settings = match crate::MarketPriceDexScreenerSettings::new(true, TEST_PAIR) {
let disabled = crate::MarketPriceDexScreenerSettings::new(false, std::option::Option::None);
assert!(disabled.is_ok(), "disabled DexScreener settings must not require a fake pair address: {disabled:?}");
assert!(crate::MarketPriceDexScreenerSettings::new(true, std::option::Option::Some("not-a-pubkey".to_owned())).is_err());
let settings = match crate::MarketPriceDexScreenerSettings::new(true, std::option::Option::Some(TEST_PAIR.to_owned())) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
assert_eq!(settings.pair_address().to_string(), TEST_PAIR);
let request = match super::build_request(settings.pair_address()) {
let pair_address = settings.pair_address();
assert!(pair_address.is_some(), "enabled DexScreener settings should retain the configured pair");
let pair_address = match pair_address {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(ksp_core_lib::Error::new(
crate::ERROR_CODE_MARKET_PRICE_PROVIDER_SETTINGS_INVALID,
"enabled DexScreener settings lost their pair address",
));
},
};
assert_eq!(pair_address.to_string(), TEST_PAIR);
let request = match super::build_request(pair_address) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-offchain-transport-lib/unit_tests/market_price_registry.rs
// version: 1
// version: 2
#[test]
fn registry_orders_all_eight_v1_providers_and_exposes_only_generic_entries() -> ksp_core_lib::Result<()> {
@@ -91,7 +91,7 @@ fn all_v1_entries() -> ksp_core_lib::Result<std::vec::Vec<crate::MarketPriceProv
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let dexscreener_settings = match crate::MarketPriceDexScreenerSettings::new(false, "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE") {
let dexscreener_settings = match crate::MarketPriceDexScreenerSettings::new(false, std::option::Option::None) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-offchain-transport-lib/unit_tests/market_price_service.rs
// version: 1
// version: 2
#[test]
fn service_registry_orders_all_eight_v1_setups_and_keeps_runtime_projection_generic() -> ksp_core_lib::Result<()> {
@@ -118,7 +118,7 @@ fn all_disabled_setups() -> ksp_core_lib::Result<std::vec::Vec<crate::MarketPric
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let dexscreener = match crate::MarketPriceDexScreenerSettings::new(false, "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE") {
let dexscreener = match crate::MarketPriceDexScreenerSettings::new(false, std::option::Option::None) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};