dydx_v3_rust/modules/
eth_private.rs

1pub use super::super::types::*;
2use super::super::{ResponseError, Result};
3use super::eth_sign::*;
4use chrono::Utc;
5use http::{Method, StatusCode};
6use serde::Deserialize;
7use std::time::Duration;
8
9#[derive(Debug, Clone)]
10pub struct EthPrivate<'a> {
11    client: reqwest::Client,
12    host: &'a str,
13    network_id: usize,
14    eth_private_key: &'a str,
15}
16
17impl EthPrivate<'_> {
18    pub fn new<'a>(host: &'a str, network_id: usize, api_timeout: u64, eth_private_key: &'a str) -> EthPrivate<'a> {
19        EthPrivate {
20            client: reqwest::ClientBuilder::new()
21                .timeout(Duration::from_secs(api_timeout))
22                .build()
23                .expect("Client::new()"),
24            host,
25            network_id,
26            eth_private_key,
27        }
28    }
29
30    pub async fn recovery(&self, ethereum_address: &str) -> Result<RecoveryResponse> {
31        let response = self
32            .request("recovery", Method::GET, ethereum_address)
33            .await;
34        response
35    }
36
37    pub async fn create_api_key(
38        &self,
39        ethereum_address: &str,
40    ) -> Result<ApiKeyCredentialsResponse> {
41        let response = self
42            .request("api-keys", Method::POST, ethereum_address)
43            .await;
44        response
45    }
46
47    pub async fn delete_api_key(
48        &self,
49        api_key: &str,
50        ethereum_address: &str,
51    ) -> Result<StatusCode> {
52        let parameter = vec![("apiKey", api_key)];
53        let response = self.delete("api-keys", ethereum_address, parameter).await;
54        response
55    }
56
57    async fn request<T: for<'de> Deserialize<'de>>(
58        &self,
59        path: &str,
60        method: Method,
61        ethereum_address: &str,
62    ) -> Result<T> {
63        let iso_timestamp = Utc::now().format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string();
64
65        let request_path = format!("/v3/{}", path);
66
67        let signature = sign_private(
68            self.network_id,
69            ethereum_address,
70            method.as_str(),
71            request_path.as_str(),
72            "{}",
73            &iso_timestamp,
74            self.eth_private_key,
75        )
76        .unwrap();
77
78        let url = format!("{}/v3/{}", &self.host, path);
79
80        let req_builder = match method {
81            Method::GET => self.client.get(url),
82            Method::POST => self.client.post(url),
83            _ => self.client.get(url),
84        };
85
86        let req_builder = req_builder
87            .header("DYDX-SIGNATURE", signature.as_str())
88            .header("DYDX-TIMESTAMP", iso_timestamp.as_str())
89            .header("DYDX-ETHEREUM-ADDRESS", ethereum_address);
90
91        let response = req_builder.send().await;
92
93        match response {
94            Ok(response) => match response.status() {
95                StatusCode::OK | StatusCode::CREATED => {
96                    return Ok(response.json::<T>().await.unwrap())
97                }
98                _ => {
99                    let error = ResponseError {
100                        code: response.status().to_string(),
101                        message: response.text().await.unwrap(),
102                    };
103                    return Err(Box::new(error));
104                }
105            },
106            Err(err) => {
107                return Err(Box::new(err));
108            }
109        };
110    }
111
112    async fn delete(
113        &self,
114        path: &str,
115        ethereum_address: &str,
116        parameters: Vec<(&str, &str)>,
117    ) -> Result<StatusCode> {
118        let request_path = if parameters.len() == 0 {
119            format!("/v3/{}", &path)
120        } else {
121            let request_path = format!("/v3/{}", &path);
122            let dummy_url = reqwest::Url::parse_with_params("https://example.net", &parameters);
123            format!("{}?{}", request_path, dummy_url.unwrap().query().unwrap())
124        };
125        let iso_timestamp = Utc::now().format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string();
126
127        let signature = sign_private(
128            self.network_id,
129            ethereum_address,
130            "DELETE",
131            request_path.as_str(),
132            "{}",
133            &iso_timestamp,
134            self.eth_private_key,
135        )
136        .unwrap();
137
138        let url = format!("{}/v3/{}", &self.host, path);
139
140        let req_builder = self.client.delete(url);
141
142        let req_builder = req_builder
143            .header("DYDX-SIGNATURE", signature.as_str())
144            .header("DYDX-TIMESTAMP", iso_timestamp.as_str())
145            .header("DYDX-ETHEREUM-ADDRESS", ethereum_address)
146            .query(&parameters);
147
148        let response = req_builder.send().await;
149
150        Ok(response.unwrap().status())
151    }
152}