Skip to main content

tycho_simulation/rfq/
constants.rs

1use std::{env, str::FromStr};
2
3use tycho_common::Bytes;
4
5use crate::rfq::errors::RFQError;
6
7pub const DEFAULT_METRIC_API_URL: &str = "https://api.metric.xyz";
8
9/// Hashflow authentication configuration
10pub struct HashflowAuth {
11    pub user: String,
12    pub key: String,
13}
14
15/// Bebop authentication configuration
16pub struct BebopAuth {
17    pub key: String,
18}
19
20/// Metric API configuration
21pub struct MetricConfig {
22    pub base_url: String,
23    pub api_key: Option<String>,
24}
25
26/// Read Hashflow authentication from environment variables
27/// Returns the HASHFLOW_USER and HASHFLOW_KEY environment variables
28pub fn get_hashflow_auth() -> Result<HashflowAuth, RFQError> {
29    let user = env::var("HASHFLOW_USER").map_err(|_| {
30        RFQError::InvalidInput("HASHFLOW_USER environment variable is required".into())
31    })?;
32
33    let key = env::var("HASHFLOW_KEY").map_err(|_| {
34        RFQError::InvalidInput("HASHFLOW_KEY environment variable is required".into())
35    })?;
36
37    Ok(HashflowAuth { user, key })
38}
39
40/// Native Relay authentication configuration
41pub struct NativeAuth {
42    pub key: String,
43}
44
45/// Read Native Relay authentication from environment variables.
46/// Returns the NATIVE_API_KEY environment variable.
47pub fn get_native_auth() -> Result<NativeAuth, RFQError> {
48    let key = env::var("NATIVE_API_KEY").map_err(|_| {
49        RFQError::InvalidInput("NATIVE_API_KEY environment variable is required".into())
50    })?;
51
52    Ok(NativeAuth { key })
53}
54/// Liquorice authentication configuration
55pub struct LiquoriceAuth {
56    pub solver: String,
57    pub key: String,
58}
59
60/// Read Liquorice authentication from environment variables
61/// Returns the LIQUORICE_USER and LIQUORICE_KEY environment variables
62pub fn get_liquorice_auth() -> Result<LiquoriceAuth, RFQError> {
63    let solver = env::var("LIQUORICE_USER").map_err(|_| {
64        RFQError::InvalidInput("LIQUORICE_USER environment variable is required".into())
65    })?;
66
67    let key = env::var("LIQUORICE_KEY").map_err(|_| {
68        RFQError::InvalidInput("LIQUORICE_KEY environment variable is required".into())
69    })?;
70
71    Ok(LiquoriceAuth { solver, key })
72}
73
74/// Read Bebop authentication from environment variables
75/// Returns the BEBOP_KEY environment variable
76pub fn get_bebop_auth() -> Result<BebopAuth, RFQError> {
77    let key = env::var("BEBOP_KEY")
78        .map_err(|_| RFQError::InvalidInput("BEBOP_KEY environment variable is required".into()))?;
79
80    Ok(BebopAuth { key })
81}
82
83/// Bebop origin identification, sent with binding quote requests. Bebop can configure API
84/// accounts to require these fields. See the `BebopClientBuilder` docs for their meaning.
85#[derive(Debug, Default)]
86pub struct BebopOrigins {
87    pub address: Option<Bytes>,
88    pub target: Option<Bytes>,
89    pub source: Option<String>,
90}
91
92/// Read optional Bebop origin identification from the BEBOP_ORIGIN_ADDRESS,
93/// BEBOP_ORIGIN_TARGET and BEBOP_ORIGIN_SOURCE environment variables.
94///
95/// Unset variables yield `None`; a set but unparseable address is an error.
96pub fn get_bebop_origins() -> Result<BebopOrigins, RFQError> {
97    let parse_address = |var: &str| -> Result<Option<Bytes>, RFQError> {
98        match env::var(var) {
99            Ok(value) => Bytes::from_str(&value)
100                .map(Some)
101                .map_err(|e| RFQError::InvalidInput(format!("Invalid {var}: {e}"))),
102            Err(_) => Ok(None),
103        }
104    };
105    Ok(BebopOrigins {
106        address: parse_address("BEBOP_ORIGIN_ADDRESS")?,
107        target: parse_address("BEBOP_ORIGIN_TARGET")?,
108        source: env::var("BEBOP_ORIGIN_SOURCE").ok(),
109    })
110}
111
112/// Read Metric API configuration from environment variables.
113/// METRIC_API_URL defaults to the public Metric endpoint; METRIC_API_KEY is the Bearer trading key
114/// required by the authenticated endpoints (`bid_ask`).
115pub fn get_metric_config() -> MetricConfig {
116    let base_url = env::var("METRIC_API_URL")
117        .ok()
118        .filter(|url| !url.trim().is_empty())
119        .unwrap_or_else(|| DEFAULT_METRIC_API_URL.to_string());
120    let api_key = env::var("METRIC_API_KEY")
121        .ok()
122        .filter(|key| !key.trim().is_empty());
123
124    MetricConfig { base_url, api_key }
125}
126
127#[cfg(test)]
128mod tests {
129    use std::env;
130
131    use super::*;
132
133    #[test]
134    fn test_hashflow_auth_success() {
135        env::set_var("HASHFLOW_USER", "test_user");
136        env::set_var("HASHFLOW_KEY", "test_key");
137
138        let auth = get_hashflow_auth().unwrap();
139        assert_eq!(auth.user, "test_user");
140        assert_eq!(auth.key, "test_key");
141
142        env::remove_var("HASHFLOW_USER");
143        env::remove_var("HASHFLOW_KEY");
144    }
145
146    #[test]
147    fn test_hashflow_auth_missing_user() {
148        env::remove_var("HASHFLOW_USER");
149        env::set_var("HASHFLOW_KEY", "test_key");
150
151        let result = get_hashflow_auth();
152        assert!(result.is_err());
153
154        env::remove_var("HASHFLOW_KEY");
155    }
156
157    #[test]
158    fn test_hashflow_auth_missing_key() {
159        env::set_var("HASHFLOW_USER", "test_user");
160        env::remove_var("HASHFLOW_KEY");
161
162        let result = get_hashflow_auth();
163        assert!(result.is_err());
164
165        env::remove_var("HASHFLOW_USER");
166    }
167
168    #[test]
169    fn test_bebop_auth_success() {
170        env::set_var("BEBOP_KEY", "test_key");
171
172        let auth = get_bebop_auth().unwrap();
173        assert_eq!(auth.key, "test_key");
174
175        env::remove_var("BEBOP_KEY");
176    }
177
178    #[test]
179    fn test_bebop_auth_missing_key() {
180        env::remove_var("BEBOP_KEY");
181
182        let result = get_bebop_auth();
183        assert!(result.is_err());
184    }
185
186    #[test]
187    fn test_metric_config_defaults_and_reads_env() {
188        env::remove_var("METRIC_API_URL");
189        env::remove_var("METRIC_API_KEY");
190
191        let config = get_metric_config();
192        assert_eq!(config.base_url, DEFAULT_METRIC_API_URL);
193        assert_eq!(config.api_key, None);
194
195        env::set_var("METRIC_API_URL", "https://metric.example");
196        env::set_var("METRIC_API_KEY", "secret");
197
198        let config = get_metric_config();
199        assert_eq!(config.base_url, "https://metric.example");
200        assert_eq!(config.api_key.as_deref(), Some("secret"));
201
202        env::remove_var("METRIC_API_URL");
203        env::remove_var("METRIC_API_KEY");
204    }
205}