Skip to main content

hypercall/price_oracle/
hydromancer_types.rs

1use serde::{Deserialize, Serialize};
2
3/// Request body for the oraclePriceHistoryByTime endpoint.
4///
5/// POST to https://api.hydromancer.xyz/info
6#[derive(Debug, Clone, Serialize)]
7#[serde(rename_all = "camelCase")]
8pub struct OraclePriceHistoryRequest {
9    #[serde(rename = "type")]
10    pub request_type: String,
11    pub coin: String,
12    pub start_time: i64,
13    pub end_time: i64,
14    pub limit: i32,
15}
16
17impl OraclePriceHistoryRequest {
18    pub fn new(coin: String, start_time: i64, end_time: i64) -> Self {
19        Self {
20            request_type: "oraclePriceHistoryByTime".to_string(),
21            coin,
22            start_time,
23            end_time,
24            limit: 2000,
25        }
26    }
27}
28
29/// A single price record from Hydromancer's oracle price history.
30#[derive(Debug, Clone, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct HydromancerPriceRecord {
33    pub time: i64,
34    pub dex: String,
35    pub coin: String,
36    pub oracle_px: Option<String>,
37    pub mark_px: Option<String>,
38    pub ext_perp_px: Option<String>,
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn test_deserialize_price_record() {
47        let json = r#"{
48            "time": 1710000000000,
49            "dex": "Hyperliquid",
50            "coin": "BTC",
51            "oraclePx": "70346.95",
52            "markPx": "70350.00",
53            "extPerpPx": "70348.00"
54        }"#;
55
56        let record: HydromancerPriceRecord = serde_json::from_str(json).unwrap();
57        assert_eq!(record.time, 1710000000000);
58        assert_eq!(record.dex, "Hyperliquid");
59        assert_eq!(record.coin, "BTC");
60        assert_eq!(record.oracle_px, Some("70346.95".to_string()));
61        assert_eq!(record.mark_px, Some("70350.00".to_string()));
62        assert_eq!(record.ext_perp_px, Some("70348.00".to_string()));
63    }
64
65    #[test]
66    fn test_deserialize_null_oracle_px() {
67        let json = r#"{
68            "time": 1710000000000,
69            "dex": "Hyperliquid",
70            "coin": "BTC",
71            "oraclePx": null,
72            "markPx": "70350.00",
73            "extPerpPx": null
74        }"#;
75
76        let record: HydromancerPriceRecord = serde_json::from_str(json).unwrap();
77        assert_eq!(record.oracle_px, None);
78        assert_eq!(record.ext_perp_px, None);
79    }
80
81    #[test]
82    fn test_serialize_request() {
83        let request =
84            OraclePriceHistoryRequest::new("BTC".to_string(), 1710000000000, 1710001800000);
85
86        let json = serde_json::to_value(&request).unwrap();
87        assert_eq!(json["type"], "oraclePriceHistoryByTime");
88        assert_eq!(json["coin"], "BTC");
89        assert_eq!(json["startTime"], 1710000000000i64);
90        assert_eq!(json["endTime"], 1710001800000i64);
91        assert_eq!(json["limit"], 2000);
92    }
93
94    #[test]
95    fn test_deserialize_vec_of_records() {
96        let json = r#"[
97            {
98                "time": 1710000000000,
99                "dex": "Hyperliquid",
100                "coin": "BTC",
101                "oraclePx": "70346.95",
102                "markPx": "70350.00",
103                "extPerpPx": "70348.00"
104            },
105            {
106                "time": 1710000002000,
107                "dex": "Hyperliquid",
108                "coin": "BTC",
109                "oraclePx": "70347.50",
110                "markPx": "70351.00",
111                "extPerpPx": null
112            }
113        ]"#;
114
115        let records: Vec<HydromancerPriceRecord> = serde_json::from_str(json).unwrap();
116        assert_eq!(records.len(), 2);
117        assert_eq!(records[0].oracle_px, Some("70346.95".to_string()));
118        assert_eq!(records[1].oracle_px, Some("70347.50".to_string()));
119        assert_eq!(records[1].ext_perp_px, None);
120    }
121}