|
| 1 | +//! Solver-engine configuration. |
| 2 | +
|
| 3 | +use {serde::Deserialize, std::path::Path, url::Url}; |
| 4 | + |
| 5 | +/// Jupiter solver configuration. |
| 6 | +#[derive(Debug, Clone, Deserialize)] |
| 7 | +#[serde(rename_all = "kebab-case", deny_unknown_fields)] |
| 8 | +pub struct Config { |
| 9 | + pub dex: JupiterConfig, |
| 10 | +} |
| 11 | + |
| 12 | +/// The `[dex]` table for the Jupiter backend. The subcommand selects the |
| 13 | +/// engine, so there is no per-aggregator sub-table. |
| 14 | +#[derive(Debug, Clone, Deserialize)] |
| 15 | +#[serde(rename_all = "kebab-case", deny_unknown_fields)] |
| 16 | +pub struct JupiterConfig { |
| 17 | + /// Base URL of the Jupiter swap API (`api.jup.ag`) or a Triton-hosted Metis |
| 18 | + /// endpoint. |
| 19 | + pub endpoint: Url, |
| 20 | + |
| 21 | + /// API key from the Jupiter developer portal (or Triton). Requests work |
| 22 | + /// without one but are heavily rate-limited, so set it for production. |
| 23 | + #[serde(default)] |
| 24 | + pub api_key: Option<String>, |
| 25 | + |
| 26 | + /// Slippage tolerance in basis points, sent to Jupiter as `slippageBps`. |
| 27 | + /// 50 = 0.5%. |
| 28 | + pub slippage_bps: u16, |
| 29 | + |
| 30 | + /// Whether buy orders (Jupiter `ExactOut`) are served. Off by default. |
| 31 | + #[serde(default)] |
| 32 | + pub enable_buy_orders: bool, |
| 33 | +} |
| 34 | + |
| 35 | +/// Load and parse the TOML config file. |
| 36 | +/// |
| 37 | +/// # Panics |
| 38 | +/// |
| 39 | +/// Panics on I/O or parse errors: a bad config is a startup failure. |
| 40 | +pub async fn load(path: &Path) -> Config { |
| 41 | + let text = tokio::fs::read_to_string(path) |
| 42 | + .await |
| 43 | + .unwrap_or_else(|err| panic!("read config {}: {err}", path.display())); |
| 44 | + toml::from_str(&text).unwrap_or_else(|err| panic!("parse config {}: {err}", path.display())) |
| 45 | +} |
| 46 | + |
| 47 | +#[cfg(test)] |
| 48 | +mod tests { |
| 49 | + use super::*; |
| 50 | + |
| 51 | + #[test] |
| 52 | + fn parses_example_config() { |
| 53 | + let config: Config = |
| 54 | + toml::from_str(include_str!("../config/example.jupiter.toml")).unwrap(); |
| 55 | + assert_eq!(config.dex.endpoint.as_str(), "https://api.jup.ag/"); |
| 56 | + assert_eq!(config.dex.slippage_bps, 50); |
| 57 | + assert!(!config.dex.enable_buy_orders); |
| 58 | + assert!(config.dex.api_key.is_some()); |
| 59 | + } |
| 60 | + |
| 61 | + #[test] |
| 62 | + fn rejects_unknown_keys() { |
| 63 | + let toml = r#" |
| 64 | +[dex] |
| 65 | +endpoint = "https://api.jup.ag" |
| 66 | +slippage-bps = 50 |
| 67 | +bogus = true |
| 68 | +"#; |
| 69 | + assert!(toml::from_str::<Config>(toml).is_err()); |
| 70 | + } |
| 71 | +} |
0 commit comments