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