1use std::time::Duration;
2
3#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
5#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
6#[serde(rename_all = "lowercase")]
7pub enum MarketStatusFilter {
8 Active,
9 Closed,
10 Resolved,
11 All,
12}
13
14impl std::fmt::Display for MarketStatusFilter {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 match self {
17 MarketStatusFilter::Active => write!(f, "active"),
18 MarketStatusFilter::Closed => write!(f, "closed"),
19 MarketStatusFilter::Resolved => write!(f, "resolved"),
20 MarketStatusFilter::All => write!(f, "all"),
21 }
22 }
23}
24
25impl std::str::FromStr for MarketStatusFilter {
26 type Err = String;
27
28 fn from_str(s: &str) -> Result<Self, Self::Err> {
29 match s.to_lowercase().as_str() {
30 "active" | "open" => Ok(MarketStatusFilter::Active),
31 "closed" | "inactive" | "paused" => Ok(MarketStatusFilter::Closed),
32 "resolved" | "settled" | "determined" | "finalized" => Ok(MarketStatusFilter::Resolved),
33 "all" => Ok(MarketStatusFilter::All),
34 _ => Err(format!("Unknown market status filter: {}", s)),
35 }
36 }
37}
38
39impl From<crate::models::MarketStatus> for MarketStatusFilter {
40 fn from(s: crate::models::MarketStatus) -> Self {
41 match s {
42 crate::models::MarketStatus::Active => MarketStatusFilter::Active,
43 crate::models::MarketStatus::Closed => MarketStatusFilter::Closed,
44 crate::models::MarketStatus::Resolved => MarketStatusFilter::Resolved,
45 }
46 }
47}
48
49#[derive(Debug, Clone)]
50pub struct ExchangeConfig {
51 pub timeout: Duration,
52 pub rate_limit_per_second: u32,
53 pub max_retries: u32,
54 pub retry_delay: Duration,
55 pub verbose: bool,
56}
57
58impl Default for ExchangeConfig {
59 fn default() -> Self {
60 Self {
61 timeout: Duration::from_secs(30),
62 rate_limit_per_second: 10,
63 max_retries: 3,
64 retry_delay: Duration::from_secs(1),
65 verbose: false,
66 }
67 }
68}
69
70impl ExchangeConfig {
71 pub fn new() -> Self {
72 Self::default()
73 }
74
75 pub fn with_timeout(mut self, timeout: Duration) -> Self {
76 self.timeout = timeout;
77 self
78 }
79
80 pub fn with_rate_limit(mut self, requests_per_second: u32) -> Self {
81 self.rate_limit_per_second = requests_per_second;
82 self
83 }
84
85 pub fn with_retries(mut self, max_retries: u32, delay: Duration) -> Self {
86 self.max_retries = max_retries;
87 self.retry_delay = delay;
88 self
89 }
90
91 pub fn with_verbose(mut self, verbose: bool) -> Self {
92 self.verbose = verbose;
93 self
94 }
95}
96
97#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
99#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
100pub struct FetchMarketsParams {
101 pub limit: Option<usize>,
103 #[serde(default)]
105 pub cursor: Option<String>,
106 #[serde(default)]
108 pub status: Option<MarketStatusFilter>,
109 #[serde(default)]
111 pub market_tickers: Vec<String>,
112 #[serde(default)]
114 pub series_ticker: Option<String>,
115 #[serde(default)]
117 pub event_ticker: Option<String>,
118}
119
120#[derive(Debug, Clone)]
154pub struct PolymarketCredentials {
155 pub private_key: Option<String>,
156 pub funder: Option<String>,
157 pub api_key: Option<String>,
158 pub api_secret: Option<String>,
159 pub api_passphrase: Option<String>,
160 pub signature_type: String,
161}
162
163impl PolymarketCredentials {
164 pub fn from_fields(
170 private_key: Option<String>,
171 funder: Option<String>,
172 api_key: Option<String>,
173 api_secret: Option<String>,
174 api_passphrase: Option<String>,
175 signature_type: Option<String>,
176 ) -> Self {
177 let resolved_signature_type = signature_type.unwrap_or_else(|| {
179 if funder.is_some() {
180 "GnosisSafe".to_string()
181 } else {
182 "EOA".to_string()
183 }
184 });
185
186 Self {
187 private_key,
188 funder,
189 api_key,
190 api_secret,
191 api_passphrase,
192 signature_type: resolved_signature_type,
193 }
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use crate::models::MarketStatus;
201
202 #[test]
203 fn market_status_filter_from_str() {
204 assert_eq!(
205 "active".parse::<MarketStatusFilter>().unwrap(),
206 MarketStatusFilter::Active
207 );
208 assert_eq!(
209 "open".parse::<MarketStatusFilter>().unwrap(),
210 MarketStatusFilter::Active
211 );
212 assert_eq!(
213 "closed".parse::<MarketStatusFilter>().unwrap(),
214 MarketStatusFilter::Closed
215 );
216 assert_eq!(
217 "resolved".parse::<MarketStatusFilter>().unwrap(),
218 MarketStatusFilter::Resolved
219 );
220 assert_eq!(
221 "settled".parse::<MarketStatusFilter>().unwrap(),
222 MarketStatusFilter::Resolved
223 );
224 assert_eq!(
225 "all".parse::<MarketStatusFilter>().unwrap(),
226 MarketStatusFilter::All
227 );
228 assert_eq!(
229 "ALL".parse::<MarketStatusFilter>().unwrap(),
230 MarketStatusFilter::All
231 );
232 assert!("invalid".parse::<MarketStatusFilter>().is_err());
233 }
234
235 #[test]
236 fn market_status_filter_display() {
237 assert_eq!(MarketStatusFilter::Active.to_string(), "active");
238 assert_eq!(MarketStatusFilter::Closed.to_string(), "closed");
239 assert_eq!(MarketStatusFilter::Resolved.to_string(), "resolved");
240 assert_eq!(MarketStatusFilter::All.to_string(), "all");
241 }
242
243 #[test]
244 fn market_status_filter_from_market_status() {
245 assert_eq!(
246 MarketStatusFilter::from(MarketStatus::Active),
247 MarketStatusFilter::Active
248 );
249 assert_eq!(
250 MarketStatusFilter::from(MarketStatus::Closed),
251 MarketStatusFilter::Closed
252 );
253 assert_eq!(
254 MarketStatusFilter::from(MarketStatus::Resolved),
255 MarketStatusFilter::Resolved
256 );
257 }
258
259 #[test]
260 fn market_status_filter_serde_roundtrip() {
261 let filter = MarketStatusFilter::All;
262 let json = serde_json::to_string(&filter).unwrap();
263 assert_eq!(json, "\"all\"");
264 let parsed: MarketStatusFilter = serde_json::from_str(&json).unwrap();
265 assert_eq!(parsed, MarketStatusFilter::All);
266 }
267
268 #[test]
269 fn fetch_markets_params_default_status_is_none() {
270 let params = FetchMarketsParams::default();
271 assert!(params.status.is_none());
272 }
273
274 #[test]
275 fn fetch_markets_params_serde_with_all_status() {
276 let params = FetchMarketsParams {
277 status: Some(MarketStatusFilter::All),
278 ..Default::default()
279 };
280 let json = serde_json::to_value(¶ms).unwrap();
281 assert_eq!(json["status"], "all");
282
283 let parsed: FetchMarketsParams = serde_json::from_value(json).unwrap();
284 assert_eq!(parsed.status, Some(MarketStatusFilter::All));
285 }
286}
287
288#[derive(Debug, Clone)]
289pub struct KalshiCredentials {
290 pub api_key_id: String,
291 pub private_key: String,
292}