Skip to main content

binance_sdk/wallet/rest_api/apis/
account_api.rs

1/*
2 * Wallet REST API
3 *
4 * Query balances, manage assets, and perform wallet operations via the Binance Wallet API.
5 *
6 * The version of the OpenAPI document: 1.0.0
7 *
8 *
9 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
10 * https://openapi-generator.tech
11 * Do not edit the class manually.
12 */
13
14#![allow(unused_imports)]
15use async_trait::async_trait;
16use derive_builder::Builder;
17use reqwest;
18use rust_decimal::prelude::*;
19use serde::{Deserialize, Serialize};
20use serde_json::{Value, json};
21use std::collections::BTreeMap;
22
23use crate::common::{
24    config::ConfigurationRestApi,
25    models::{ParamBuildError, RestApiResponse},
26    utils::send_request,
27};
28use crate::wallet::rest_api::models;
29
30const HAS_TIME_UNIT: bool = false;
31
32#[async_trait]
33pub trait AccountApi: Send + Sync {
34    async fn account_api_trading_status(
35        &self,
36        params: AccountApiTradingStatusParams,
37    ) -> anyhow::Result<RestApiResponse<models::AccountApiTradingStatusResponse>>;
38    async fn account_info(
39        &self,
40        params: AccountInfoParams,
41    ) -> anyhow::Result<RestApiResponse<models::AccountInfoResponse>>;
42    async fn account_status(
43        &self,
44        params: AccountStatusParams,
45    ) -> anyhow::Result<RestApiResponse<models::AccountStatusResponse>>;
46    async fn daily_account_snapshot(
47        &self,
48        params: DailyAccountSnapshotParams,
49    ) -> anyhow::Result<RestApiResponse<models::DailyAccountSnapshotResponse>>;
50    async fn disable_fast_withdraw_switch(
51        &self,
52        params: DisableFastWithdrawSwitchParams,
53    ) -> anyhow::Result<RestApiResponse<Value>>;
54    async fn enable_fast_withdraw_switch(
55        &self,
56        params: EnableFastWithdrawSwitchParams,
57    ) -> anyhow::Result<RestApiResponse<Value>>;
58    async fn get_api_key_permission(
59        &self,
60        params: GetApiKeyPermissionParams,
61    ) -> anyhow::Result<RestApiResponse<models::GetApiKeyPermissionResponse>>;
62}
63
64#[derive(Debug, Clone)]
65pub struct AccountApiClient {
66    configuration: ConfigurationRestApi,
67}
68
69impl AccountApiClient {
70    pub fn new(configuration: ConfigurationRestApi) -> Self {
71        Self { configuration }
72    }
73}
74
75#[allow(non_camel_case_types)]
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub enum DailyAccountSnapshotTypeEnum {
78    #[serde(rename = "SPOT")]
79    Spot,
80    #[serde(rename = "MARGIN")]
81    Margin,
82    #[serde(rename = "FUTURES")]
83    Futures,
84}
85
86impl DailyAccountSnapshotTypeEnum {
87    #[must_use]
88    pub fn as_str(&self) -> &'static str {
89        match self {
90            Self::Spot => "SPOT",
91            Self::Margin => "MARGIN",
92            Self::Futures => "FUTURES",
93        }
94    }
95}
96
97impl std::str::FromStr for DailyAccountSnapshotTypeEnum {
98    type Err = Box<dyn std::error::Error + Send + Sync>;
99
100    fn from_str(s: &str) -> Result<Self, Self::Err> {
101        match s {
102            "SPOT" => Ok(Self::Spot),
103            "MARGIN" => Ok(Self::Margin),
104            "FUTURES" => Ok(Self::Futures),
105            other => Err(format!("invalid DailyAccountSnapshotTypeEnum: {}", other).into()),
106        }
107    }
108}
109
110/// Request parameters for the [`account_api_trading_status`] operation.
111///
112/// This struct holds all of the inputs you can pass when calling
113/// [`account_api_trading_status`](#method.account_api_trading_status).
114#[derive(Clone, Debug, Builder, Deserialize, Default)]
115#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
116pub struct AccountApiTradingStatusParams {
117    ///
118    /// The `recv_window` parameter.
119    ///
120    /// This field is **optional.
121    #[builder(setter(into), default)]
122    #[serde(rename = "recvWindow", default)]
123    pub recv_window: Option<i64>,
124}
125
126impl AccountApiTradingStatusParams {
127    /// Create a builder for [`account_api_trading_status`].
128    ///
129    #[must_use]
130    pub fn builder() -> AccountApiTradingStatusParamsBuilder {
131        AccountApiTradingStatusParamsBuilder::default()
132    }
133}
134/// Request parameters for the [`account_info`] operation.
135///
136/// This struct holds all of the inputs you can pass when calling
137/// [`account_info`](#method.account_info).
138#[derive(Clone, Debug, Builder, Deserialize, Default)]
139#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
140pub struct AccountInfoParams {
141    ///
142    /// The `recv_window` parameter.
143    ///
144    /// This field is **optional.
145    #[builder(setter(into), default)]
146    #[serde(rename = "recvWindow", default)]
147    pub recv_window: Option<i64>,
148}
149
150impl AccountInfoParams {
151    /// Create a builder for [`account_info`].
152    ///
153    #[must_use]
154    pub fn builder() -> AccountInfoParamsBuilder {
155        AccountInfoParamsBuilder::default()
156    }
157}
158/// Request parameters for the [`account_status`] operation.
159///
160/// This struct holds all of the inputs you can pass when calling
161/// [`account_status`](#method.account_status).
162#[derive(Clone, Debug, Builder, Deserialize, Default)]
163#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
164pub struct AccountStatusParams {
165    ///
166    /// The `recv_window` parameter.
167    ///
168    /// This field is **optional.
169    #[builder(setter(into), default)]
170    #[serde(rename = "recvWindow", default)]
171    pub recv_window: Option<i64>,
172}
173
174impl AccountStatusParams {
175    /// Create a builder for [`account_status`].
176    ///
177    #[must_use]
178    pub fn builder() -> AccountStatusParamsBuilder {
179        AccountStatusParamsBuilder::default()
180    }
181}
182/// Request parameters for the [`daily_account_snapshot`] operation.
183///
184/// This struct holds all of the inputs you can pass when calling
185/// [`daily_account_snapshot`](#method.daily_account_snapshot).
186#[derive(Clone, Debug, Builder, Deserialize)]
187#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
188pub struct DailyAccountSnapshotParams {
189    ///
190    /// The `r#type` parameter.
191    ///
192    /// This field is **required.
193    #[builder(setter(into))]
194    #[serde(rename = "type")]
195    pub r#type: DailyAccountSnapshotTypeEnum,
196    ///
197    /// The `start_time` parameter.
198    ///
199    /// This field is **optional.
200    #[builder(setter(into), default)]
201    #[serde(rename = "startTime", default)]
202    pub start_time: Option<i64>,
203    ///
204    /// The `end_time` parameter.
205    ///
206    /// This field is **optional.
207    #[builder(setter(into), default)]
208    #[serde(rename = "endTime", default)]
209    pub end_time: Option<i64>,
210    ///
211    /// The `limit` parameter.
212    ///
213    /// This field is **optional.
214    #[builder(setter(into), default)]
215    #[serde(rename = "limit", default)]
216    pub limit: Option<i64>,
217    ///
218    /// The `recv_window` parameter.
219    ///
220    /// This field is **optional.
221    #[builder(setter(into), default)]
222    #[serde(rename = "recvWindow", default)]
223    pub recv_window: Option<i64>,
224}
225
226impl DailyAccountSnapshotParams {
227    /// Create a builder for [`daily_account_snapshot`].
228    ///
229    /// Required parameters:
230    ///
231    /// * `r#type` — String
232    ///
233    #[must_use]
234    pub fn builder(r#type: DailyAccountSnapshotTypeEnum) -> DailyAccountSnapshotParamsBuilder {
235        DailyAccountSnapshotParamsBuilder::default().r#type(r#type)
236    }
237}
238/// Request parameters for the [`disable_fast_withdraw_switch`] operation.
239///
240/// This struct holds all of the inputs you can pass when calling
241/// [`disable_fast_withdraw_switch`](#method.disable_fast_withdraw_switch).
242#[derive(Clone, Debug, Builder, Deserialize, Default)]
243#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
244pub struct DisableFastWithdrawSwitchParams {
245    ///
246    /// The `recv_window` parameter.
247    ///
248    /// This field is **optional.
249    #[builder(setter(into), default)]
250    #[serde(rename = "recvWindow", default)]
251    pub recv_window: Option<i64>,
252}
253
254impl DisableFastWithdrawSwitchParams {
255    /// Create a builder for [`disable_fast_withdraw_switch`].
256    ///
257    #[must_use]
258    pub fn builder() -> DisableFastWithdrawSwitchParamsBuilder {
259        DisableFastWithdrawSwitchParamsBuilder::default()
260    }
261}
262/// Request parameters for the [`enable_fast_withdraw_switch`] operation.
263///
264/// This struct holds all of the inputs you can pass when calling
265/// [`enable_fast_withdraw_switch`](#method.enable_fast_withdraw_switch).
266#[derive(Clone, Debug, Builder, Deserialize, Default)]
267#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
268pub struct EnableFastWithdrawSwitchParams {
269    ///
270    /// The `recv_window` parameter.
271    ///
272    /// This field is **optional.
273    #[builder(setter(into), default)]
274    #[serde(rename = "recvWindow", default)]
275    pub recv_window: Option<i64>,
276}
277
278impl EnableFastWithdrawSwitchParams {
279    /// Create a builder for [`enable_fast_withdraw_switch`].
280    ///
281    #[must_use]
282    pub fn builder() -> EnableFastWithdrawSwitchParamsBuilder {
283        EnableFastWithdrawSwitchParamsBuilder::default()
284    }
285}
286/// Request parameters for the [`get_api_key_permission`] operation.
287///
288/// This struct holds all of the inputs you can pass when calling
289/// [`get_api_key_permission`](#method.get_api_key_permission).
290#[derive(Clone, Debug, Builder, Deserialize, Default)]
291#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
292pub struct GetApiKeyPermissionParams {
293    ///
294    /// The `recv_window` parameter.
295    ///
296    /// This field is **optional.
297    #[builder(setter(into), default)]
298    #[serde(rename = "recvWindow", default)]
299    pub recv_window: Option<i64>,
300}
301
302impl GetApiKeyPermissionParams {
303    /// Create a builder for [`get_api_key_permission`].
304    ///
305    #[must_use]
306    pub fn builder() -> GetApiKeyPermissionParamsBuilder {
307        GetApiKeyPermissionParamsBuilder::default()
308    }
309}
310
311#[async_trait]
312impl AccountApi for AccountApiClient {
313    async fn account_api_trading_status(
314        &self,
315        params: AccountApiTradingStatusParams,
316    ) -> anyhow::Result<RestApiResponse<models::AccountApiTradingStatusResponse>> {
317        let AccountApiTradingStatusParams { recv_window } = params;
318
319        let mut query_params = BTreeMap::new();
320        let body_params = BTreeMap::new();
321
322        if let Some(rw) = recv_window {
323            query_params.insert("recvWindow".to_string(), json!(rw));
324        }
325
326        send_request::<models::AccountApiTradingStatusResponse>(
327            &self.configuration,
328            "/sapi/v1/account/apiTradingStatus",
329            reqwest::Method::GET,
330            query_params,
331            body_params,
332            if HAS_TIME_UNIT {
333                self.configuration.time_unit
334            } else {
335                None
336            },
337            true,
338        )
339        .await
340    }
341
342    async fn account_info(
343        &self,
344        params: AccountInfoParams,
345    ) -> anyhow::Result<RestApiResponse<models::AccountInfoResponse>> {
346        let AccountInfoParams { recv_window } = params;
347
348        let mut query_params = BTreeMap::new();
349        let body_params = BTreeMap::new();
350
351        if let Some(rw) = recv_window {
352            query_params.insert("recvWindow".to_string(), json!(rw));
353        }
354
355        send_request::<models::AccountInfoResponse>(
356            &self.configuration,
357            "/sapi/v1/account/info",
358            reqwest::Method::GET,
359            query_params,
360            body_params,
361            if HAS_TIME_UNIT {
362                self.configuration.time_unit
363            } else {
364                None
365            },
366            true,
367        )
368        .await
369    }
370
371    async fn account_status(
372        &self,
373        params: AccountStatusParams,
374    ) -> anyhow::Result<RestApiResponse<models::AccountStatusResponse>> {
375        let AccountStatusParams { recv_window } = params;
376
377        let mut query_params = BTreeMap::new();
378        let body_params = BTreeMap::new();
379
380        if let Some(rw) = recv_window {
381            query_params.insert("recvWindow".to_string(), json!(rw));
382        }
383
384        send_request::<models::AccountStatusResponse>(
385            &self.configuration,
386            "/sapi/v1/account/status",
387            reqwest::Method::GET,
388            query_params,
389            body_params,
390            if HAS_TIME_UNIT {
391                self.configuration.time_unit
392            } else {
393                None
394            },
395            true,
396        )
397        .await
398    }
399
400    async fn daily_account_snapshot(
401        &self,
402        params: DailyAccountSnapshotParams,
403    ) -> anyhow::Result<RestApiResponse<models::DailyAccountSnapshotResponse>> {
404        let DailyAccountSnapshotParams {
405            r#type,
406            start_time,
407            end_time,
408            limit,
409            recv_window,
410        } = params;
411
412        let mut query_params = BTreeMap::new();
413        let body_params = BTreeMap::new();
414
415        query_params.insert("type".to_string(), json!(r#type));
416
417        if let Some(rw) = start_time {
418            query_params.insert("startTime".to_string(), json!(rw));
419        }
420
421        if let Some(rw) = end_time {
422            query_params.insert("endTime".to_string(), json!(rw));
423        }
424
425        if let Some(rw) = limit {
426            query_params.insert("limit".to_string(), json!(rw));
427        }
428
429        if let Some(rw) = recv_window {
430            query_params.insert("recvWindow".to_string(), json!(rw));
431        }
432
433        send_request::<models::DailyAccountSnapshotResponse>(
434            &self.configuration,
435            "/sapi/v1/accountSnapshot",
436            reqwest::Method::GET,
437            query_params,
438            body_params,
439            if HAS_TIME_UNIT {
440                self.configuration.time_unit
441            } else {
442                None
443            },
444            true,
445        )
446        .await
447    }
448
449    async fn disable_fast_withdraw_switch(
450        &self,
451        params: DisableFastWithdrawSwitchParams,
452    ) -> anyhow::Result<RestApiResponse<Value>> {
453        let DisableFastWithdrawSwitchParams { recv_window } = params;
454
455        let mut query_params = BTreeMap::new();
456        let body_params = BTreeMap::new();
457
458        if let Some(rw) = recv_window {
459            query_params.insert("recvWindow".to_string(), json!(rw));
460        }
461
462        send_request::<Value>(
463            &self.configuration,
464            "/sapi/v1/account/disableFastWithdrawSwitch",
465            reqwest::Method::POST,
466            query_params,
467            body_params,
468            if HAS_TIME_UNIT {
469                self.configuration.time_unit
470            } else {
471                None
472            },
473            true,
474        )
475        .await
476    }
477
478    async fn enable_fast_withdraw_switch(
479        &self,
480        params: EnableFastWithdrawSwitchParams,
481    ) -> anyhow::Result<RestApiResponse<Value>> {
482        let EnableFastWithdrawSwitchParams { recv_window } = params;
483
484        let mut query_params = BTreeMap::new();
485        let body_params = BTreeMap::new();
486
487        if let Some(rw) = recv_window {
488            query_params.insert("recvWindow".to_string(), json!(rw));
489        }
490
491        send_request::<Value>(
492            &self.configuration,
493            "/sapi/v1/account/enableFastWithdrawSwitch",
494            reqwest::Method::POST,
495            query_params,
496            body_params,
497            if HAS_TIME_UNIT {
498                self.configuration.time_unit
499            } else {
500                None
501            },
502            true,
503        )
504        .await
505    }
506
507    async fn get_api_key_permission(
508        &self,
509        params: GetApiKeyPermissionParams,
510    ) -> anyhow::Result<RestApiResponse<models::GetApiKeyPermissionResponse>> {
511        let GetApiKeyPermissionParams { recv_window } = params;
512
513        let mut query_params = BTreeMap::new();
514        let body_params = BTreeMap::new();
515
516        if let Some(rw) = recv_window {
517            query_params.insert("recvWindow".to_string(), json!(rw));
518        }
519
520        send_request::<models::GetApiKeyPermissionResponse>(
521            &self.configuration,
522            "/sapi/v1/account/apiRestrictions",
523            reqwest::Method::GET,
524            query_params,
525            body_params,
526            if HAS_TIME_UNIT {
527                self.configuration.time_unit
528            } else {
529                None
530            },
531            true,
532        )
533        .await
534    }
535}
536
537#[cfg(all(test, feature = "wallet"))]
538mod tests {
539    use super::*;
540    use crate::TOKIO_SHARED_RT;
541    use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
542    use async_trait::async_trait;
543    use std::collections::HashMap;
544
545    struct DummyRestApiResponse<T> {
546        inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
547        status: u16,
548        headers: HashMap<String, String>,
549        rate_limits: Option<Vec<RestApiRateLimit>>,
550    }
551
552    impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
553        fn from(dummy: DummyRestApiResponse<T>) -> Self {
554            Self {
555                data_fn: dummy.inner,
556                status: dummy.status,
557                headers: dummy.headers,
558                rate_limits: dummy.rate_limits,
559            }
560        }
561    }
562
563    struct MockAccountApiClient {
564        force_error: bool,
565    }
566
567    #[async_trait]
568    impl AccountApi for MockAccountApiClient {
569        async fn account_api_trading_status(
570            &self,
571            _params: AccountApiTradingStatusParams,
572        ) -> anyhow::Result<RestApiResponse<models::AccountApiTradingStatusResponse>> {
573            if self.force_error {
574                return Err(ConnectorError::ConnectorClientError {
575                    msg: "ResponseError".to_string(),
576                    code: None,
577                }
578                .into());
579            }
580
581            let resp_json: Value = serde_json::from_str(r#"{"data":{"isLocked":false,"plannedRecoverTime":0,"triggerCondition":{"GCR":150,"IFER":150,"UFR":300},"updateTime":1547630471725}}"#).unwrap_or_else(|_| serde_json::json!({}));
582            let dummy_response: models::AccountApiTradingStatusResponse =
583                serde_json::from_value(resp_json.clone())
584                    .expect("should parse into models::AccountApiTradingStatusResponse");
585
586            let dummy = DummyRestApiResponse {
587                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
588                status: 200,
589                headers: HashMap::new(),
590                rate_limits: None,
591            };
592
593            Ok(dummy.into())
594        }
595
596        async fn account_info(
597            &self,
598            _params: AccountInfoParams,
599        ) -> anyhow::Result<RestApiResponse<models::AccountInfoResponse>> {
600            if self.force_error {
601                return Err(ConnectorError::ConnectorClientError {
602                    msg: "ResponseError".to_string(),
603                    code: None,
604                }
605                .into());
606            }
607
608            let resp_json: Value = serde_json::from_str(r#"{"vipLevel":0,"isMarginEnabled":true,"isFutureEnabled":true,"isOptionsEnabled":true,"isPortfolioMarginRetailEnabled":true}"#).unwrap_or_else(|_| serde_json::json!({}));
609            let dummy_response: models::AccountInfoResponse =
610                serde_json::from_value(resp_json.clone())
611                    .expect("should parse into models::AccountInfoResponse");
612
613            let dummy = DummyRestApiResponse {
614                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
615                status: 200,
616                headers: HashMap::new(),
617                rate_limits: None,
618            };
619
620            Ok(dummy.into())
621        }
622
623        async fn account_status(
624            &self,
625            _params: AccountStatusParams,
626        ) -> anyhow::Result<RestApiResponse<models::AccountStatusResponse>> {
627            if self.force_error {
628                return Err(ConnectorError::ConnectorClientError {
629                    msg: "ResponseError".to_string(),
630                    code: None,
631                }
632                .into());
633            }
634
635            let resp_json: Value = serde_json::from_str(r#"{"data":"Normal"}"#)
636                .unwrap_or_else(|_| serde_json::json!({}));
637            let dummy_response: models::AccountStatusResponse =
638                serde_json::from_value(resp_json.clone())
639                    .expect("should parse into models::AccountStatusResponse");
640
641            let dummy = DummyRestApiResponse {
642                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
643                status: 200,
644                headers: HashMap::new(),
645                rate_limits: None,
646            };
647
648            Ok(dummy.into())
649        }
650
651        async fn daily_account_snapshot(
652            &self,
653            _params: DailyAccountSnapshotParams,
654        ) -> anyhow::Result<RestApiResponse<models::DailyAccountSnapshotResponse>> {
655            if self.force_error {
656                return Err(ConnectorError::ConnectorClientError {
657                    msg: "ResponseError".to_string(),
658                    code: None,
659                }
660                .into());
661            }
662
663            let resp_json: Value = serde_json::from_str(r#"{"code":200,"msg":"","snapshotVos":[{"data":{"balances":[{"asset":"BTC","free":"0.09905021","locked":"0.00000000"}],"totalAssetOfBtc":"0.09942700","marginLevel":"2748.02909813","totalLiabilityOfBtc":"0.00000100","totalNetAssetOfBtc":"0.00274750","userAssets":[{"asset":"XRP","borrowed":"0.00000000","free":"1.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"1.00000000"}],"assets":[{"asset":"USDT","marginBalance":"118.99782335","walletBalance":"120.23811389"}],"position":[{"entryPrice":"7130.41000000","markPrice":"7257.66239673","positionAmt":"0.01000000","symbol":"BTCUSDT","unRealizedProfit":"1.24029054"}]},"type":"spot","updateTime":1576281599000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
664            let dummy_response: models::DailyAccountSnapshotResponse =
665                serde_json::from_value(resp_json.clone())
666                    .expect("should parse into models::DailyAccountSnapshotResponse");
667
668            let dummy = DummyRestApiResponse {
669                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
670                status: 200,
671                headers: HashMap::new(),
672                rate_limits: None,
673            };
674
675            Ok(dummy.into())
676        }
677
678        async fn disable_fast_withdraw_switch(
679            &self,
680            _params: DisableFastWithdrawSwitchParams,
681        ) -> anyhow::Result<RestApiResponse<Value>> {
682            if self.force_error {
683                return Err(ConnectorError::ConnectorClientError {
684                    msg: "ResponseError".to_string(),
685                    code: None,
686                }
687                .into());
688            }
689
690            let dummy_response = Value::Null;
691
692            let dummy = DummyRestApiResponse {
693                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
694                status: 200,
695                headers: HashMap::new(),
696                rate_limits: None,
697            };
698
699            Ok(dummy.into())
700        }
701
702        async fn enable_fast_withdraw_switch(
703            &self,
704            _params: EnableFastWithdrawSwitchParams,
705        ) -> anyhow::Result<RestApiResponse<Value>> {
706            if self.force_error {
707                return Err(ConnectorError::ConnectorClientError {
708                    msg: "ResponseError".to_string(),
709                    code: None,
710                }
711                .into());
712            }
713
714            let dummy_response = Value::Null;
715
716            let dummy = DummyRestApiResponse {
717                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
718                status: 200,
719                headers: HashMap::new(),
720                rate_limits: None,
721            };
722
723            Ok(dummy.into())
724        }
725
726        async fn get_api_key_permission(
727            &self,
728            _params: GetApiKeyPermissionParams,
729        ) -> anyhow::Result<RestApiResponse<models::GetApiKeyPermissionResponse>> {
730            if self.force_error {
731                return Err(ConnectorError::ConnectorClientError {
732                    msg: "ResponseError".to_string(),
733                    code: None,
734                }
735                .into());
736            }
737
738            let resp_json: Value = serde_json::from_str(r#"{"ipRestrict":false,"createTime":1623840271000,"enableReading":true,"enableWithdrawals":false,"enableInternalTransfer":true,"enableMargin":false,"enableFutures":false,"permitsUniversalTransfer":true,"enableVanillaOptions":false,"enableFixApiTrade":false,"enableFixReadOnly":true,"enableSpotAndMarginTrading":false,"enablePortfolioMarginTrading":true}"#).unwrap_or_else(|_| serde_json::json!({}));
739            let dummy_response: models::GetApiKeyPermissionResponse =
740                serde_json::from_value(resp_json.clone())
741                    .expect("should parse into models::GetApiKeyPermissionResponse");
742
743            let dummy = DummyRestApiResponse {
744                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
745                status: 200,
746                headers: HashMap::new(),
747                rate_limits: None,
748            };
749
750            Ok(dummy.into())
751        }
752    }
753
754    #[test]
755    fn account_api_trading_status_required_params_success() {
756        TOKIO_SHARED_RT.block_on(async {
757            let client = MockAccountApiClient { force_error: false };
758
759            let params = AccountApiTradingStatusParams::builder().build().unwrap();
760
761            let resp_json: Value = serde_json::from_str(r#"{"data":{"isLocked":false,"plannedRecoverTime":0,"triggerCondition":{"GCR":150,"IFER":150,"UFR":300},"updateTime":1547630471725}}"#).unwrap_or_else(|_| serde_json::json!({}));
762            let expected_response : models::AccountApiTradingStatusResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AccountApiTradingStatusResponse");
763
764            let resp = client.account_api_trading_status(params).await.expect("Expected a response");
765            let data_future = resp.data();
766            let actual_response = data_future.await.unwrap();
767            assert_eq!(actual_response, expected_response);
768        });
769    }
770
771    #[test]
772    fn account_api_trading_status_optional_params_success() {
773        TOKIO_SHARED_RT.block_on(async {
774            let client = MockAccountApiClient { force_error: false };
775
776            let params = AccountApiTradingStatusParams::builder().recv_window(5000).build().unwrap();
777
778            let resp_json: Value = serde_json::from_str(r#"{"data":{"isLocked":false,"plannedRecoverTime":0,"triggerCondition":{"GCR":150,"IFER":150,"UFR":300},"updateTime":1547630471725}}"#).unwrap_or_else(|_| serde_json::json!({}));
779            let expected_response : models::AccountApiTradingStatusResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AccountApiTradingStatusResponse");
780
781            let resp = client.account_api_trading_status(params).await.expect("Expected a response");
782            let data_future = resp.data();
783            let actual_response = data_future.await.unwrap();
784            assert_eq!(actual_response, expected_response);
785        });
786    }
787
788    #[test]
789    fn account_api_trading_status_response_error() {
790        TOKIO_SHARED_RT.block_on(async {
791            let client = MockAccountApiClient { force_error: true };
792
793            let params = AccountApiTradingStatusParams::builder().build().unwrap();
794
795            match client.account_api_trading_status(params).await {
796                Ok(_) => panic!("Expected an error"),
797                Err(err) => {
798                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
799                }
800            }
801        });
802    }
803
804    #[test]
805    fn account_info_required_params_success() {
806        TOKIO_SHARED_RT.block_on(async {
807            let client = MockAccountApiClient { force_error: false };
808
809            let params = AccountInfoParams::builder().build().unwrap();
810
811            let resp_json: Value = serde_json::from_str(r#"{"vipLevel":0,"isMarginEnabled":true,"isFutureEnabled":true,"isOptionsEnabled":true,"isPortfolioMarginRetailEnabled":true}"#).unwrap_or_else(|_| serde_json::json!({}));
812            let expected_response : models::AccountInfoResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AccountInfoResponse");
813
814            let resp = client.account_info(params).await.expect("Expected a response");
815            let data_future = resp.data();
816            let actual_response = data_future.await.unwrap();
817            assert_eq!(actual_response, expected_response);
818        });
819    }
820
821    #[test]
822    fn account_info_optional_params_success() {
823        TOKIO_SHARED_RT.block_on(async {
824            let client = MockAccountApiClient { force_error: false };
825
826            let params = AccountInfoParams::builder().recv_window(5000).build().unwrap();
827
828            let resp_json: Value = serde_json::from_str(r#"{"vipLevel":0,"isMarginEnabled":true,"isFutureEnabled":true,"isOptionsEnabled":true,"isPortfolioMarginRetailEnabled":true}"#).unwrap_or_else(|_| serde_json::json!({}));
829            let expected_response : models::AccountInfoResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AccountInfoResponse");
830
831            let resp = client.account_info(params).await.expect("Expected a response");
832            let data_future = resp.data();
833            let actual_response = data_future.await.unwrap();
834            assert_eq!(actual_response, expected_response);
835        });
836    }
837
838    #[test]
839    fn account_info_response_error() {
840        TOKIO_SHARED_RT.block_on(async {
841            let client = MockAccountApiClient { force_error: true };
842
843            let params = AccountInfoParams::builder().build().unwrap();
844
845            match client.account_info(params).await {
846                Ok(_) => panic!("Expected an error"),
847                Err(err) => {
848                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
849                }
850            }
851        });
852    }
853
854    #[test]
855    fn account_status_required_params_success() {
856        TOKIO_SHARED_RT.block_on(async {
857            let client = MockAccountApiClient { force_error: false };
858
859            let params = AccountStatusParams::builder().build().unwrap();
860
861            let resp_json: Value = serde_json::from_str(r#"{"data":"Normal"}"#)
862                .unwrap_or_else(|_| serde_json::json!({}));
863            let expected_response: models::AccountStatusResponse =
864                serde_json::from_value(resp_json.clone())
865                    .expect("should parse into models::AccountStatusResponse");
866
867            let resp = client
868                .account_status(params)
869                .await
870                .expect("Expected a response");
871            let data_future = resp.data();
872            let actual_response = data_future.await.unwrap();
873            assert_eq!(actual_response, expected_response);
874        });
875    }
876
877    #[test]
878    fn account_status_optional_params_success() {
879        TOKIO_SHARED_RT.block_on(async {
880            let client = MockAccountApiClient { force_error: false };
881
882            let params = AccountStatusParams::builder()
883                .recv_window(5000)
884                .build()
885                .unwrap();
886
887            let resp_json: Value = serde_json::from_str(r#"{"data":"Normal"}"#)
888                .unwrap_or_else(|_| serde_json::json!({}));
889            let expected_response: models::AccountStatusResponse =
890                serde_json::from_value(resp_json.clone())
891                    .expect("should parse into models::AccountStatusResponse");
892
893            let resp = client
894                .account_status(params)
895                .await
896                .expect("Expected a response");
897            let data_future = resp.data();
898            let actual_response = data_future.await.unwrap();
899            assert_eq!(actual_response, expected_response);
900        });
901    }
902
903    #[test]
904    fn account_status_response_error() {
905        TOKIO_SHARED_RT.block_on(async {
906            let client = MockAccountApiClient { force_error: true };
907
908            let params = AccountStatusParams::builder().build().unwrap();
909
910            match client.account_status(params).await {
911                Ok(_) => panic!("Expected an error"),
912                Err(err) => {
913                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
914                }
915            }
916        });
917    }
918
919    #[test]
920    fn daily_account_snapshot_required_params_success() {
921        TOKIO_SHARED_RT.block_on(async {
922            let client = MockAccountApiClient { force_error: false };
923
924            let params = DailyAccountSnapshotParams::builder(DailyAccountSnapshotTypeEnum::Spot,).build().unwrap();
925
926            let resp_json: Value = serde_json::from_str(r#"{"code":200,"msg":"","snapshotVos":[{"data":{"balances":[{"asset":"BTC","free":"0.09905021","locked":"0.00000000"}],"totalAssetOfBtc":"0.09942700","marginLevel":"2748.02909813","totalLiabilityOfBtc":"0.00000100","totalNetAssetOfBtc":"0.00274750","userAssets":[{"asset":"XRP","borrowed":"0.00000000","free":"1.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"1.00000000"}],"assets":[{"asset":"USDT","marginBalance":"118.99782335","walletBalance":"120.23811389"}],"position":[{"entryPrice":"7130.41000000","markPrice":"7257.66239673","positionAmt":"0.01000000","symbol":"BTCUSDT","unRealizedProfit":"1.24029054"}]},"type":"spot","updateTime":1576281599000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
927            let expected_response : models::DailyAccountSnapshotResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DailyAccountSnapshotResponse");
928
929            let resp = client.daily_account_snapshot(params).await.expect("Expected a response");
930            let data_future = resp.data();
931            let actual_response = data_future.await.unwrap();
932            assert_eq!(actual_response, expected_response);
933        });
934    }
935
936    #[test]
937    fn daily_account_snapshot_optional_params_success() {
938        TOKIO_SHARED_RT.block_on(async {
939            let client = MockAccountApiClient { force_error: false };
940
941            let params = DailyAccountSnapshotParams::builder(DailyAccountSnapshotTypeEnum::Spot,).start_time(1623319461670).end_time(1641782889000).limit(7).recv_window(5000).build().unwrap();
942
943            let resp_json: Value = serde_json::from_str(r#"{"code":200,"msg":"","snapshotVos":[{"data":{"balances":[{"asset":"BTC","free":"0.09905021","locked":"0.00000000"}],"totalAssetOfBtc":"0.09942700","marginLevel":"2748.02909813","totalLiabilityOfBtc":"0.00000100","totalNetAssetOfBtc":"0.00274750","userAssets":[{"asset":"XRP","borrowed":"0.00000000","free":"1.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"1.00000000"}],"assets":[{"asset":"USDT","marginBalance":"118.99782335","walletBalance":"120.23811389"}],"position":[{"entryPrice":"7130.41000000","markPrice":"7257.66239673","positionAmt":"0.01000000","symbol":"BTCUSDT","unRealizedProfit":"1.24029054"}]},"type":"spot","updateTime":1576281599000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
944            let expected_response : models::DailyAccountSnapshotResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DailyAccountSnapshotResponse");
945
946            let resp = client.daily_account_snapshot(params).await.expect("Expected a response");
947            let data_future = resp.data();
948            let actual_response = data_future.await.unwrap();
949            assert_eq!(actual_response, expected_response);
950        });
951    }
952
953    #[test]
954    fn daily_account_snapshot_response_error() {
955        TOKIO_SHARED_RT.block_on(async {
956            let client = MockAccountApiClient { force_error: true };
957
958            let params = DailyAccountSnapshotParams::builder(DailyAccountSnapshotTypeEnum::Spot)
959                .build()
960                .unwrap();
961
962            match client.daily_account_snapshot(params).await {
963                Ok(_) => panic!("Expected an error"),
964                Err(err) => {
965                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
966                }
967            }
968        });
969    }
970
971    #[test]
972    fn disable_fast_withdraw_switch_required_params_success() {
973        TOKIO_SHARED_RT.block_on(async {
974            let client = MockAccountApiClient { force_error: false };
975
976            let params = DisableFastWithdrawSwitchParams::builder().build().unwrap();
977
978            let expected_response = Value::Null;
979
980            let resp = client
981                .disable_fast_withdraw_switch(params)
982                .await
983                .expect("Expected a response");
984            let data_future = resp.data();
985            let actual_response = data_future.await.unwrap();
986            assert_eq!(actual_response, expected_response);
987        });
988    }
989
990    #[test]
991    fn disable_fast_withdraw_switch_optional_params_success() {
992        TOKIO_SHARED_RT.block_on(async {
993            let client = MockAccountApiClient { force_error: false };
994
995            let params = DisableFastWithdrawSwitchParams::builder()
996                .recv_window(5000)
997                .build()
998                .unwrap();
999
1000            let expected_response = Value::Null;
1001
1002            let resp = client
1003                .disable_fast_withdraw_switch(params)
1004                .await
1005                .expect("Expected a response");
1006            let data_future = resp.data();
1007            let actual_response = data_future.await.unwrap();
1008            assert_eq!(actual_response, expected_response);
1009        });
1010    }
1011
1012    #[test]
1013    fn disable_fast_withdraw_switch_response_error() {
1014        TOKIO_SHARED_RT.block_on(async {
1015            let client = MockAccountApiClient { force_error: true };
1016
1017            let params = DisableFastWithdrawSwitchParams::builder().build().unwrap();
1018
1019            match client.disable_fast_withdraw_switch(params).await {
1020                Ok(_) => panic!("Expected an error"),
1021                Err(err) => {
1022                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1023                }
1024            }
1025        });
1026    }
1027
1028    #[test]
1029    fn enable_fast_withdraw_switch_required_params_success() {
1030        TOKIO_SHARED_RT.block_on(async {
1031            let client = MockAccountApiClient { force_error: false };
1032
1033            let params = EnableFastWithdrawSwitchParams::builder().build().unwrap();
1034
1035            let expected_response = Value::Null;
1036
1037            let resp = client
1038                .enable_fast_withdraw_switch(params)
1039                .await
1040                .expect("Expected a response");
1041            let data_future = resp.data();
1042            let actual_response = data_future.await.unwrap();
1043            assert_eq!(actual_response, expected_response);
1044        });
1045    }
1046
1047    #[test]
1048    fn enable_fast_withdraw_switch_optional_params_success() {
1049        TOKIO_SHARED_RT.block_on(async {
1050            let client = MockAccountApiClient { force_error: false };
1051
1052            let params = EnableFastWithdrawSwitchParams::builder()
1053                .recv_window(5000)
1054                .build()
1055                .unwrap();
1056
1057            let expected_response = Value::Null;
1058
1059            let resp = client
1060                .enable_fast_withdraw_switch(params)
1061                .await
1062                .expect("Expected a response");
1063            let data_future = resp.data();
1064            let actual_response = data_future.await.unwrap();
1065            assert_eq!(actual_response, expected_response);
1066        });
1067    }
1068
1069    #[test]
1070    fn enable_fast_withdraw_switch_response_error() {
1071        TOKIO_SHARED_RT.block_on(async {
1072            let client = MockAccountApiClient { force_error: true };
1073
1074            let params = EnableFastWithdrawSwitchParams::builder().build().unwrap();
1075
1076            match client.enable_fast_withdraw_switch(params).await {
1077                Ok(_) => panic!("Expected an error"),
1078                Err(err) => {
1079                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1080                }
1081            }
1082        });
1083    }
1084
1085    #[test]
1086    fn get_api_key_permission_required_params_success() {
1087        TOKIO_SHARED_RT.block_on(async {
1088            let client = MockAccountApiClient { force_error: false };
1089
1090            let params = GetApiKeyPermissionParams::builder().build().unwrap();
1091
1092            let resp_json: Value = serde_json::from_str(r#"{"ipRestrict":false,"createTime":1623840271000,"enableReading":true,"enableWithdrawals":false,"enableInternalTransfer":true,"enableMargin":false,"enableFutures":false,"permitsUniversalTransfer":true,"enableVanillaOptions":false,"enableFixApiTrade":false,"enableFixReadOnly":true,"enableSpotAndMarginTrading":false,"enablePortfolioMarginTrading":true}"#).unwrap_or_else(|_| serde_json::json!({}));
1093            let expected_response : models::GetApiKeyPermissionResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetApiKeyPermissionResponse");
1094
1095            let resp = client.get_api_key_permission(params).await.expect("Expected a response");
1096            let data_future = resp.data();
1097            let actual_response = data_future.await.unwrap();
1098            assert_eq!(actual_response, expected_response);
1099        });
1100    }
1101
1102    #[test]
1103    fn get_api_key_permission_optional_params_success() {
1104        TOKIO_SHARED_RT.block_on(async {
1105            let client = MockAccountApiClient { force_error: false };
1106
1107            let params = GetApiKeyPermissionParams::builder().recv_window(5000).build().unwrap();
1108
1109            let resp_json: Value = serde_json::from_str(r#"{"ipRestrict":false,"createTime":1623840271000,"enableReading":true,"enableWithdrawals":false,"enableInternalTransfer":true,"enableMargin":false,"enableFutures":false,"permitsUniversalTransfer":true,"enableVanillaOptions":false,"enableFixApiTrade":false,"enableFixReadOnly":true,"enableSpotAndMarginTrading":false,"enablePortfolioMarginTrading":true}"#).unwrap_or_else(|_| serde_json::json!({}));
1110            let expected_response : models::GetApiKeyPermissionResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetApiKeyPermissionResponse");
1111
1112            let resp = client.get_api_key_permission(params).await.expect("Expected a response");
1113            let data_future = resp.data();
1114            let actual_response = data_future.await.unwrap();
1115            assert_eq!(actual_response, expected_response);
1116        });
1117    }
1118
1119    #[test]
1120    fn get_api_key_permission_response_error() {
1121        TOKIO_SHARED_RT.block_on(async {
1122            let client = MockAccountApiClient { force_error: true };
1123
1124            let params = GetApiKeyPermissionParams::builder().build().unwrap();
1125
1126            match client.get_api_key_permission(params).await {
1127                Ok(_) => panic!("Expected an error"),
1128                Err(err) => {
1129                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
1130                }
1131            }
1132        });
1133    }
1134}