coinbase_client/private_client/
private_client.rs

1use crate::configure_pagination;
2use crate::{
3    deserialize_option_to_date, deserialize_response, deserialize_to_date, Json, COINBASE_API_URL,
4    COINBASE_SANDBOX_API_URL,
5};
6
7use super::Order;
8use super::Report;
9
10use crate::error::{Error, ErrorKind, ErrorMessage, StatusError};
11use base64;
12use chrono::{DateTime, Utc};
13use core::f64;
14use crypto::{self, mac::Mac};
15use reqwest;
16use serde::{self, Deserialize};
17use std::str;
18use std::time::{SystemTime, SystemTimeError};
19
20/// `PrivateClient` requires authentication and provide access to placing orders and other account information
21pub struct PrivateClient {
22    reqwest_client: reqwest::Client,
23    secret: String,
24    passphrase: String,
25    key: String,
26    url: &'static str,
27}
28
29impl PrivateClient {
30    async fn get_paginated<T>(
31        &self,
32        path: &str,
33        before: Option<&str>,
34        after: Option<&str>,
35        limit: Option<u16>,
36    ) -> Result<T, Error>
37    where
38        T: serde::de::DeserializeOwned,
39    {
40        let pagination_params = configure_pagination(before, after, limit);
41        self.get(&format!("{}{}", path, pagination_params)).await
42    }
43
44    async fn get<T>(&self, path: &str) -> Result<T, Error>
45    where
46        T: serde::de::DeserializeOwned,
47    {
48        let headers = self.access_headers(path, None, "GET");
49        let response = self
50            .reqwest_client
51            .get(format!("{}{}", self.url, path))
52            .headers(headers)
53            .send()
54            .await?;
55        deserialize_response::<T>(response).await
56    }
57
58    async fn post_and_deserialize<T, K>(&self, path: &str, body: Option<K>) -> Result<T, Error>
59    where
60        K: serde::Serialize,
61        T: serde::de::DeserializeOwned,
62    {
63        deserialize_response::<T>(self.post(path, body).await?).await
64    }
65
66    async fn post<K>(&self, path: &str, body: Option<K>) -> Result<reqwest::Response, Error>
67    where
68        K: serde::Serialize,
69    {
70        let request_builder = self.reqwest_client.post(format!("{}{}", self.url, path));
71        Ok(if let Some(n) = body {
72            request_builder
73                .headers(self.access_headers(path, Some(&serde_json::to_string(&n)?), "POST"))
74                .json::<K>(&n)
75                .send()
76        } else {
77            request_builder
78                .headers(self.access_headers(path, None, "POST"))
79                .send()
80        }
81        .await?)
82    }
83
84    async fn delete<T>(&self, path: &str) -> Result<T, Error>
85    where
86        T: serde::de::DeserializeOwned,
87    {
88        let headers = self.access_headers(path, None, "DELETE");
89        let response = self
90            .reqwest_client
91            .delete(format!("{}{}", self.url, path))
92            .headers(headers)
93            .send()
94            .await?;
95        deserialize_response::<T>(response).await
96    }
97
98    fn get_current_timestamp() -> Result<String, SystemTimeError> {
99        Ok(SystemTime::now()
100            .duration_since(SystemTime::UNIX_EPOCH)?
101            .as_secs()
102            .to_string())
103    }
104
105    fn access_headers(
106        &self,
107        url: &str,
108        body: Option<&str>,
109        meathod: &str,
110    ) -> reqwest::header::HeaderMap {
111        let timestamp = PrivateClient::get_current_timestamp().unwrap();
112        let signature = self.sign_message(url, body, &timestamp, meathod);
113        let mut headers = reqwest::header::HeaderMap::new();
114        headers.insert(
115            reqwest::header::USER_AGENT,
116            reqwest::header::HeaderValue::from_str("coinbase-client")
117                .expect("invalid user agent value"),
118        );
119        headers.insert(
120            reqwest::header::HeaderName::from_static("cb-access-key"),
121            reqwest::header::HeaderValue::from_str(&self.key)
122                .expect("invalid user cb-access-key value"),
123        );
124        headers.insert(
125            reqwest::header::HeaderName::from_static("cb-access-sign"),
126            reqwest::header::HeaderValue::from_str(&signature)
127                .expect("invalid cb-access-sign value"),
128        );
129        headers.insert(
130            reqwest::header::HeaderName::from_static("cb-access-timestamp"),
131            reqwest::header::HeaderValue::from_str(&timestamp)
132                .expect("invalid user cb-access-timestamp value"),
133        );
134        headers.insert(
135            reqwest::header::HeaderName::from_static("cb-access-passphrase"),
136            reqwest::header::HeaderValue::from_str(&self.passphrase)
137                .expect("invalid user cb-access-passphrase value"),
138        );
139
140        headers
141    }
142
143    fn sign_message(
144        &self,
145        url: &str,
146        body: Option<&str>,
147        timestamp: &str,
148        meathod: &str,
149    ) -> String {
150        let mut prehash = String::new();
151        // omit body if not supplied
152        match body {
153            Some(body) => {
154                prehash.push_str(&timestamp);
155                prehash.push_str(&meathod);
156                prehash.push_str(&url);
157                prehash.push_str(&body);
158            }
159            None => {
160                prehash.push_str(&timestamp);
161                prehash.push_str(&meathod);
162                prehash.push_str(&url);
163            }
164        }
165        // decode your coinbase api secret
166        let decoded_secret = base64::decode(&self.secret)
167            .expect("unable to decode secret, is your secret in base 64 encoding");
168        // hmac-sha256 it
169        let mut hmac = crypto::hmac::Hmac::new(crypto::sha2::Sha256::new(), &decoded_secret);
170        hmac.input(prehash.as_bytes());
171        let hmac_result = hmac.result();
172        let hmac_code = hmac_result.code();
173        let base64_encoding = base64::encode(hmac_code);
174        // return base64 encoded hmac result
175        base64_encoding
176    }
177
178    /// Creates a new `PrivateClient`
179    /// <br>
180    /// ~~~~
181    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
182    /// ~~~~
183    pub fn new(secret: String, passphrase: String, key: String) -> Self {
184        Self {
185            reqwest_client: reqwest::Client::new(),
186            secret, // shared secret
187            key,
188            passphrase,
189            url: COINBASE_API_URL,
190        }
191    }
192
193    /// Creates a new `PrivateClient` for testing API connectivity and web trading
194    /// <br>
195    /// ~~~~
196    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
197    /// ~~~~
198    pub fn new_sandbox(secret: String, passphrase: String, key: String) -> Self {
199        Self {
200            reqwest_client: reqwest::Client::new(),
201            secret,
202            key,
203            passphrase,
204            url: COINBASE_SANDBOX_API_URL,
205        }
206    }
207
208    /// Gets a list of trading accounts from the profile of the API key.
209    /// <br>
210    /// [API docs](https://docs.pro.coinbase.com/#account)
211    /// <br>
212    /// ~~~~
213    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
214    /// let accounts = client.get_accounts().await.unwrap();
215    /// ~~~~
216    pub async fn get_accounts(&self) -> Result<Vec<Account>, Error> {
217        let accounts = self.get("/accounts").await?;
218        Ok(accounts)
219    }
220
221    /// Get trading account by account ID
222    /// <br>
223    /// [API docs](https://docs.pro.coinbase.com/#account)
224    /// <br>
225    /// ~~~~
226    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
227    /// let account = client.get_account("1f6a7175-a89c-494f-986d-af9987e6dd69")
228    /// .await
229    /// .unwrap();
230    /// ~~~~
231    pub async fn get_account(&self, account_id: &str) -> Result<Account, Error> {
232        let account = self.get(&format!("/accounts/{}", account_id)).await?;
233        Ok(account)
234    }
235
236    /// Get account activity of the API key's profile.
237    /// <br>
238    /// [API docs](https://docs.pro.coinbase.com/#get-account-history)
239    /// <br>
240    /// ~~~~
241    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
242    ///  let history = client
243    /// .get_account_history(
244    ///     "680f85f4-1a99-4108-93ce-a9066f9de246",
245    ///     Some("297946691"),
246    ///     Some("296147671"),
247    ///     Some(100),
248    /// )
249    /// .await
250    /// .unwrap();
251    /// ~~~~
252    pub async fn get_account_history(
253        &self,
254        account_id: &str,
255        before: Option<&str>,
256        after: Option<&str>,
257        limit: Option<u16>,
258    ) -> Result<Vec<AccountHistory>, Error> {
259        let account = self
260            .get_paginated(
261                &format!("/accounts/{}/ledger?", account_id),
262                before,
263                after,
264                limit,
265            )
266            .await?;
267        Ok(account)
268    }
269
270    /// Get holds of an account that belong to the same profile as the API key.
271    /// <br>
272    /// [API docs](https://docs.pro.coinbase.com/#get-holds)\
273    /// <br>
274    /// ~~~~
275    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
276    /// let _holds = client
277    /// .get_account_holds(
278    ///     "680f85f4-1a99-4108-93ce-a9066f9de246",
279    ///     None,
280    ///     None,
281    ///     Some(100),
282    /// )
283    /// .await
284    /// .unwrap();
285    /// ~~~~
286    pub async fn get_account_holds(
287        &self,
288        account_id: &str,
289        before: Option<&str>,
290        after: Option<&str>,
291        limit: Option<u16>,
292    ) -> Result<Vec<Hold>, Error> {
293        let account = self
294            .get_paginated(
295                &format!("/accounts/{}/holds?", account_id),
296                before,
297                after,
298                limit,
299            )
300            .await?;
301        Ok(account)
302    }
303
304    /// You can place three types of orders: limit, market and stop
305    /// <br>
306    /// [Overview of order types and settings](https://help.coinbase.com/en/pro/trading-and-funding/orders/overview-of-order-types-and-settings-stop-limit-market)
307    /// <br>
308    /// Create order order useing [`OrderBuilder`](https://docs.rs/coinbase-client/1.0.0-alpha/coinbase_client/private_client/struct.OrderBuilder.html)
309    /// <br>
310    /// [API docs](https://docs.pro.coinbase.com/#place-a-new-order)
311    /// ~~~~
312    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
313    /// let order = OrderBuilder::market(OrderSide::Buy, "BTC-USD", SizeOrFunds::Funds(10.00))
314    /// .build();
315    /// let res = client.place_order(order).await.unwrap();
316    /// ~~~~
317    pub async fn place_order(&self, order: Order) -> Result<String, Error> {
318        #[derive(Deserialize, Debug)]
319        pub struct OrderID {
320            pub id: String,
321        }
322        Ok(self
323            .post_and_deserialize::<OrderID, _>("/orders", Some(order))
324            .await?
325            .id)
326    }
327
328    /// Cancel order specified by order ID
329    /// <br>
330    /// [API docs](https://docs.pro.coinbase.com/#cancel-an-order)
331    /// <br>
332    /// ~~~~
333    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
334    /// let order = OrderBuilder::limit(OrderSide::Buy, "BTC-USD", 33000.0, 1.0)
335    /// .build();
336    /// let order_to_cancel_id = client.place_order(order).await.unwrap();
337    /// let canceled_order_id = client.cancel_order(&order_to_cancel_id)
338    /// .await.unwrap();
339    /// ~~~~
340    pub async fn cancel_order(&self, order_id: &str) -> Result<String, Error> {
341        Ok(self.delete(&format!("/orders/{}", order_id)).await?)
342    }
343
344    /// Cancel order specified by order OID
345    /// <br>
346    /// [API docs](https://docs.pro.coinbase.com/#cancel-an-order)
347    pub async fn cancel_order_by_oid(&self, oid: &str) -> Result<String, Error> {
348        Ok(self.delete(&format!("/orders/client:{}", oid)).await?)
349    }
350
351    /// Cancel all orders
352    /// <br>
353    /// [API docs](https://docs.pro.coinbase.com/#cancel-an-order)
354    /// <br>
355    /// ~~~~
356    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
357    /// let canceled_orders_ids = client.cancel_orders().await.unwrap();
358    /// ~~~~
359    pub async fn cancel_orders(&self) -> Result<Vec<String>, Error> {
360        Ok(self.delete("/orders").await?)
361    }
362
363    /// Get open orders from the profile that the API key belongs
364    /// <br>
365    /// [API docs](https://docs.pro.coinbase.com/#list-orders)
366    /// <br>
367    /// This request is [paginated](https://docs.pro.coinbase.com/#pagination)
368    /// <br>
369    /// ~~~~
370    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
371    /// let orders = client
372    ///     .get_orders(
373    ///         Some(OrderStatus::OpenActivePending),
374    ///         Some("2021-06-19T20:24:20.467086Z"),
375    ///         None,
376    ///         None,
377    ///     )
378    ///     .await
379    ///     .unwrap();
380    /// ~~~~
381    pub async fn get_orders(
382        &self,
383        order_status: Option<OrderStatus>,
384        before: Option<&str>,
385        after: Option<&str>,
386        limit: Option<u16>,
387    ) -> Result<Vec<OrderInfo>, Error> {
388        let path = match order_status {
389            Some(n) => {
390                let params = match n {
391                    OrderStatus::Open => "status=open",
392                    OrderStatus::Active => "status=active",
393                    OrderStatus::Pending => "status=pending",
394                    OrderStatus::OpenActive => "status=open&status=active",
395                    OrderStatus::OpenPending => "status=open&status=pending",
396                    OrderStatus::ActivePending => "status=active&status=pending",
397                    OrderStatus::OpenActivePending => "status=open&status=active&status=pending",
398                };
399                format!("/orders?{}&", params)
400            }
401            None => String::from("/orders?"),
402        };
403
404        Ok(self.get_paginated(&path, before, after, limit).await?)
405    }
406
407    /// Get open order from the profile that the API key belongs
408    /// <br>
409    /// [API docs](https://docs.pro.coinbase.com/#get-an-order)
410    /// <br>
411    /// ~~~~
412    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
413    /// let order = OrderBuilder::limit(OrderSide::Buy, "BTC-USD", 36000.0, 1.0)
414    /// .build();
415    /// let order_id = client.place_order(order).await.unwrap();
416    /// let order = client.get_order(&order_id).await.unwrap();
417    /// ~~~~
418    pub async fn get_order(&self, order_id: &str) -> Result<OrderInfo, Error> {
419        Ok(self.get(&format!("/orders/{}", order_id)).await?)
420    }
421
422    /// Gets order specified by order OID
423    /// <br>
424    /// [API docs](https://docs.pro.coinbase.com/#get-an-order)
425    pub async fn get_order_by_oid(&self, oid: &str) -> Result<OrderInfo, Error> {
426        Ok(self.get(&format!("/orders/client:{}", oid)).await?)
427    }
428
429    /// Get recent fills by specified order_id of the API key's profile
430    /// <br>
431    /// [API docs](https://docs.pro.coinbase.com/#fills)
432    /// <br>
433    /// ~~~~
434    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
435    /// let fills = client
436    ///     .get_fill_by_order_id("4f2756cf-dcb5-492b-83e5-5f2141892758", None, None, None)
437    ///     .await
438    ///     .unwrap();
439    /// ~~~~
440    pub async fn get_fill_by_order_id(
441        &self,
442        order_id: &str,
443        before: Option<&str>,
444        after: Option<&str>,
445        limit: Option<u16>,
446    ) -> Result<Vec<Fill>, Error> {
447        Ok(self
448            .get_paginated(
449                &format!("/fills?order_id={}&", order_id),
450                before,
451                after,
452                limit,
453            )
454            .await?)
455    }
456
457    /// Get recent fills by specified product_id of the API key's profile
458    /// <br>
459    /// [API docs](https://docs.pro.coinbase.com/#fills)
460    /// <br>
461    /// ~~~~
462    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
463    /// let fills = client
464    ///     .get_fills_by_product_id(&product_id, None, Some("29786034"), None)
465    ///     .await
466    ///     .unwrap();
467    /// ~~~~
468    pub async fn get_fills_by_product_id(
469        &self,
470        product_id: &str,
471        before: Option<&str>,
472        after: Option<&str>,
473        limit: Option<u16>,
474    ) -> Result<Vec<Fill>, Error> {
475        Ok(self
476            .get_paginated(
477                &format!("/fills?product_id={}&", product_id),
478                before,
479                after,
480                limit,
481            )
482            .await?)
483    }
484
485    /// Get information on your payment method transfer limits, as well as buy/sell limits per currency
486    /// <br>
487    /// [API docs](https://docs.pro.coinbase.com/#limits)
488    /// <br>
489    /// ~~~~
490    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
491    /// let limits = client.get_limits().await.unwrap();
492    /// ~~~~
493    pub async fn get_limits(&self) -> Result<Json, Error> {
494        Ok(self.get(&format!("/users/self/exchange-limits")).await?)
495    }
496
497    /// Get deposits from the profile of the API key, in descending order by created time
498    /// <br>
499    /// **optional parameters**
500    /// <br>
501    /// *profile_id*: limit list of deposits to this profile_id. By default, it retrieves deposits using default profile
502    /// <br>
503    /// *before*: if before is set, then it returns deposits created after the before timestamp, sorted by oldest creation date
504    /// <br>
505    /// *after*: if after is set, then it returns deposits created before the after timestamp, sorted by newest
506    /// <br>
507    /// *limit*: truncate list to this many deposits, capped at 100. Default is 100.
508    /// <br>
509    /// [API docs](https://docs.pro.coinbase.com/#list-deposits)
510    /// <br>
511    /// This request is [paginated](https://docs.pro.coinbase.com/#pagination)
512    /// <br>
513    /// ~~~~
514    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
515    /// let deposits = client
516    ///     .get_deposits(
517    ///         Some("b7482eaa-3eea-4065-9d81-1484257c5f92"),
518    ///         None,
519    ///         None,
520    ///         None,
521    ///     )
522    ///     .await.unwrap();
523    /// ~~~~
524    pub async fn get_deposits(
525        &self,
526        profile_id: Option<&str>,
527        before: Option<&str>,
528        after: Option<&str>,
529        limit: Option<u16>,
530    ) -> Result<Json, Error> {
531        let path = match profile_id {
532            Some(n) => format!("/transfers?type=deposit&profile_id={}&", n),
533            None => String::from("/transfers?type=deposit&"),
534        };
535        Ok(self.get_paginated(&path, before, after, limit).await?)
536    }
537    /// Get internal deposits from the profile of the API key, in descending order by created time
538    /// <br>
539    /// **optional parameters**
540    /// <br>
541    /// *profile_id*: limit list of internal deposits to this profile_id. By default, it retrieves internal deposits using default profile
542    /// <br>
543    /// *before*: if before is set, then it returns internal deposits created after the before timestamp, sorted by oldest creation date
544    /// <br>
545    /// *after*: if after is set, then it returns internal deposits created before the after timestamp, sorted by newest
546    /// <br>
547    /// *limit*: truncate list to this many internal deposits, capped at 100. Default is 100.
548    /// <br>
549    /// [API docs](https://docs.pro.coinbase.com/#list-deposits)
550    /// <br>
551    /// This request is [paginated](https://docs.pro.coinbase.com/#pagination)
552    /// <br>
553    /// ~~~~
554    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
555    /// let deposits = client
556    /// .get_internal_deposits(
557    ///     Some("e1d7731f-b7e2-4285-b711-eeec76fc2aff"),
558    ///     None,
559    ///     None,
560    ///     None,
561    /// )
562    /// .await.unwrap();
563    /// ~~~~
564    pub async fn get_internal_deposits(
565        &self,
566        profile_id: Option<&str>,
567        before: Option<&str>,
568        after: Option<&str>,
569        limit: Option<u16>,
570    ) -> Result<Json, Error> {
571        let path = match profile_id {
572            Some(n) => format!("/transfers?type=internal_deposit&profile_id={}&", n),
573            None => String::from("/transfers?type=internal_deposit&"),
574        };
575        Ok(self.get_paginated(&path, before, after, limit).await?)
576    }
577
578    /// Get information on a single deposit
579    /// <br>
580    /// [API docs](https://docs.pro.coinbase.com/#single-deposit)
581    /// <br>
582    /// ~~~~
583    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
584    /// let deposit = client
585    /// .get_deposit("80259339-7bf9-498f-8200-ddbd32a1c545")
586    /// .await;
587    /// ~~~~
588    pub async fn get_deposit(&self, transfer_id: &str) -> Result<Json, Error> {
589        Ok(self.get(&format!("/transfers/{}", transfer_id)).await?)
590    }
591
592    /// Get your payment methods
593    /// <br>
594    /// [API docs](https://docs.pro.coinbase.com/#payment-methods)
595    /// <br>
596    /// ~~~~
597    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
598    /// let payment_methods = client.get_payment_methods().await.unwrap();
599    /// ~~~~
600    pub async fn get_payment_methods(&self) -> Result<Json, Error> {
601        Ok(self.get("/payment-methods").await?)
602    }
603
604    /// Deposit funds from a payment method
605    /// <br>
606    /// [API docs](https://docs.pro.coinbase.com/#payment-method)
607    /// <br>
608    /// ~~~~
609    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
610    /// let res = client
611    /// .deposit_funds(10.00, "USD", "1b4b4fbc-8921-5e7c-b362-a1c589a2cf20")
612    /// .await
613    /// .unwrap();
614    /// ~~~~
615    pub async fn deposit_funds(
616        &self,
617        amount: f64,
618        currency: &str,
619        payment_method_id: &str,
620    ) -> Result<DepositInfo, Error> {
621        Ok(self
622            .post_and_deserialize(
623                "/deposits/payment-method",
624                Some(serde_json::json!({
625                        "amount": amount,
626                        "currency": currency,
627                        "payment_method_id": payment_method_id
628                })),
629            )
630            .await?)
631    }
632
633    /// Deposit funds from a coinbase account
634    /// <br>
635    /// [API docs](https://docs.pro.coinbase.com/#coinbase)
636    /// <br>
637    /// ~~~~
638    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
639    /// let res = client
640    ///     .deposit_funds_from_coinbase(10.00, "BTC", "95671473-4dda-5264-a654-fc6923e8a334")
641    ///     .await
642    ///     .unwrap();
643    /// ~~~~
644    pub async fn deposit_funds_from_coinbase(
645        &self,
646        amount: f64,
647        currency: &str,
648        coinbase_account_id: &str,
649    ) -> Result<DepositInfo, Error> {
650        Ok(self
651            .post_and_deserialize(
652                "/deposits/coinbase-account",
653                Some(serde_json::json!({
654                        "amount": amount,
655                        "currency": currency,
656                        "coinbase_account_id": coinbase_account_id
657                })),
658            )
659            .await?)
660    }
661
662    /// Get a list of your coinbase accounts
663    /// <br>
664    /// [API docs](https://docs.pro.coinbase.com/#coinbase-accounts)
665    /// <br>
666    /// ~~~~
667    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
668    /// let accounts = client.get_coinbase_accounts().await.unwrap();
669    /// ~~~~
670    pub async fn get_coinbase_accounts(&self) -> Result<Json, Error> {
671        Ok(self.get("/coinbase-accounts").await?)
672    }
673
674    /// Generate an address for crypto deposits
675    /// <br>
676    /// [API docs](https://docs.pro.coinbase.com/#generate-a-crypto-deposit-address)
677    /// <br>
678    /// ~~~~
679    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
680    /// let address = client
681    ///     .generate_crypto_deposit_address("95671473-4dda-5264-a654-fc6923e8a334")
682    ///     .await
683    ///     .unwrap();    
684    /// ~~~~
685    pub async fn generate_crypto_deposit_address(
686        &self,
687        coinbase_account_id: &str,
688    ) -> Result<Json, Error> {
689        Ok(self
690            .post_and_deserialize::<_, Json>(
691                &format!("/coinbase-accounts/{}/addresses", coinbase_account_id),
692                None,
693            )
694            .await?)
695    }
696
697    /// Get withdrawals from the profile of the API key
698    /// <br>
699    /// **optional parameters**
700    /// <br>
701    /// *profile_id*: limit list of withdrawals to this profile_id. By default, it retrieves withdrawals using default profile
702    /// <br>
703    /// *before*: If before is set, then it returns withdrawals created after the before timestamp, sorted by oldest creation date
704    /// <br>
705    /// *after*: If after is set, then it returns withdrawals created before the after timestamp, sorted by newest
706    /// <br>
707    /// *limit*: truncate list to this many withdrawals, capped at 100. Default is 100
708    /// <br>
709    /// [API docs](https://docs.pro.coinbase.com/#list-withdrawals)
710    /// <br>
711    /// This request is [paginated](https://docs.pro.coinbase.com/#pagination)
712    /// <br>
713    /// ~~~~
714    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
715    /// let withdrawls = client
716    ///     .get_withdrawls(
717    ///         Some("b7482eaa-3eea-4065-9d81-1484257c5f92"),
718    ///         None,
719    ///         None,
720    ///         None,
721    ///     )
722    ///     .await
723    ///     .unwrap();
724    /// ~~~~
725    pub async fn get_withdrawls(
726        &self,
727        profile_id: Option<&str>,
728        before: Option<&str>,
729        after: Option<&str>,
730        limit: Option<u16>,
731    ) -> Result<Json, Error> {
732        let path = match profile_id {
733            Some(n) => format!("/transfers?type=withdraw&profile_id={}&", n),
734            None => String::from("/transfers?type=withdraw&"),
735        };
736        Ok(self.get_paginated(&path, before, after, limit).await?)
737    }
738
739    /// Get withdrawals from the profile of the API key
740    /// <br>
741    /// **optional parameters**
742    /// <br>
743    /// *profile_id*: limit list of internal withdrawals to this profile_id. By default, it retrieves internal withdrawals using default profile
744    /// <br>
745    /// <br>
746    /// *before*: If before is set, then it returns internal withdrawals created after the before timestamp, sorted by oldest creation date
747    /// <br>
748    /// <br>
749    /// *after*: If after is set, then it returns internal withdrawals created before the after timestamp, sorted by newest
750    /// <br>
751    /// <br>
752    /// *limit*: truncate list to this many internal withdrawals, capped at 100. Default is 100
753    /// <br>
754    /// [API docs](https://docs.pro.coinbase.com/#list-withdrawals)
755    /// <br>
756    /// This request is [paginated](https://docs.pro.coinbase.com/#pagination)
757    /// <br>
758    /// ~~~~
759    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
760    /// let withdrawls = client
761    ///     .get_internal_withdrawls(
762    ///         Some("b7482eaa-3eea-4065-9d81-1484257c5f92"),
763    ///         None,
764    ///         None,
765    ///         None,
766    ///     )
767    ///     .await
768    ///     .unwrap();
769    /// ~~~~
770    pub async fn get_internal_withdrawls(
771        &self,
772        profile_id: Option<&str>,
773        before: Option<&str>,
774        after: Option<&str>,
775        limit: Option<u16>,
776    ) -> Result<Json, Error> {
777        let path = match profile_id {
778            Some(n) => format!("/transfers?type=internal_withdraw&profile_id={}&", n),
779            None => String::from("/transfers?type=internal_withdraw&"),
780        };
781        Ok(self.get_paginated(&path, before, after, limit).await?)
782    }
783
784    /// Get information on a single withdrawal
785    /// <br>
786    /// [API docs](https://docs.pro.coinbase.com/#single-withdrawal)
787    /// <br>
788    /// ~~~~
789    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
790    /// let withdrawl = client
791    ///     .get_withdrawl("0e94a87f-9d50-4ead-86ac-7898830c5edf")
792    ///     .await
793    ///     .unwrap();
794    /// ~~~~
795    pub async fn get_withdrawl(&self, transfer_id: &str) -> Result<Json, Error> {
796        Ok(self.get(&format!("/transfers/{}", transfer_id)).await?)
797    }
798
799    /// Withdraw funds to a payment method
800    /// <br>
801    /// [API docs](https://docs.pro.coinbase.com/#payment-method55)
802    pub async fn withdraw_funds(
803        &self,
804        amount: f64,
805        currency: &str,
806        payment_method_id: &str,
807    ) -> Result<WithdrawInfo, Error> {
808        Ok(self
809            .post_and_deserialize(
810                "/withdrawals/payment-method",
811                Some(serde_json::json!({
812                        "amount": amount,
813                        "currency": currency,
814                        "payment_method_id": payment_method_id
815                })),
816            )
817            .await?)
818    }
819
820    /// Withdraw funds to a coinbase account
821    /// <br>
822    /// [API docs](https://docs.pro.coinbase.com/#coinbase56)
823    /// <br>
824    /// ~~~~
825    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
826    /// let res = client
827    ///     .withdraw_to_coinbase(1.0, "ADA", "91bdfea7-f2sd-5waa-bb0d-5b93c9f09ffc")
828    ///     .await
829    ///     .unwrap();    
830    /// ~~~~
831    pub async fn withdraw_to_coinbase(
832        &self,
833        amount: f64,
834        currency: &str,
835        coinbase_account_id: &str,
836    ) -> Result<WithdrawInfo, Error> {
837        Ok(self
838            .post_and_deserialize(
839                "/withdrawals/coinbase-account",
840                Some(serde_json::json!({
841                        "amount": amount,
842                        "currency": currency,
843                        "coinbase_account_id": coinbase_account_id
844                })),
845            )
846            .await?)
847    }
848
849    /// Withdraw funds to a crypto address.
850    /// <br>
851    /// **parameters**
852    /// <br>
853    /// amount: The amount to withdraw
854    /// <br>
855    /// currency: The type of currency
856    /// <br>
857    /// crypto_address: A crypto address of the recipient
858    /// <br>
859    /// destination_tag: A destination tag for currencies that support one
860    /// <br>
861    /// no_destination_tag:	A boolean flag to opt out of using a destination tag for currencies that support one. This is required when not providing a destination tag.
862    /// <br>
863    /// add_network_fee_to_total: A boolean flag to add the network fee on top of the amount. If this is blank, it will default to deducting the network fee from the amount.
864    /// <br>
865    /// [API docs](https://docs.pro.coinbase.com/#crypto)
866    /// <br>
867    /// ~~~~
868    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
869    /// let res = client.withdraw_to_crypto_address(6.0, "ADA", "addr1qyk0yr3ht9d6hcqwp8q8j38nxs04npyjauzz9wp5jcfr95h64lvegfk57zmzltj3nmpjff6490ayyvjh0g6sne6hm3hspnnscy", None, None, None).await.unwrap();
870    /// ~~~~
871    pub async fn withdraw_to_crypto_address(
872        &self,
873        amount: f64,
874        currency: &str,
875        crypto_address: &str,
876        destination_tag: Option<&str>,
877        no_destination_tag: Option<bool>,
878        add_network_fee_to_total: Option<bool>,
879    ) -> Result<Json, Error> {
880        Ok(self
881            .post_and_deserialize(
882                "/withdrawals/crypto",
883                Some(serde_json::json!({
884                        "amount": amount,
885                        "currency": currency,
886                        "crypto_address": crypto_address,
887                        "destination_tag": destination_tag,
888                        "no_destination_tag": no_destination_tag,
889                        "add_network_fee_to_total": add_network_fee_to_total
890                })),
891            )
892            .await?)
893    }
894
895    /// Get your current maker & taker fee rates, as well as your 30-day trailing volume
896    /// <br>
897    /// [API docs](https://docs.pro.coinbase.com/#get-current-fees)
898    /// <br>
899    /// ~~~~
900    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
901    /// let fees = client.get_fees().await.unwrap();
902    /// ~~~~
903    pub async fn get_fees(&self) -> Result<Fees, Error> {
904        Ok(self.get("/fees").await?)
905    }
906
907    /// Get the network fee estimate when sending to the given address
908    /// <br>
909    /// [API docs](https://docs.pro.coinbase.com/#fee-estimate)
910    /// <br>
911    /// ~~~~
912    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
913    /// let fee = client
914    ///     .get_fee_estimate("ETH", "0x82289D45Ee8E806C63Ba0DC94a22d4238525d815")
915    ///     .await
916    ///     .unwrap();
917    /// ~~~~
918    pub async fn get_fee_estimate(
919        &self,
920        currency: &str,
921        crypto_address: &str,
922    ) -> Result<f64, Error> {
923        #[derive(serde::Deserialize)]
924        struct Fee {
925            fee: f64,
926        }
927        let fee = self
928            .get::<Fee>(&format!(
929                "/withdrawals/fee-estimate?currency={}&crypto_address={}",
930                currency, crypto_address
931            ))
932            .await?;
933        Ok(fee.fee)
934    }
935
936    /// Convert between stablecoins
937    /// <br>
938    /// [API docs](https://docs.pro.coinbase.com/#stablecoin-conversions)
939    /// <br>
940    /// ~~~~
941    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
942    /// let convertion = client
943    ///     .convert_stablecoin("USD", "USDC", 10.00)
944    ///     .await
945    ///     .unwrap();
946    /// ~~~~
947    pub async fn convert_stablecoin(
948        &self,
949        from_currency_id: &str,
950        to_currency_id: &str,
951        amount: f64,
952    ) -> Result<StablecoinConversion, Error> {
953        Ok(self
954            .post_and_deserialize(
955                "/conversions",
956                Some(serde_json::json!({
957                    "from": from_currency_id,
958                    "to": to_currency_id,
959                    "amount": amount
960                })),
961            )
962            .await?)
963    }
964    
965    /// Reports provide batches of historic information about your profile in various human and machine readable forms    
966    /// <br>
967    /// Create a `Report` useing [`ReportBuilder`](https://docs.rs/coinbase-client/1.0.0-alpha/coinbase_client/private_client/struct.ReportBuilder.html)
968    /// <br>
969    /// [API docs](https://docs.pro.coinbase.com/#create-a-new-report)
970    /// <br>
971    /// ~~~~
972    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
973    /// let report = Report::account_builder(
974    ///     "2014-11-01T00:00:00.000Z",
975    ///     "2021-06-11T02:48:15.853Z",
976    ///     "1f6a7175-a89c-494f-986d-af9987e6dd69",
977    /// )
978    /// .email("willstanhope@gmail.com")
979    /// .format(Format::CSV)
980    /// .build();
981    /// let res = client.create_report(report).await.unwrap();
982    /// ~~~~
983    pub async fn create_report<'a>(&self, report: Report) -> Result<ReportInfo, Error> {
984        Ok(self.post_and_deserialize("/reports", Some(report)).await?)
985    }
986
987    /// Get report status
988    /// <br>
989    /// Once a report request has been accepted for processing, the status becomes available
990    /// <br>
991    /// [API docs](https://docs.pro.coinbase.com/#get-report-status)
992    /// <br>
993    /// ~~~~
994    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
995    /// let report = client
996    /// .get_report("d4a3e847-b618-454d-bcb3-e77b0ad61600")
997    /// .await
998    /// .unwrap();
999    /// ~~~~
1000    pub async fn get_report(&self, report_id: &str) -> Result<ReportInfo, Error> {
1001        Ok(self.get(&format!("/reports/{}", report_id)).await?)
1002    }
1003
1004    /// Get your profiles
1005    /// <br>
1006    /// [API docs](https://docs.pro.coinbase.com/#list-profiles)
1007    /// <br>
1008    /// ~~~~
1009    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
1010    /// let profiles = client.get_profiles().await.unwrap();
1011    /// ~~~~
1012    pub async fn get_profiles(&self) -> Result<Vec<Profile>, Error> {
1013        Ok(self.get("/profiles").await?)
1014    }
1015
1016    /// Get a single profile by profile id
1017    /// <br>
1018    /// [API docs](https://docs.pro.coinbase.com/#get-a-profile)
1019    /// <br>
1020    /// ~~~~
1021    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
1022    /// let profile = client
1023    /// .get_profile("e1d7731f-b7e2-4285-b711-eeec76fc2aff")
1024    /// .await
1025    /// .unwrap();
1026    /// ~~~~
1027    pub async fn get_profile(&self, profile_id: &str) -> Result<Profile, Error> {
1028        Ok(self.get(&format!("/profiles/{}", profile_id)).await?)
1029    }
1030
1031    /// Transfer funds from API key's profile to another user owned profile
1032    /// <br>
1033    /// [API docs](https://docs.pro.coinbase.com/#create-profile-transfer)
1034    /// <br>
1035    /// ~~~~
1036    /// let client = PrivateClient::new("tGJSu7SuV3/HOR1/9DcFwO1s560BKI51SDEbnwuvTPbw4BbG5lYJLuKUFpD8TPU61R85dxJpGTygKZ5v+6wJdA==", "t9riylyad0r", "4a9f6de8bcdee641a0a207613dfb43ef");
1037    /// let ok = client
1038    ///     .create_profile_transfer(
1039    ///         "e1d7731f-b7e2-4285-b711-eeec76fc2aff",
1040    ///         "3510ac37-1a99-4c9c-9865-15f1bc5a832e",
1041    ///         "USD",
1042    ///         100.00,
1043    ///     )
1044    ///     .await
1045    ///     .unwrap();
1046    /// ~~~~
1047    pub async fn create_profile_transfer(
1048        &self,
1049        from: &str,
1050        to: &str,
1051        currency: &str,
1052        amount: f64,
1053    ) -> Result<String, Error> {
1054        let response = self
1055            .post(
1056                "/profiles/transfer",
1057                Some(serde_json::json!(
1058                    {
1059                        "from": from,
1060                        "to": to,
1061                        "currency": currency,
1062                        "amount": amount
1063                    }
1064                )),
1065            )
1066            .await?;
1067        let status = response.status();
1068        if !status.is_success() {
1069            let error_message = response.json::<ErrorMessage>().await?;
1070            return Err(Error::new(ErrorKind::Status(StatusError::new(
1071                status.as_u16(),
1072                error_message.message,
1073            ))));
1074        }
1075        Ok(response.text().await?)
1076    }
1077
1078    /// Get cryptographically signed prices ready to be posted on-chain using Open Oracle smart contracts.
1079    /// <br>
1080    /// [API docs](https://docs.pro.coinbase.com/#oracle)
1081    pub async fn oracle(&self) -> Result<Json, Error> {
1082        Ok(self.get("/oracle").await?)
1083    }
1084}
1085
1086/// Limit list of orders to these statuses. Passing `OpenActivePending` returns orders of all statuses.
1087pub enum OrderStatus {
1088    Open,
1089    Active,
1090    Pending,
1091    OpenActive,
1092    OpenPending,
1093    ActivePending,
1094    OpenActivePending,
1095}
1096
1097/// A structure that repersents a Stablecoin Conversion
1098#[derive(Deserialize, Debug)]
1099pub struct StablecoinConversion {
1100    id: String,
1101    amount: String,
1102    from_account_id: String,
1103    to_account_id: String,
1104    from: String,
1105    to: String,
1106}
1107
1108/// A structure that repersents an Account
1109#[derive(Deserialize, Debug)]
1110pub struct Account {
1111    pub id: String,
1112    pub currency: String,
1113    pub balance: String,
1114    pub available: String,
1115    pub hold: String,
1116    pub profile_id: String,
1117    pub trading_enabled: bool,
1118}
1119
1120/// A structure that repersents an Account History
1121#[derive(Deserialize, Debug)]
1122pub struct AccountHistory {
1123    id: String,
1124    #[serde(deserialize_with = "deserialize_to_date")]
1125    created_at: DateTime<Utc>,
1126    amount: String,
1127    balance: String,
1128    r#type: String,
1129    details: AccountHistoryDetails,
1130}
1131
1132/// A structure that repersents an Account Hold
1133#[derive(Deserialize, Debug)]
1134pub struct Hold {
1135    id: String,
1136    account_id: String,
1137    #[serde(deserialize_with = "deserialize_to_date")]
1138    created_at: DateTime<Utc>,
1139    #[serde(deserialize_with = "deserialize_to_date")]
1140    updated_at: DateTime<Utc>,
1141    amount: String,
1142    r#type: String,
1143    r#ref: String,
1144}
1145
1146/// A structure that repersents Account History Details
1147#[derive(Deserialize, Debug)]
1148pub struct AccountHistoryDetails {
1149    order_id: Option<String>,
1150    trade_id: Option<String>,
1151    product_id: Option<String>,
1152}
1153
1154/// A structure that repersents Deposit Info
1155#[derive(Deserialize, Debug)]
1156pub struct DepositInfo {
1157    id: String,
1158    amount: String,
1159    currency: String,
1160    payout_at: Option<String>,
1161}
1162
1163/// A structure that repersents Withdraw Info
1164#[derive(Deserialize, Debug)]
1165pub struct WithdrawInfo {
1166    id: String,
1167    amount: String,
1168    currency: String,
1169}
1170
1171/// A structure that repersents Order Info
1172#[derive(Debug, Deserialize)]
1173pub struct OrderInfo {
1174    id: String,
1175    price: String,
1176    size: String,
1177    product_id: String,
1178    side: String,
1179    stp: Option<String>,
1180    r#type: String,
1181    time_in_force: String,
1182    post_only: bool,
1183    #[serde(deserialize_with = "deserialize_to_date")]
1184    created_at: DateTime<Utc>,
1185    fill_fees: String,
1186    filled_size: String,
1187    executed_value: String,
1188    status: String,
1189    settled: bool,
1190}
1191
1192/// A structure that repersents Report Info
1193#[derive(Debug, Deserialize)]
1194pub struct ReportInfo {
1195    id: String,
1196    r#type: String,
1197    status: String,
1198    #[serde(default, deserialize_with = "deserialize_option_to_date")]
1199    created_at: Option<DateTime<Utc>>,
1200    #[serde(default, deserialize_with = "deserialize_option_to_date")]
1201    completed_at: Option<DateTime<Utc>>,
1202    #[serde(default, deserialize_with = "deserialize_option_to_date")]
1203    expires_at: Option<DateTime<Utc>>,
1204    file_url: Option<String>,
1205    params: Option<ReportParams>,
1206}
1207
1208/// A structure that repersents Report Info Params
1209#[derive(Debug, Deserialize)]
1210pub struct ReportParams {
1211    #[serde(deserialize_with = "deserialize_to_date")]
1212    start_date: DateTime<Utc>,
1213    #[serde(deserialize_with = "deserialize_to_date")]
1214    end_date: DateTime<Utc>,
1215}
1216
1217/// A structure that repersents a Fill
1218#[derive(Debug, Deserialize)]
1219pub struct Fill {
1220    trade_id: u64,
1221    product_id: String,
1222    price: String,
1223    size: String,
1224    order_id: String,
1225    #[serde(deserialize_with = "deserialize_to_date")]
1226    created_at: DateTime<Utc>,
1227    liquidity: String,
1228    fee: String,
1229    settled: bool,
1230    side: String,
1231}
1232
1233/// A structure that represents your current maker & taker fee rates, as well as your 30-day trailing volume
1234#[derive(Debug, Deserialize)]
1235pub struct Fees {
1236    maker_fee_rate: String,
1237    taker_fee_rate: String,
1238    usd_volume: String,
1239}
1240
1241/// A structure represents a single profile
1242#[derive(Debug, Deserialize)]
1243pub struct Profile {
1244    id: String,
1245    user_id: String,
1246    name: String,
1247    active: bool,
1248    is_default: bool,
1249    #[serde(deserialize_with = "deserialize_to_date")]
1250    created_at: DateTime<Utc>,
1251}