Skip to main content

binance_sdk/wallet/rest_api/apis/
asset_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 AssetApi: Send + Sync {
34    async fn asset_detail(
35        &self,
36        params: AssetDetailParams,
37    ) -> anyhow::Result<RestApiResponse<models::AssetDetailResponse>>;
38    async fn asset_dividend_record(
39        &self,
40        params: AssetDividendRecordParams,
41    ) -> anyhow::Result<RestApiResponse<models::AssetDividendRecordResponse>>;
42    async fn dust_convert(
43        &self,
44        params: DustConvertParams,
45    ) -> anyhow::Result<RestApiResponse<models::DustConvertResponse>>;
46    async fn dust_convertible_assets(
47        &self,
48        params: DustConvertibleAssetsParams,
49    ) -> anyhow::Result<RestApiResponse<models::DustConvertibleAssetsResponse>>;
50    async fn dust_transfer(
51        &self,
52        params: DustTransferParams,
53    ) -> anyhow::Result<RestApiResponse<models::DustTransferResponse>>;
54    async fn dustlog(
55        &self,
56        params: DustlogParams,
57    ) -> anyhow::Result<RestApiResponse<models::DustlogResponse>>;
58    async fn funding_wallet(
59        &self,
60        params: FundingWalletParams,
61    ) -> anyhow::Result<RestApiResponse<Vec<models::FundingWalletResponseInner>>>;
62    async fn get_assets_that_can_be_converted_into_bnb(
63        &self,
64        params: GetAssetsThatCanBeConvertedIntoBnbParams,
65    ) -> anyhow::Result<RestApiResponse<models::GetAssetsThatCanBeConvertedIntoBnbResponse>>;
66    async fn get_cloud_mining_payment_and_refund_history(
67        &self,
68        params: GetCloudMiningPaymentAndRefundHistoryParams,
69    ) -> anyhow::Result<RestApiResponse<models::GetCloudMiningPaymentAndRefundHistoryResponse>>;
70    async fn get_open_symbol_list(
71        &self,
72    ) -> anyhow::Result<RestApiResponse<Vec<models::GetOpenSymbolListResponseInner>>>;
73    async fn get_spot_asset_tags(
74        &self,
75        params: GetSpotAssetTagsParams,
76    ) -> anyhow::Result<RestApiResponse<Vec<models::GetSpotAssetTagsResponseInner>>>;
77    async fn query_user_delegation_history(
78        &self,
79        params: QueryUserDelegationHistoryParams,
80    ) -> anyhow::Result<RestApiResponse<models::QueryUserDelegationHistoryResponse>>;
81    async fn query_user_universal_transfer_history(
82        &self,
83        params: QueryUserUniversalTransferHistoryParams,
84    ) -> anyhow::Result<RestApiResponse<models::QueryUserUniversalTransferHistoryResponse>>;
85    async fn query_user_wallet_balance(
86        &self,
87        params: QueryUserWalletBalanceParams,
88    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryUserWalletBalanceResponseInner>>>;
89    async fn toggle_bnb_burn_on_spot_trade_and_margin_interest(
90        &self,
91        params: ToggleBnbBurnOnSpotTradeAndMarginInterestParams,
92    ) -> anyhow::Result<RestApiResponse<models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse>>;
93    async fn trade_fee(
94        &self,
95        params: TradeFeeParams,
96    ) -> anyhow::Result<RestApiResponse<Vec<models::TradeFeeResponseInner>>>;
97    async fn user_asset(
98        &self,
99        params: UserAssetParams,
100    ) -> anyhow::Result<RestApiResponse<Vec<models::UserAssetResponseInner>>>;
101    async fn user_universal_transfer(
102        &self,
103        params: UserUniversalTransferParams,
104    ) -> anyhow::Result<RestApiResponse<models::UserUniversalTransferResponse>>;
105}
106
107#[derive(Debug, Clone)]
108pub struct AssetApiClient {
109    configuration: ConfigurationRestApi,
110}
111
112impl AssetApiClient {
113    pub fn new(configuration: ConfigurationRestApi) -> Self {
114        Self { configuration }
115    }
116}
117
118#[allow(non_camel_case_types)]
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub enum DustTransferAccountTypeEnum {
121    #[serde(rename = "SPOT")]
122    Spot,
123    #[serde(rename = "MARGIN")]
124    Margin,
125}
126
127impl DustTransferAccountTypeEnum {
128    #[must_use]
129    pub fn as_str(&self) -> &'static str {
130        match self {
131            Self::Spot => "SPOT",
132            Self::Margin => "MARGIN",
133        }
134    }
135}
136
137impl std::str::FromStr for DustTransferAccountTypeEnum {
138    type Err = Box<dyn std::error::Error + Send + Sync>;
139
140    fn from_str(s: &str) -> Result<Self, Self::Err> {
141        match s {
142            "SPOT" => Ok(Self::Spot),
143            "MARGIN" => Ok(Self::Margin),
144            other => Err(format!("invalid DustTransferAccountTypeEnum: {}", other).into()),
145        }
146    }
147}
148
149#[allow(non_camel_case_types)]
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub enum DustlogAccountTypeEnum {
152    #[serde(rename = "SPOT")]
153    Spot,
154    #[serde(rename = "MARGIN")]
155    Margin,
156}
157
158impl DustlogAccountTypeEnum {
159    #[must_use]
160    pub fn as_str(&self) -> &'static str {
161        match self {
162            Self::Spot => "SPOT",
163            Self::Margin => "MARGIN",
164        }
165    }
166}
167
168impl std::str::FromStr for DustlogAccountTypeEnum {
169    type Err = Box<dyn std::error::Error + Send + Sync>;
170
171    fn from_str(s: &str) -> Result<Self, Self::Err> {
172        match s {
173            "SPOT" => Ok(Self::Spot),
174            "MARGIN" => Ok(Self::Margin),
175            other => Err(format!("invalid DustlogAccountTypeEnum: {}", other).into()),
176        }
177    }
178}
179
180#[allow(non_camel_case_types)]
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub enum GetAssetsThatCanBeConvertedIntoBnbAccountTypeEnum {
183    #[serde(rename = "SPOT")]
184    Spot,
185    #[serde(rename = "MARGIN")]
186    Margin,
187}
188
189impl GetAssetsThatCanBeConvertedIntoBnbAccountTypeEnum {
190    #[must_use]
191    pub fn as_str(&self) -> &'static str {
192        match self {
193            Self::Spot => "SPOT",
194            Self::Margin => "MARGIN",
195        }
196    }
197}
198
199impl std::str::FromStr for GetAssetsThatCanBeConvertedIntoBnbAccountTypeEnum {
200    type Err = Box<dyn std::error::Error + Send + Sync>;
201
202    fn from_str(s: &str) -> Result<Self, Self::Err> {
203        match s {
204            "SPOT" => Ok(Self::Spot),
205            "MARGIN" => Ok(Self::Margin),
206            other => Err(format!(
207                "invalid GetAssetsThatCanBeConvertedIntoBnbAccountTypeEnum: {}",
208                other
209            )
210            .into()),
211        }
212    }
213}
214
215#[allow(non_camel_case_types)]
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub enum QueryUserDelegationHistoryTypeEnum {
218    #[serde(rename = "DELEGATE")]
219    Delegate,
220    #[serde(rename = "UNDELEGATE")]
221    Undelegate,
222}
223
224impl QueryUserDelegationHistoryTypeEnum {
225    #[must_use]
226    pub fn as_str(&self) -> &'static str {
227        match self {
228            Self::Delegate => "DELEGATE",
229            Self::Undelegate => "UNDELEGATE",
230        }
231    }
232}
233
234impl std::str::FromStr for QueryUserDelegationHistoryTypeEnum {
235    type Err = Box<dyn std::error::Error + Send + Sync>;
236
237    fn from_str(s: &str) -> Result<Self, Self::Err> {
238        match s {
239            "DELEGATE" => Ok(Self::Delegate),
240            "UNDELEGATE" => Ok(Self::Undelegate),
241            other => Err(format!("invalid QueryUserDelegationHistoryTypeEnum: {}", other).into()),
242        }
243    }
244}
245
246#[allow(non_camel_case_types)]
247#[derive(Debug, Clone, Serialize, Deserialize)]
248pub enum QueryUserUniversalTransferHistoryFromSymbolEnum {
249    #[serde(rename = "ISOLATEDMARGIN_MARGIN")]
250    IsolatedmarginMargin,
251    #[serde(rename = "ISOLATEDMARGIN_ISOLATEDMARGIN")]
252    IsolatedmarginIsolatedmargin,
253}
254
255impl QueryUserUniversalTransferHistoryFromSymbolEnum {
256    #[must_use]
257    pub fn as_str(&self) -> &'static str {
258        match self {
259            Self::IsolatedmarginMargin => "ISOLATEDMARGIN_MARGIN",
260            Self::IsolatedmarginIsolatedmargin => "ISOLATEDMARGIN_ISOLATEDMARGIN",
261        }
262    }
263}
264
265impl std::str::FromStr for QueryUserUniversalTransferHistoryFromSymbolEnum {
266    type Err = Box<dyn std::error::Error + Send + Sync>;
267
268    fn from_str(s: &str) -> Result<Self, Self::Err> {
269        match s {
270            "ISOLATEDMARGIN_MARGIN" => Ok(Self::IsolatedmarginMargin),
271            "ISOLATEDMARGIN_ISOLATEDMARGIN" => Ok(Self::IsolatedmarginIsolatedmargin),
272            other => Err(format!(
273                "invalid QueryUserUniversalTransferHistoryFromSymbolEnum: {}",
274                other
275            )
276            .into()),
277        }
278    }
279}
280
281#[allow(non_camel_case_types)]
282#[derive(Debug, Clone, Serialize, Deserialize)]
283pub enum QueryUserUniversalTransferHistoryToSymbolEnum {
284    #[serde(rename = "MARGIN_ISOLATEDMARGIN")]
285    MarginIsolatedmargin,
286    #[serde(rename = "ISOLATEDMARGIN_ISOLATEDMARGIN")]
287    IsolatedmarginIsolatedmargin,
288}
289
290impl QueryUserUniversalTransferHistoryToSymbolEnum {
291    #[must_use]
292    pub fn as_str(&self) -> &'static str {
293        match self {
294            Self::MarginIsolatedmargin => "MARGIN_ISOLATEDMARGIN",
295            Self::IsolatedmarginIsolatedmargin => "ISOLATEDMARGIN_ISOLATEDMARGIN",
296        }
297    }
298}
299
300impl std::str::FromStr for QueryUserUniversalTransferHistoryToSymbolEnum {
301    type Err = Box<dyn std::error::Error + Send + Sync>;
302
303    fn from_str(s: &str) -> Result<Self, Self::Err> {
304        match s {
305            "MARGIN_ISOLATEDMARGIN" => Ok(Self::MarginIsolatedmargin),
306            "ISOLATEDMARGIN_ISOLATEDMARGIN" => Ok(Self::IsolatedmarginIsolatedmargin),
307            other => Err(format!(
308                "invalid QueryUserUniversalTransferHistoryToSymbolEnum: {}",
309                other
310            )
311            .into()),
312        }
313    }
314}
315
316#[allow(non_camel_case_types)]
317#[derive(Debug, Clone, Serialize, Deserialize)]
318pub enum UserUniversalTransferTypeEnum {
319    #[serde(rename = "MAIN_UMFUTURE")]
320    MainUmfuture,
321    #[serde(rename = "MAIN_CMFUTURE")]
322    MainCmfuture,
323    #[serde(rename = "MAIN_MARGIN")]
324    MainMargin,
325    #[serde(rename = "UMFUTURE_MAIN")]
326    UmfutureMain,
327    #[serde(rename = "UMFUTURE_MARGIN")]
328    UmfutureMargin,
329    #[serde(rename = "CMFUTURE_MAIN")]
330    CmfutureMain,
331    #[serde(rename = "CMFUTURE_MARGIN")]
332    CmfutureMargin,
333    #[serde(rename = "MARGIN_MAIN")]
334    MarginMain,
335    #[serde(rename = "MARGIN_UMFUTURE")]
336    MarginUmfuture,
337    #[serde(rename = "MARGIN_CMFUTURE")]
338    MarginCmfuture,
339    #[serde(rename = "ISOLATEDMARGIN_MARGIN")]
340    IsolatedmarginMargin,
341    #[serde(rename = "MARGIN_ISOLATEDMARGIN")]
342    MarginIsolatedmargin,
343    #[serde(rename = "ISOLATEDMARGIN_ISOLATEDMARGIN")]
344    IsolatedmarginIsolatedmargin,
345    #[serde(rename = "MAIN_FUNDING")]
346    MainFunding,
347    #[serde(rename = "FUNDING_MAIN")]
348    FundingMain,
349    #[serde(rename = "FUNDING_UMFUTURE")]
350    FundingUmfuture,
351    #[serde(rename = "UMFUTURE_FUNDING")]
352    UmfutureFunding,
353    #[serde(rename = "MARGIN_FUNDING")]
354    MarginFunding,
355    #[serde(rename = "FUNDING_MARGIN")]
356    FundingMargin,
357    #[serde(rename = "FUNDING_CMFUTURE")]
358    FundingCmfuture,
359    #[serde(rename = "CMFUTURE_FUNDING")]
360    CmfutureFunding,
361    #[serde(rename = "MAIN_OPTION")]
362    MainOption,
363    #[serde(rename = "OPTION_MAIN")]
364    OptionMain,
365    #[serde(rename = "UMFUTURE_OPTION")]
366    UmfutureOption,
367    #[serde(rename = "OPTION_UMFUTURE")]
368    OptionUmfuture,
369    #[serde(rename = "MARGIN_OPTION")]
370    MarginOption,
371    #[serde(rename = "OPTION_MARGIN")]
372    OptionMargin,
373    #[serde(rename = "FUNDING_OPTION")]
374    FundingOption,
375    #[serde(rename = "OPTION_FUNDING")]
376    OptionFunding,
377    #[serde(rename = "MAIN_PORTFOLIO_MARGIN")]
378    MainPortfolioMargin,
379    #[serde(rename = "PORTFOLIO_MARGIN_MAIN")]
380    PortfolioMarginMain,
381}
382
383impl UserUniversalTransferTypeEnum {
384    #[must_use]
385    pub fn as_str(&self) -> &'static str {
386        match self {
387            Self::MainUmfuture => "MAIN_UMFUTURE",
388            Self::MainCmfuture => "MAIN_CMFUTURE",
389            Self::MainMargin => "MAIN_MARGIN",
390            Self::UmfutureMain => "UMFUTURE_MAIN",
391            Self::UmfutureMargin => "UMFUTURE_MARGIN",
392            Self::CmfutureMain => "CMFUTURE_MAIN",
393            Self::CmfutureMargin => "CMFUTURE_MARGIN",
394            Self::MarginMain => "MARGIN_MAIN",
395            Self::MarginUmfuture => "MARGIN_UMFUTURE",
396            Self::MarginCmfuture => "MARGIN_CMFUTURE",
397            Self::IsolatedmarginMargin => "ISOLATEDMARGIN_MARGIN",
398            Self::MarginIsolatedmargin => "MARGIN_ISOLATEDMARGIN",
399            Self::IsolatedmarginIsolatedmargin => "ISOLATEDMARGIN_ISOLATEDMARGIN",
400            Self::MainFunding => "MAIN_FUNDING",
401            Self::FundingMain => "FUNDING_MAIN",
402            Self::FundingUmfuture => "FUNDING_UMFUTURE",
403            Self::UmfutureFunding => "UMFUTURE_FUNDING",
404            Self::MarginFunding => "MARGIN_FUNDING",
405            Self::FundingMargin => "FUNDING_MARGIN",
406            Self::FundingCmfuture => "FUNDING_CMFUTURE",
407            Self::CmfutureFunding => "CMFUTURE_FUNDING",
408            Self::MainOption => "MAIN_OPTION",
409            Self::OptionMain => "OPTION_MAIN",
410            Self::UmfutureOption => "UMFUTURE_OPTION",
411            Self::OptionUmfuture => "OPTION_UMFUTURE",
412            Self::MarginOption => "MARGIN_OPTION",
413            Self::OptionMargin => "OPTION_MARGIN",
414            Self::FundingOption => "FUNDING_OPTION",
415            Self::OptionFunding => "OPTION_FUNDING",
416            Self::MainPortfolioMargin => "MAIN_PORTFOLIO_MARGIN",
417            Self::PortfolioMarginMain => "PORTFOLIO_MARGIN_MAIN",
418        }
419    }
420}
421
422impl std::str::FromStr for UserUniversalTransferTypeEnum {
423    type Err = Box<dyn std::error::Error + Send + Sync>;
424
425    fn from_str(s: &str) -> Result<Self, Self::Err> {
426        match s {
427            "MAIN_UMFUTURE" => Ok(Self::MainUmfuture),
428            "MAIN_CMFUTURE" => Ok(Self::MainCmfuture),
429            "MAIN_MARGIN" => Ok(Self::MainMargin),
430            "UMFUTURE_MAIN" => Ok(Self::UmfutureMain),
431            "UMFUTURE_MARGIN" => Ok(Self::UmfutureMargin),
432            "CMFUTURE_MAIN" => Ok(Self::CmfutureMain),
433            "CMFUTURE_MARGIN" => Ok(Self::CmfutureMargin),
434            "MARGIN_MAIN" => Ok(Self::MarginMain),
435            "MARGIN_UMFUTURE" => Ok(Self::MarginUmfuture),
436            "MARGIN_CMFUTURE" => Ok(Self::MarginCmfuture),
437            "ISOLATEDMARGIN_MARGIN" => Ok(Self::IsolatedmarginMargin),
438            "MARGIN_ISOLATEDMARGIN" => Ok(Self::MarginIsolatedmargin),
439            "ISOLATEDMARGIN_ISOLATEDMARGIN" => Ok(Self::IsolatedmarginIsolatedmargin),
440            "MAIN_FUNDING" => Ok(Self::MainFunding),
441            "FUNDING_MAIN" => Ok(Self::FundingMain),
442            "FUNDING_UMFUTURE" => Ok(Self::FundingUmfuture),
443            "UMFUTURE_FUNDING" => Ok(Self::UmfutureFunding),
444            "MARGIN_FUNDING" => Ok(Self::MarginFunding),
445            "FUNDING_MARGIN" => Ok(Self::FundingMargin),
446            "FUNDING_CMFUTURE" => Ok(Self::FundingCmfuture),
447            "CMFUTURE_FUNDING" => Ok(Self::CmfutureFunding),
448            "MAIN_OPTION" => Ok(Self::MainOption),
449            "OPTION_MAIN" => Ok(Self::OptionMain),
450            "UMFUTURE_OPTION" => Ok(Self::UmfutureOption),
451            "OPTION_UMFUTURE" => Ok(Self::OptionUmfuture),
452            "MARGIN_OPTION" => Ok(Self::MarginOption),
453            "OPTION_MARGIN" => Ok(Self::OptionMargin),
454            "FUNDING_OPTION" => Ok(Self::FundingOption),
455            "OPTION_FUNDING" => Ok(Self::OptionFunding),
456            "MAIN_PORTFOLIO_MARGIN" => Ok(Self::MainPortfolioMargin),
457            "PORTFOLIO_MARGIN_MAIN" => Ok(Self::PortfolioMarginMain),
458            other => Err(format!("invalid UserUniversalTransferTypeEnum: {}", other).into()),
459        }
460    }
461}
462
463#[allow(non_camel_case_types)]
464#[derive(Debug, Clone, Serialize, Deserialize)]
465pub enum UserUniversalTransferFromSymbolEnum {
466    #[serde(rename = "ISOLATEDMARGIN_MARGIN")]
467    IsolatedmarginMargin,
468    #[serde(rename = "ISOLATEDMARGIN_ISOLATEDMARGIN")]
469    IsolatedmarginIsolatedmargin,
470}
471
472impl UserUniversalTransferFromSymbolEnum {
473    #[must_use]
474    pub fn as_str(&self) -> &'static str {
475        match self {
476            Self::IsolatedmarginMargin => "ISOLATEDMARGIN_MARGIN",
477            Self::IsolatedmarginIsolatedmargin => "ISOLATEDMARGIN_ISOLATEDMARGIN",
478        }
479    }
480}
481
482impl std::str::FromStr for UserUniversalTransferFromSymbolEnum {
483    type Err = Box<dyn std::error::Error + Send + Sync>;
484
485    fn from_str(s: &str) -> Result<Self, Self::Err> {
486        match s {
487            "ISOLATEDMARGIN_MARGIN" => Ok(Self::IsolatedmarginMargin),
488            "ISOLATEDMARGIN_ISOLATEDMARGIN" => Ok(Self::IsolatedmarginIsolatedmargin),
489            other => Err(format!("invalid UserUniversalTransferFromSymbolEnum: {}", other).into()),
490        }
491    }
492}
493
494#[allow(non_camel_case_types)]
495#[derive(Debug, Clone, Serialize, Deserialize)]
496pub enum UserUniversalTransferToSymbolEnum {
497    #[serde(rename = "MARGIN_ISOLATEDMARGIN")]
498    MarginIsolatedmargin,
499    #[serde(rename = "ISOLATEDMARGIN_ISOLATEDMARGIN")]
500    IsolatedmarginIsolatedmargin,
501}
502
503impl UserUniversalTransferToSymbolEnum {
504    #[must_use]
505    pub fn as_str(&self) -> &'static str {
506        match self {
507            Self::MarginIsolatedmargin => "MARGIN_ISOLATEDMARGIN",
508            Self::IsolatedmarginIsolatedmargin => "ISOLATEDMARGIN_ISOLATEDMARGIN",
509        }
510    }
511}
512
513impl std::str::FromStr for UserUniversalTransferToSymbolEnum {
514    type Err = Box<dyn std::error::Error + Send + Sync>;
515
516    fn from_str(s: &str) -> Result<Self, Self::Err> {
517        match s {
518            "MARGIN_ISOLATEDMARGIN" => Ok(Self::MarginIsolatedmargin),
519            "ISOLATEDMARGIN_ISOLATEDMARGIN" => Ok(Self::IsolatedmarginIsolatedmargin),
520            other => Err(format!("invalid UserUniversalTransferToSymbolEnum: {}", other).into()),
521        }
522    }
523}
524
525/// Request parameters for the [`asset_detail`] operation.
526///
527/// This struct holds all of the inputs you can pass when calling
528/// [`asset_detail`](#method.asset_detail).
529#[derive(Clone, Debug, Builder, Deserialize, Default)]
530#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
531pub struct AssetDetailParams {
532    ///
533    /// The `asset` parameter.
534    ///
535    /// This field is **optional.
536    #[builder(setter(into), default)]
537    #[serde(rename = "asset", default)]
538    pub asset: Option<String>,
539    ///
540    /// The `recv_window` parameter.
541    ///
542    /// This field is **optional.
543    #[builder(setter(into), default)]
544    #[serde(rename = "recvWindow", default)]
545    pub recv_window: Option<i64>,
546}
547
548impl AssetDetailParams {
549    /// Create a builder for [`asset_detail`].
550    ///
551    #[must_use]
552    pub fn builder() -> AssetDetailParamsBuilder {
553        AssetDetailParamsBuilder::default()
554    }
555}
556/// Request parameters for the [`asset_dividend_record`] operation.
557///
558/// This struct holds all of the inputs you can pass when calling
559/// [`asset_dividend_record`](#method.asset_dividend_record).
560#[derive(Clone, Debug, Builder, Deserialize, Default)]
561#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
562pub struct AssetDividendRecordParams {
563    ///
564    /// The `asset` parameter.
565    ///
566    /// This field is **optional.
567    #[builder(setter(into), default)]
568    #[serde(rename = "asset", default)]
569    pub asset: Option<String>,
570    ///
571    /// The `start_time` parameter.
572    ///
573    /// This field is **optional.
574    #[builder(setter(into), default)]
575    #[serde(rename = "startTime", default)]
576    pub start_time: Option<i64>,
577    ///
578    /// The `end_time` parameter.
579    ///
580    /// This field is **optional.
581    #[builder(setter(into), default)]
582    #[serde(rename = "endTime", default)]
583    pub end_time: Option<i64>,
584    ///
585    /// The `limit` parameter.
586    ///
587    /// This field is **optional.
588    #[builder(setter(into), default)]
589    #[serde(rename = "limit", default)]
590    pub limit: Option<i64>,
591    ///
592    /// The `recv_window` parameter.
593    ///
594    /// This field is **optional.
595    #[builder(setter(into), default)]
596    #[serde(rename = "recvWindow", default)]
597    pub recv_window: Option<i64>,
598}
599
600impl AssetDividendRecordParams {
601    /// Create a builder for [`asset_dividend_record`].
602    ///
603    #[must_use]
604    pub fn builder() -> AssetDividendRecordParamsBuilder {
605        AssetDividendRecordParamsBuilder::default()
606    }
607}
608/// Request parameters for the [`dust_convert`] operation.
609///
610/// This struct holds all of the inputs you can pass when calling
611/// [`dust_convert`](#method.dust_convert).
612#[derive(Clone, Debug, Builder, Deserialize)]
613#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
614pub struct DustConvertParams {
615    ///
616    /// The `asset` parameter.
617    ///
618    /// This field is **required.
619    #[builder(setter(into))]
620    #[serde(rename = "asset")]
621    pub asset: String,
622    /// `SPOT` or `MARGIN`, default `SPOT`
623    ///
624    /// This field is **optional.
625    #[builder(setter(into), default)]
626    #[serde(rename = "accountType", default)]
627    pub account_type: Option<String>,
628    /// A unique id for the request
629    ///
630    /// This field is **optional.
631    #[builder(setter(into), default)]
632    #[serde(rename = "clientId", default)]
633    pub client_id: Option<String>,
634    ///
635    /// The `target_asset` parameter.
636    ///
637    /// This field is **optional.
638    #[builder(setter(into), default)]
639    #[serde(rename = "targetAsset", default)]
640    pub target_asset: Option<String>,
641    ///
642    /// The `third_party_client_id` parameter.
643    ///
644    /// This field is **optional.
645    #[builder(setter(into), default)]
646    #[serde(rename = "thirdPartyClientId", default)]
647    pub third_party_client_id: Option<String>,
648    ///
649    /// The `dust_quota_asset_to_target_asset_price` parameter.
650    ///
651    /// This field is **optional.
652    #[builder(setter(into), default)]
653    #[serde(rename = "dustQuotaAssetToTargetAssetPrice", default)]
654    pub dust_quota_asset_to_target_asset_price: Option<rust_decimal::Decimal>,
655}
656
657impl DustConvertParams {
658    /// Create a builder for [`dust_convert`].
659    ///
660    /// Required parameters:
661    ///
662    /// * `asset` — String
663    ///
664    #[must_use]
665    pub fn builder(asset: String) -> DustConvertParamsBuilder {
666        DustConvertParamsBuilder::default().asset(asset)
667    }
668}
669/// Request parameters for the [`dust_convertible_assets`] operation.
670///
671/// This struct holds all of the inputs you can pass when calling
672/// [`dust_convertible_assets`](#method.dust_convertible_assets).
673#[derive(Clone, Debug, Builder, Deserialize)]
674#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
675pub struct DustConvertibleAssetsParams {
676    ///
677    /// The `target_asset` parameter.
678    ///
679    /// This field is **required.
680    #[builder(setter(into))]
681    #[serde(rename = "targetAsset")]
682    pub target_asset: String,
683    /// `SPOT` or `MARGIN`, default `SPOT`
684    ///
685    /// This field is **optional.
686    #[builder(setter(into), default)]
687    #[serde(rename = "accountType", default)]
688    pub account_type: Option<String>,
689    ///
690    /// The `dust_quota_asset_to_target_asset_price` parameter.
691    ///
692    /// This field is **optional.
693    #[builder(setter(into), default)]
694    #[serde(rename = "dustQuotaAssetToTargetAssetPrice", default)]
695    pub dust_quota_asset_to_target_asset_price: Option<rust_decimal::Decimal>,
696}
697
698impl DustConvertibleAssetsParams {
699    /// Create a builder for [`dust_convertible_assets`].
700    ///
701    /// Required parameters:
702    ///
703    /// * `target_asset` — String
704    ///
705    #[must_use]
706    pub fn builder(target_asset: String) -> DustConvertibleAssetsParamsBuilder {
707        DustConvertibleAssetsParamsBuilder::default().target_asset(target_asset)
708    }
709}
710/// Request parameters for the [`dust_transfer`] operation.
711///
712/// This struct holds all of the inputs you can pass when calling
713/// [`dust_transfer`](#method.dust_transfer).
714#[derive(Clone, Debug, Builder, Deserialize)]
715#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
716pub struct DustTransferParams {
717    /// The asset being converted. For example: asset=BTC,USDT
718    ///
719    /// This field is **required.
720    #[builder(setter(into))]
721    #[serde(rename = "asset")]
722    pub asset: String,
723    ///
724    /// The `account_type` parameter.
725    ///
726    /// This field is **optional.
727    #[builder(setter(into), default)]
728    #[serde(rename = "accountType", default)]
729    pub account_type: Option<DustTransferAccountTypeEnum>,
730    ///
731    /// The `recv_window` parameter.
732    ///
733    /// This field is **optional.
734    #[builder(setter(into), default)]
735    #[serde(rename = "recvWindow", default)]
736    pub recv_window: Option<i64>,
737}
738
739impl DustTransferParams {
740    /// Create a builder for [`dust_transfer`].
741    ///
742    /// Required parameters:
743    ///
744    /// * `asset` — The asset being converted. For example: asset=BTC,USDT
745    ///
746    #[must_use]
747    pub fn builder(asset: String) -> DustTransferParamsBuilder {
748        DustTransferParamsBuilder::default().asset(asset)
749    }
750}
751/// Request parameters for the [`dustlog`] operation.
752///
753/// This struct holds all of the inputs you can pass when calling
754/// [`dustlog`](#method.dustlog).
755#[derive(Clone, Debug, Builder, Deserialize, Default)]
756#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
757pub struct DustlogParams {
758    ///
759    /// The `account_type` parameter.
760    ///
761    /// This field is **optional.
762    #[builder(setter(into), default)]
763    #[serde(rename = "accountType", default)]
764    pub account_type: Option<DustlogAccountTypeEnum>,
765    ///
766    /// The `start_time` parameter.
767    ///
768    /// This field is **optional.
769    #[builder(setter(into), default)]
770    #[serde(rename = "startTime", default)]
771    pub start_time: Option<i64>,
772    ///
773    /// The `end_time` parameter.
774    ///
775    /// This field is **optional.
776    #[builder(setter(into), default)]
777    #[serde(rename = "endTime", default)]
778    pub end_time: Option<i64>,
779    ///
780    /// The `recv_window` parameter.
781    ///
782    /// This field is **optional.
783    #[builder(setter(into), default)]
784    #[serde(rename = "recvWindow", default)]
785    pub recv_window: Option<i64>,
786}
787
788impl DustlogParams {
789    /// Create a builder for [`dustlog`].
790    ///
791    #[must_use]
792    pub fn builder() -> DustlogParamsBuilder {
793        DustlogParamsBuilder::default()
794    }
795}
796/// Request parameters for the [`funding_wallet`] operation.
797///
798/// This struct holds all of the inputs you can pass when calling
799/// [`funding_wallet`](#method.funding_wallet).
800#[derive(Clone, Debug, Builder, Deserialize, Default)]
801#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
802pub struct FundingWalletParams {
803    ///
804    /// The `asset` parameter.
805    ///
806    /// This field is **optional.
807    #[builder(setter(into), default)]
808    #[serde(rename = "asset", default)]
809    pub asset: Option<String>,
810    ///
811    /// The `need_btc_valuation` parameter.
812    ///
813    /// This field is **optional.
814    #[builder(setter(into), default)]
815    #[serde(rename = "needBtcValuation", default)]
816    pub need_btc_valuation: Option<bool>,
817    ///
818    /// The `recv_window` parameter.
819    ///
820    /// This field is **optional.
821    #[builder(setter(into), default)]
822    #[serde(rename = "recvWindow", default)]
823    pub recv_window: Option<i64>,
824}
825
826impl FundingWalletParams {
827    /// Create a builder for [`funding_wallet`].
828    ///
829    #[must_use]
830    pub fn builder() -> FundingWalletParamsBuilder {
831        FundingWalletParamsBuilder::default()
832    }
833}
834/// Request parameters for the [`get_assets_that_can_be_converted_into_bnb`] operation.
835///
836/// This struct holds all of the inputs you can pass when calling
837/// [`get_assets_that_can_be_converted_into_bnb`](#method.get_assets_that_can_be_converted_into_bnb).
838#[derive(Clone, Debug, Builder, Deserialize, Default)]
839#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
840pub struct GetAssetsThatCanBeConvertedIntoBnbParams {
841    ///
842    /// The `account_type` parameter.
843    ///
844    /// This field is **optional.
845    #[builder(setter(into), default)]
846    #[serde(rename = "accountType", default)]
847    pub account_type: Option<GetAssetsThatCanBeConvertedIntoBnbAccountTypeEnum>,
848    ///
849    /// The `recv_window` parameter.
850    ///
851    /// This field is **optional.
852    #[builder(setter(into), default)]
853    #[serde(rename = "recvWindow", default)]
854    pub recv_window: Option<i64>,
855}
856
857impl GetAssetsThatCanBeConvertedIntoBnbParams {
858    /// Create a builder for [`get_assets_that_can_be_converted_into_bnb`].
859    ///
860    #[must_use]
861    pub fn builder() -> GetAssetsThatCanBeConvertedIntoBnbParamsBuilder {
862        GetAssetsThatCanBeConvertedIntoBnbParamsBuilder::default()
863    }
864}
865/// Request parameters for the [`get_cloud_mining_payment_and_refund_history`] operation.
866///
867/// This struct holds all of the inputs you can pass when calling
868/// [`get_cloud_mining_payment_and_refund_history`](#method.get_cloud_mining_payment_and_refund_history).
869#[derive(Clone, Debug, Builder, Deserialize)]
870#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
871pub struct GetCloudMiningPaymentAndRefundHistoryParams {
872    /// inclusive, unit: ms
873    ///
874    /// This field is **required.
875    #[builder(setter(into))]
876    #[serde(rename = "startTime")]
877    pub start_time: i64,
878    /// exclusive, unit: ms
879    ///
880    /// This field is **required.
881    #[builder(setter(into))]
882    #[serde(rename = "endTime")]
883    pub end_time: i64,
884    /// The transaction id
885    ///
886    /// This field is **optional.
887    #[builder(setter(into), default)]
888    #[serde(rename = "tranId", default)]
889    pub tran_id: Option<i64>,
890    /// The unique flag
891    ///
892    /// This field is **optional.
893    #[builder(setter(into), default)]
894    #[serde(rename = "clientTranId", default)]
895    pub client_tran_id: Option<String>,
896    /// If it is blank, we will query all assets
897    ///
898    /// This field is **optional.
899    #[builder(setter(into), default)]
900    #[serde(rename = "asset", default)]
901    pub asset: Option<String>,
902    ///
903    /// The `current` parameter.
904    ///
905    /// This field is **optional.
906    #[builder(setter(into), default)]
907    #[serde(rename = "current", default)]
908    pub current: Option<i64>,
909    ///
910    /// The `size` parameter.
911    ///
912    /// This field is **optional.
913    #[builder(setter(into), default)]
914    #[serde(rename = "size", default)]
915    pub size: Option<i64>,
916}
917
918impl GetCloudMiningPaymentAndRefundHistoryParams {
919    /// Create a builder for [`get_cloud_mining_payment_and_refund_history`].
920    ///
921    /// Required parameters:
922    ///
923    /// * `start_time` — inclusive, unit: ms
924    /// * `end_time` — exclusive, unit: ms
925    ///
926    #[must_use]
927    pub fn builder(
928        start_time: i64,
929        end_time: i64,
930    ) -> GetCloudMiningPaymentAndRefundHistoryParamsBuilder {
931        GetCloudMiningPaymentAndRefundHistoryParamsBuilder::default()
932            .start_time(start_time)
933            .end_time(end_time)
934    }
935}
936/// Request parameters for the [`get_spot_asset_tags`] operation.
937///
938/// This struct holds all of the inputs you can pass when calling
939/// [`get_spot_asset_tags`](#method.get_spot_asset_tags).
940#[derive(Clone, Debug, Builder, Deserialize, Default)]
941#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
942pub struct GetSpotAssetTagsParams {
943    /// Tag filter. Supports multiple comma-separated tags with OR semantics (an asset is returned if it matches any one tag); leading/trailing whitespace around each tag is ignored. Returns all eligible assets when omitted.
944    ///
945    /// This field is **optional.
946    #[builder(setter(into), default)]
947    #[serde(rename = "tag", default)]
948    pub tag: Option<String>,
949}
950
951impl GetSpotAssetTagsParams {
952    /// Create a builder for [`get_spot_asset_tags`].
953    ///
954    #[must_use]
955    pub fn builder() -> GetSpotAssetTagsParamsBuilder {
956        GetSpotAssetTagsParamsBuilder::default()
957    }
958}
959/// Request parameters for the [`query_user_delegation_history`] operation.
960///
961/// This struct holds all of the inputs you can pass when calling
962/// [`query_user_delegation_history`](#method.query_user_delegation_history).
963#[derive(Clone, Debug, Builder, Deserialize)]
964#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
965pub struct QueryUserDelegationHistoryParams {
966    ///
967    /// The `email` parameter.
968    ///
969    /// This field is **required.
970    #[builder(setter(into))]
971    #[serde(rename = "email")]
972    pub email: String,
973    ///
974    /// The `start_time` parameter.
975    ///
976    /// This field is **required.
977    #[builder(setter(into))]
978    #[serde(rename = "startTime")]
979    pub start_time: i64,
980    ///
981    /// The `end_time` parameter.
982    ///
983    /// This field is **required.
984    #[builder(setter(into))]
985    #[serde(rename = "endTime")]
986    pub end_time: i64,
987    ///
988    /// The `r#type` parameter.
989    ///
990    /// This field is **optional.
991    #[builder(setter(into), default)]
992    #[serde(rename = "type", default)]
993    pub r#type: Option<QueryUserDelegationHistoryTypeEnum>,
994    ///
995    /// The `asset` parameter.
996    ///
997    /// This field is **optional.
998    #[builder(setter(into), default)]
999    #[serde(rename = "asset", default)]
1000    pub asset: Option<String>,
1001    ///
1002    /// The `current` parameter.
1003    ///
1004    /// This field is **optional.
1005    #[builder(setter(into), default)]
1006    #[serde(rename = "current", default)]
1007    pub current: Option<i64>,
1008    ///
1009    /// The `size` parameter.
1010    ///
1011    /// This field is **optional.
1012    #[builder(setter(into), default)]
1013    #[serde(rename = "size", default)]
1014    pub size: Option<i64>,
1015    ///
1016    /// The `recv_window` parameter.
1017    ///
1018    /// This field is **optional.
1019    #[builder(setter(into), default)]
1020    #[serde(rename = "recvWindow", default)]
1021    pub recv_window: Option<i64>,
1022}
1023
1024impl QueryUserDelegationHistoryParams {
1025    /// Create a builder for [`query_user_delegation_history`].
1026    ///
1027    /// Required parameters:
1028    ///
1029    /// * `email` — String
1030    /// * `start_time` — i64
1031    /// * `end_time` — i64
1032    ///
1033    #[must_use]
1034    pub fn builder(
1035        email: String,
1036        start_time: i64,
1037        end_time: i64,
1038    ) -> QueryUserDelegationHistoryParamsBuilder {
1039        QueryUserDelegationHistoryParamsBuilder::default()
1040            .email(email)
1041            .start_time(start_time)
1042            .end_time(end_time)
1043    }
1044}
1045/// Request parameters for the [`query_user_universal_transfer_history`] operation.
1046///
1047/// This struct holds all of the inputs you can pass when calling
1048/// [`query_user_universal_transfer_history`](#method.query_user_universal_transfer_history).
1049#[derive(Clone, Debug, Builder, Deserialize)]
1050#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1051pub struct QueryUserUniversalTransferHistoryParams {
1052    ///
1053    /// The `r#type` parameter.
1054    ///
1055    /// This field is **required.
1056    #[builder(setter(into))]
1057    #[serde(rename = "type")]
1058    pub r#type: String,
1059    ///
1060    /// The `start_time` parameter.
1061    ///
1062    /// This field is **optional.
1063    #[builder(setter(into), default)]
1064    #[serde(rename = "startTime", default)]
1065    pub start_time: Option<i64>,
1066    ///
1067    /// The `end_time` parameter.
1068    ///
1069    /// This field is **optional.
1070    #[builder(setter(into), default)]
1071    #[serde(rename = "endTime", default)]
1072    pub end_time: Option<i64>,
1073    ///
1074    /// The `current` parameter.
1075    ///
1076    /// This field is **optional.
1077    #[builder(setter(into), default)]
1078    #[serde(rename = "current", default)]
1079    pub current: Option<i64>,
1080    ///
1081    /// The `size` parameter.
1082    ///
1083    /// This field is **optional.
1084    #[builder(setter(into), default)]
1085    #[serde(rename = "size", default)]
1086    pub size: Option<i64>,
1087    ///
1088    /// The `from_symbol` parameter.
1089    ///
1090    /// This field is **optional.
1091    #[builder(setter(into), default)]
1092    #[serde(rename = "fromSymbol", default)]
1093    pub from_symbol: Option<QueryUserUniversalTransferHistoryFromSymbolEnum>,
1094    ///
1095    /// The `to_symbol` parameter.
1096    ///
1097    /// This field is **optional.
1098    #[builder(setter(into), default)]
1099    #[serde(rename = "toSymbol", default)]
1100    pub to_symbol: Option<QueryUserUniversalTransferHistoryToSymbolEnum>,
1101    ///
1102    /// The `recv_window` parameter.
1103    ///
1104    /// This field is **optional.
1105    #[builder(setter(into), default)]
1106    #[serde(rename = "recvWindow", default)]
1107    pub recv_window: Option<i64>,
1108}
1109
1110impl QueryUserUniversalTransferHistoryParams {
1111    /// Create a builder for [`query_user_universal_transfer_history`].
1112    ///
1113    /// Required parameters:
1114    ///
1115    /// * `r#type` — String
1116    ///
1117    #[must_use]
1118    pub fn builder(r#type: String) -> QueryUserUniversalTransferHistoryParamsBuilder {
1119        QueryUserUniversalTransferHistoryParamsBuilder::default().r#type(r#type)
1120    }
1121}
1122/// Request parameters for the [`query_user_wallet_balance`] operation.
1123///
1124/// This struct holds all of the inputs you can pass when calling
1125/// [`query_user_wallet_balance`](#method.query_user_wallet_balance).
1126#[derive(Clone, Debug, Builder, Deserialize, Default)]
1127#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1128pub struct QueryUserWalletBalanceParams {
1129    ///
1130    /// The `quote_asset` parameter.
1131    ///
1132    /// This field is **optional.
1133    #[builder(setter(into), default)]
1134    #[serde(rename = "quoteAsset", default)]
1135    pub quote_asset: Option<String>,
1136    ///
1137    /// The `recv_window` parameter.
1138    ///
1139    /// This field is **optional.
1140    #[builder(setter(into), default)]
1141    #[serde(rename = "recvWindow", default)]
1142    pub recv_window: Option<i64>,
1143}
1144
1145impl QueryUserWalletBalanceParams {
1146    /// Create a builder for [`query_user_wallet_balance`].
1147    ///
1148    #[must_use]
1149    pub fn builder() -> QueryUserWalletBalanceParamsBuilder {
1150        QueryUserWalletBalanceParamsBuilder::default()
1151    }
1152}
1153/// Request parameters for the [`toggle_bnb_burn_on_spot_trade_and_margin_interest`] operation.
1154///
1155/// This struct holds all of the inputs you can pass when calling
1156/// [`toggle_bnb_burn_on_spot_trade_and_margin_interest`](#method.toggle_bnb_burn_on_spot_trade_and_margin_interest).
1157#[derive(Clone, Debug, Builder, Deserialize, Default)]
1158#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1159pub struct ToggleBnbBurnOnSpotTradeAndMarginInterestParams {
1160    /// Determines whether to use BNB to pay for trading fees on SPOT
1161    ///
1162    /// This field is **optional.
1163    #[builder(setter(into), default)]
1164    #[serde(rename = "spotBNBBurn", default)]
1165    pub spot_bnb_burn: Option<String>,
1166    /// Determines whether to use BNB to pay for margin loan's interest
1167    ///
1168    /// This field is **optional.
1169    #[builder(setter(into), default)]
1170    #[serde(rename = "interestBNBBurn", default)]
1171    pub interest_bnb_burn: Option<String>,
1172    ///
1173    /// The `recv_window` parameter.
1174    ///
1175    /// This field is **optional.
1176    #[builder(setter(into), default)]
1177    #[serde(rename = "recvWindow", default)]
1178    pub recv_window: Option<i64>,
1179}
1180
1181impl ToggleBnbBurnOnSpotTradeAndMarginInterestParams {
1182    /// Create a builder for [`toggle_bnb_burn_on_spot_trade_and_margin_interest`].
1183    ///
1184    #[must_use]
1185    pub fn builder() -> ToggleBnbBurnOnSpotTradeAndMarginInterestParamsBuilder {
1186        ToggleBnbBurnOnSpotTradeAndMarginInterestParamsBuilder::default()
1187    }
1188}
1189/// Request parameters for the [`trade_fee`] operation.
1190///
1191/// This struct holds all of the inputs you can pass when calling
1192/// [`trade_fee`](#method.trade_fee).
1193#[derive(Clone, Debug, Builder, Deserialize, Default)]
1194#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1195pub struct TradeFeeParams {
1196    ///
1197    /// The `symbol` parameter.
1198    ///
1199    /// This field is **optional.
1200    #[builder(setter(into), default)]
1201    #[serde(rename = "symbol", default)]
1202    pub symbol: Option<String>,
1203    ///
1204    /// The `recv_window` parameter.
1205    ///
1206    /// This field is **optional.
1207    #[builder(setter(into), default)]
1208    #[serde(rename = "recvWindow", default)]
1209    pub recv_window: Option<i64>,
1210}
1211
1212impl TradeFeeParams {
1213    /// Create a builder for [`trade_fee`].
1214    ///
1215    #[must_use]
1216    pub fn builder() -> TradeFeeParamsBuilder {
1217        TradeFeeParamsBuilder::default()
1218    }
1219}
1220/// Request parameters for the [`user_asset`] operation.
1221///
1222/// This struct holds all of the inputs you can pass when calling
1223/// [`user_asset`](#method.user_asset).
1224#[derive(Clone, Debug, Builder, Deserialize, Default)]
1225#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1226pub struct UserAssetParams {
1227    /// If asset is blank, then query all positive assets user have.
1228    ///
1229    /// This field is **optional.
1230    #[builder(setter(into), default)]
1231    #[serde(rename = "asset", default)]
1232    pub asset: Option<String>,
1233    /// Whether need btc valuation or not.
1234    ///
1235    /// This field is **optional.
1236    #[builder(setter(into), default)]
1237    #[serde(rename = "needBtcValuation", default)]
1238    pub need_btc_valuation: Option<bool>,
1239    ///
1240    /// The `recv_window` parameter.
1241    ///
1242    /// This field is **optional.
1243    #[builder(setter(into), default)]
1244    #[serde(rename = "recvWindow", default)]
1245    pub recv_window: Option<i64>,
1246}
1247
1248impl UserAssetParams {
1249    /// Create a builder for [`user_asset`].
1250    ///
1251    #[must_use]
1252    pub fn builder() -> UserAssetParamsBuilder {
1253        UserAssetParamsBuilder::default()
1254    }
1255}
1256/// Request parameters for the [`user_universal_transfer`] operation.
1257///
1258/// This struct holds all of the inputs you can pass when calling
1259/// [`user_universal_transfer`](#method.user_universal_transfer).
1260#[derive(Clone, Debug, Builder, Deserialize)]
1261#[builder(pattern = "owned", build_fn(error = "ParamBuildError"))]
1262pub struct UserUniversalTransferParams {
1263    ///
1264    /// The `r#type` parameter.
1265    ///
1266    /// This field is **required.
1267    #[builder(setter(into))]
1268    #[serde(rename = "type")]
1269    pub r#type: UserUniversalTransferTypeEnum,
1270    ///
1271    /// The `asset` parameter.
1272    ///
1273    /// This field is **required.
1274    #[builder(setter(into))]
1275    #[serde(rename = "asset")]
1276    pub asset: String,
1277    ///
1278    /// The `amount` parameter.
1279    ///
1280    /// This field is **required.
1281    #[builder(setter(into))]
1282    #[serde(rename = "amount")]
1283    pub amount: rust_decimal::Decimal,
1284    ///
1285    /// The `from_symbol` parameter.
1286    ///
1287    /// This field is **optional.
1288    #[builder(setter(into), default)]
1289    #[serde(rename = "fromSymbol", default)]
1290    pub from_symbol: Option<UserUniversalTransferFromSymbolEnum>,
1291    ///
1292    /// The `to_symbol` parameter.
1293    ///
1294    /// This field is **optional.
1295    #[builder(setter(into), default)]
1296    #[serde(rename = "toSymbol", default)]
1297    pub to_symbol: Option<UserUniversalTransferToSymbolEnum>,
1298    ///
1299    /// The `recv_window` parameter.
1300    ///
1301    /// This field is **optional.
1302    #[builder(setter(into), default)]
1303    #[serde(rename = "recvWindow", default)]
1304    pub recv_window: Option<i64>,
1305}
1306
1307impl UserUniversalTransferParams {
1308    /// Create a builder for [`user_universal_transfer`].
1309    ///
1310    /// Required parameters:
1311    ///
1312    /// * `r#type` — String
1313    /// * `asset` — String
1314    /// * `amount` — `rust_decimal::Decimal`
1315    ///
1316    #[must_use]
1317    pub fn builder(
1318        r#type: UserUniversalTransferTypeEnum,
1319        asset: String,
1320        amount: rust_decimal::Decimal,
1321    ) -> UserUniversalTransferParamsBuilder {
1322        UserUniversalTransferParamsBuilder::default()
1323            .r#type(r#type)
1324            .asset(asset)
1325            .amount(amount)
1326    }
1327}
1328
1329#[async_trait]
1330impl AssetApi for AssetApiClient {
1331    async fn asset_detail(
1332        &self,
1333        params: AssetDetailParams,
1334    ) -> anyhow::Result<RestApiResponse<models::AssetDetailResponse>> {
1335        let AssetDetailParams { asset, recv_window } = params;
1336
1337        let mut query_params = BTreeMap::new();
1338        let body_params = BTreeMap::new();
1339
1340        if let Some(rw) = asset {
1341            query_params.insert("asset".to_string(), json!(rw));
1342        }
1343
1344        if let Some(rw) = recv_window {
1345            query_params.insert("recvWindow".to_string(), json!(rw));
1346        }
1347
1348        send_request::<models::AssetDetailResponse>(
1349            &self.configuration,
1350            "/sapi/v1/asset/assetDetail",
1351            reqwest::Method::GET,
1352            query_params,
1353            body_params,
1354            if HAS_TIME_UNIT {
1355                self.configuration.time_unit
1356            } else {
1357                None
1358            },
1359            true,
1360        )
1361        .await
1362    }
1363
1364    async fn asset_dividend_record(
1365        &self,
1366        params: AssetDividendRecordParams,
1367    ) -> anyhow::Result<RestApiResponse<models::AssetDividendRecordResponse>> {
1368        let AssetDividendRecordParams {
1369            asset,
1370            start_time,
1371            end_time,
1372            limit,
1373            recv_window,
1374        } = params;
1375
1376        let mut query_params = BTreeMap::new();
1377        let body_params = BTreeMap::new();
1378
1379        if let Some(rw) = asset {
1380            query_params.insert("asset".to_string(), json!(rw));
1381        }
1382
1383        if let Some(rw) = start_time {
1384            query_params.insert("startTime".to_string(), json!(rw));
1385        }
1386
1387        if let Some(rw) = end_time {
1388            query_params.insert("endTime".to_string(), json!(rw));
1389        }
1390
1391        if let Some(rw) = limit {
1392            query_params.insert("limit".to_string(), json!(rw));
1393        }
1394
1395        if let Some(rw) = recv_window {
1396            query_params.insert("recvWindow".to_string(), json!(rw));
1397        }
1398
1399        send_request::<models::AssetDividendRecordResponse>(
1400            &self.configuration,
1401            "/sapi/v1/asset/assetDividend",
1402            reqwest::Method::GET,
1403            query_params,
1404            body_params,
1405            if HAS_TIME_UNIT {
1406                self.configuration.time_unit
1407            } else {
1408                None
1409            },
1410            true,
1411        )
1412        .await
1413    }
1414
1415    async fn dust_convert(
1416        &self,
1417        params: DustConvertParams,
1418    ) -> anyhow::Result<RestApiResponse<models::DustConvertResponse>> {
1419        let DustConvertParams {
1420            asset,
1421            account_type,
1422            client_id,
1423            target_asset,
1424            third_party_client_id,
1425            dust_quota_asset_to_target_asset_price,
1426        } = params;
1427
1428        let mut query_params = BTreeMap::new();
1429        let body_params = BTreeMap::new();
1430
1431        query_params.insert("asset".to_string(), json!(asset));
1432
1433        if let Some(rw) = account_type {
1434            query_params.insert("accountType".to_string(), json!(rw));
1435        }
1436
1437        if let Some(rw) = client_id {
1438            query_params.insert("clientId".to_string(), json!(rw));
1439        }
1440
1441        if let Some(rw) = target_asset {
1442            query_params.insert("targetAsset".to_string(), json!(rw));
1443        }
1444
1445        if let Some(rw) = third_party_client_id {
1446            query_params.insert("thirdPartyClientId".to_string(), json!(rw));
1447        }
1448
1449        if let Some(rw) = dust_quota_asset_to_target_asset_price {
1450            query_params.insert("dustQuotaAssetToTargetAssetPrice".to_string(), json!(rw));
1451        }
1452
1453        send_request::<models::DustConvertResponse>(
1454            &self.configuration,
1455            "/sapi/v1/asset/dust-convert/convert",
1456            reqwest::Method::POST,
1457            query_params,
1458            body_params,
1459            if HAS_TIME_UNIT {
1460                self.configuration.time_unit
1461            } else {
1462                None
1463            },
1464            true,
1465        )
1466        .await
1467    }
1468
1469    async fn dust_convertible_assets(
1470        &self,
1471        params: DustConvertibleAssetsParams,
1472    ) -> anyhow::Result<RestApiResponse<models::DustConvertibleAssetsResponse>> {
1473        let DustConvertibleAssetsParams {
1474            target_asset,
1475            account_type,
1476            dust_quota_asset_to_target_asset_price,
1477        } = params;
1478
1479        let mut query_params = BTreeMap::new();
1480        let body_params = BTreeMap::new();
1481
1482        if let Some(rw) = account_type {
1483            query_params.insert("accountType".to_string(), json!(rw));
1484        }
1485
1486        query_params.insert("targetAsset".to_string(), json!(target_asset));
1487
1488        if let Some(rw) = dust_quota_asset_to_target_asset_price {
1489            query_params.insert("dustQuotaAssetToTargetAssetPrice".to_string(), json!(rw));
1490        }
1491
1492        send_request::<models::DustConvertibleAssetsResponse>(
1493            &self.configuration,
1494            "/sapi/v1/asset/dust-convert/query-convertible-assets",
1495            reqwest::Method::POST,
1496            query_params,
1497            body_params,
1498            if HAS_TIME_UNIT {
1499                self.configuration.time_unit
1500            } else {
1501                None
1502            },
1503            true,
1504        )
1505        .await
1506    }
1507
1508    async fn dust_transfer(
1509        &self,
1510        params: DustTransferParams,
1511    ) -> anyhow::Result<RestApiResponse<models::DustTransferResponse>> {
1512        let DustTransferParams {
1513            asset,
1514            account_type,
1515            recv_window,
1516        } = params;
1517
1518        let mut query_params = BTreeMap::new();
1519        let body_params = BTreeMap::new();
1520
1521        query_params.insert("asset".to_string(), json!(asset));
1522
1523        if let Some(rw) = account_type {
1524            query_params.insert("accountType".to_string(), json!(rw));
1525        }
1526
1527        if let Some(rw) = recv_window {
1528            query_params.insert("recvWindow".to_string(), json!(rw));
1529        }
1530
1531        send_request::<models::DustTransferResponse>(
1532            &self.configuration,
1533            "/sapi/v1/asset/dust",
1534            reqwest::Method::POST,
1535            query_params,
1536            body_params,
1537            if HAS_TIME_UNIT {
1538                self.configuration.time_unit
1539            } else {
1540                None
1541            },
1542            true,
1543        )
1544        .await
1545    }
1546
1547    async fn dustlog(
1548        &self,
1549        params: DustlogParams,
1550    ) -> anyhow::Result<RestApiResponse<models::DustlogResponse>> {
1551        let DustlogParams {
1552            account_type,
1553            start_time,
1554            end_time,
1555            recv_window,
1556        } = params;
1557
1558        let mut query_params = BTreeMap::new();
1559        let body_params = BTreeMap::new();
1560
1561        if let Some(rw) = account_type {
1562            query_params.insert("accountType".to_string(), json!(rw));
1563        }
1564
1565        if let Some(rw) = start_time {
1566            query_params.insert("startTime".to_string(), json!(rw));
1567        }
1568
1569        if let Some(rw) = end_time {
1570            query_params.insert("endTime".to_string(), json!(rw));
1571        }
1572
1573        if let Some(rw) = recv_window {
1574            query_params.insert("recvWindow".to_string(), json!(rw));
1575        }
1576
1577        send_request::<models::DustlogResponse>(
1578            &self.configuration,
1579            "/sapi/v1/asset/dribblet",
1580            reqwest::Method::GET,
1581            query_params,
1582            body_params,
1583            if HAS_TIME_UNIT {
1584                self.configuration.time_unit
1585            } else {
1586                None
1587            },
1588            true,
1589        )
1590        .await
1591    }
1592
1593    async fn funding_wallet(
1594        &self,
1595        params: FundingWalletParams,
1596    ) -> anyhow::Result<RestApiResponse<Vec<models::FundingWalletResponseInner>>> {
1597        let FundingWalletParams {
1598            asset,
1599            need_btc_valuation,
1600            recv_window,
1601        } = params;
1602
1603        let mut query_params = BTreeMap::new();
1604        let body_params = BTreeMap::new();
1605
1606        if let Some(rw) = asset {
1607            query_params.insert("asset".to_string(), json!(rw));
1608        }
1609
1610        if let Some(rw) = need_btc_valuation {
1611            query_params.insert("needBtcValuation".to_string(), json!(rw));
1612        }
1613
1614        if let Some(rw) = recv_window {
1615            query_params.insert("recvWindow".to_string(), json!(rw));
1616        }
1617
1618        send_request::<Vec<models::FundingWalletResponseInner>>(
1619            &self.configuration,
1620            "/sapi/v1/asset/get-funding-asset",
1621            reqwest::Method::POST,
1622            query_params,
1623            body_params,
1624            if HAS_TIME_UNIT {
1625                self.configuration.time_unit
1626            } else {
1627                None
1628            },
1629            true,
1630        )
1631        .await
1632    }
1633
1634    async fn get_assets_that_can_be_converted_into_bnb(
1635        &self,
1636        params: GetAssetsThatCanBeConvertedIntoBnbParams,
1637    ) -> anyhow::Result<RestApiResponse<models::GetAssetsThatCanBeConvertedIntoBnbResponse>> {
1638        let GetAssetsThatCanBeConvertedIntoBnbParams {
1639            account_type,
1640            recv_window,
1641        } = params;
1642
1643        let mut query_params = BTreeMap::new();
1644        let body_params = BTreeMap::new();
1645
1646        if let Some(rw) = account_type {
1647            query_params.insert("accountType".to_string(), json!(rw));
1648        }
1649
1650        if let Some(rw) = recv_window {
1651            query_params.insert("recvWindow".to_string(), json!(rw));
1652        }
1653
1654        send_request::<models::GetAssetsThatCanBeConvertedIntoBnbResponse>(
1655            &self.configuration,
1656            "/sapi/v1/asset/dust-btc",
1657            reqwest::Method::POST,
1658            query_params,
1659            body_params,
1660            if HAS_TIME_UNIT {
1661                self.configuration.time_unit
1662            } else {
1663                None
1664            },
1665            true,
1666        )
1667        .await
1668    }
1669
1670    async fn get_cloud_mining_payment_and_refund_history(
1671        &self,
1672        params: GetCloudMiningPaymentAndRefundHistoryParams,
1673    ) -> anyhow::Result<RestApiResponse<models::GetCloudMiningPaymentAndRefundHistoryResponse>>
1674    {
1675        let GetCloudMiningPaymentAndRefundHistoryParams {
1676            start_time,
1677            end_time,
1678            tran_id,
1679            client_tran_id,
1680            asset,
1681            current,
1682            size,
1683        } = params;
1684
1685        let mut query_params = BTreeMap::new();
1686        let body_params = BTreeMap::new();
1687
1688        if let Some(rw) = tran_id {
1689            query_params.insert("tranId".to_string(), json!(rw));
1690        }
1691
1692        if let Some(rw) = client_tran_id {
1693            query_params.insert("clientTranId".to_string(), json!(rw));
1694        }
1695
1696        if let Some(rw) = asset {
1697            query_params.insert("asset".to_string(), json!(rw));
1698        }
1699
1700        query_params.insert("startTime".to_string(), json!(start_time));
1701
1702        query_params.insert("endTime".to_string(), json!(end_time));
1703
1704        if let Some(rw) = current {
1705            query_params.insert("current".to_string(), json!(rw));
1706        }
1707
1708        if let Some(rw) = size {
1709            query_params.insert("size".to_string(), json!(rw));
1710        }
1711
1712        send_request::<models::GetCloudMiningPaymentAndRefundHistoryResponse>(
1713            &self.configuration,
1714            "/sapi/v1/asset/ledger-transfer/cloud-mining/queryByPage",
1715            reqwest::Method::GET,
1716            query_params,
1717            body_params,
1718            if HAS_TIME_UNIT {
1719                self.configuration.time_unit
1720            } else {
1721                None
1722            },
1723            true,
1724        )
1725        .await
1726    }
1727
1728    async fn get_open_symbol_list(
1729        &self,
1730    ) -> anyhow::Result<RestApiResponse<Vec<models::GetOpenSymbolListResponseInner>>> {
1731        let query_params = BTreeMap::new();
1732        let body_params = BTreeMap::new();
1733
1734        send_request::<Vec<models::GetOpenSymbolListResponseInner>>(
1735            &self.configuration,
1736            "/sapi/v1/spot/open-symbol-list",
1737            reqwest::Method::GET,
1738            query_params,
1739            body_params,
1740            if HAS_TIME_UNIT {
1741                self.configuration.time_unit
1742            } else {
1743                None
1744            },
1745            false,
1746        )
1747        .await
1748    }
1749
1750    async fn get_spot_asset_tags(
1751        &self,
1752        params: GetSpotAssetTagsParams,
1753    ) -> anyhow::Result<RestApiResponse<Vec<models::GetSpotAssetTagsResponseInner>>> {
1754        let GetSpotAssetTagsParams { tag } = params;
1755
1756        let mut query_params = BTreeMap::new();
1757        let body_params = BTreeMap::new();
1758
1759        if let Some(rw) = tag {
1760            query_params.insert("tag".to_string(), json!(rw));
1761        }
1762
1763        send_request::<Vec<models::GetSpotAssetTagsResponseInner>>(
1764            &self.configuration,
1765            "/sapi/v1/spot/asset/tags",
1766            reqwest::Method::GET,
1767            query_params,
1768            body_params,
1769            if HAS_TIME_UNIT {
1770                self.configuration.time_unit
1771            } else {
1772                None
1773            },
1774            false,
1775        )
1776        .await
1777    }
1778
1779    async fn query_user_delegation_history(
1780        &self,
1781        params: QueryUserDelegationHistoryParams,
1782    ) -> anyhow::Result<RestApiResponse<models::QueryUserDelegationHistoryResponse>> {
1783        let QueryUserDelegationHistoryParams {
1784            email,
1785            start_time,
1786            end_time,
1787            r#type,
1788            asset,
1789            current,
1790            size,
1791            recv_window,
1792        } = params;
1793
1794        let mut query_params = BTreeMap::new();
1795        let body_params = BTreeMap::new();
1796
1797        query_params.insert("email".to_string(), json!(email));
1798
1799        query_params.insert("startTime".to_string(), json!(start_time));
1800
1801        query_params.insert("endTime".to_string(), json!(end_time));
1802
1803        if let Some(rw) = r#type {
1804            query_params.insert("type".to_string(), json!(rw));
1805        }
1806
1807        if let Some(rw) = asset {
1808            query_params.insert("asset".to_string(), json!(rw));
1809        }
1810
1811        if let Some(rw) = current {
1812            query_params.insert("current".to_string(), json!(rw));
1813        }
1814
1815        if let Some(rw) = size {
1816            query_params.insert("size".to_string(), json!(rw));
1817        }
1818
1819        if let Some(rw) = recv_window {
1820            query_params.insert("recvWindow".to_string(), json!(rw));
1821        }
1822
1823        send_request::<models::QueryUserDelegationHistoryResponse>(
1824            &self.configuration,
1825            "/sapi/v1/asset/custody/transfer-history",
1826            reqwest::Method::GET,
1827            query_params,
1828            body_params,
1829            if HAS_TIME_UNIT {
1830                self.configuration.time_unit
1831            } else {
1832                None
1833            },
1834            true,
1835        )
1836        .await
1837    }
1838
1839    async fn query_user_universal_transfer_history(
1840        &self,
1841        params: QueryUserUniversalTransferHistoryParams,
1842    ) -> anyhow::Result<RestApiResponse<models::QueryUserUniversalTransferHistoryResponse>> {
1843        let QueryUserUniversalTransferHistoryParams {
1844            r#type,
1845            start_time,
1846            end_time,
1847            current,
1848            size,
1849            from_symbol,
1850            to_symbol,
1851            recv_window,
1852        } = params;
1853
1854        let mut query_params = BTreeMap::new();
1855        let body_params = BTreeMap::new();
1856
1857        query_params.insert("type".to_string(), json!(r#type));
1858
1859        if let Some(rw) = start_time {
1860            query_params.insert("startTime".to_string(), json!(rw));
1861        }
1862
1863        if let Some(rw) = end_time {
1864            query_params.insert("endTime".to_string(), json!(rw));
1865        }
1866
1867        if let Some(rw) = current {
1868            query_params.insert("current".to_string(), json!(rw));
1869        }
1870
1871        if let Some(rw) = size {
1872            query_params.insert("size".to_string(), json!(rw));
1873        }
1874
1875        if let Some(rw) = from_symbol {
1876            query_params.insert("fromSymbol".to_string(), json!(rw));
1877        }
1878
1879        if let Some(rw) = to_symbol {
1880            query_params.insert("toSymbol".to_string(), json!(rw));
1881        }
1882
1883        if let Some(rw) = recv_window {
1884            query_params.insert("recvWindow".to_string(), json!(rw));
1885        }
1886
1887        send_request::<models::QueryUserUniversalTransferHistoryResponse>(
1888            &self.configuration,
1889            "/sapi/v1/asset/transfer",
1890            reqwest::Method::GET,
1891            query_params,
1892            body_params,
1893            if HAS_TIME_UNIT {
1894                self.configuration.time_unit
1895            } else {
1896                None
1897            },
1898            true,
1899        )
1900        .await
1901    }
1902
1903    async fn query_user_wallet_balance(
1904        &self,
1905        params: QueryUserWalletBalanceParams,
1906    ) -> anyhow::Result<RestApiResponse<Vec<models::QueryUserWalletBalanceResponseInner>>> {
1907        let QueryUserWalletBalanceParams {
1908            quote_asset,
1909            recv_window,
1910        } = params;
1911
1912        let mut query_params = BTreeMap::new();
1913        let body_params = BTreeMap::new();
1914
1915        if let Some(rw) = quote_asset {
1916            query_params.insert("quoteAsset".to_string(), json!(rw));
1917        }
1918
1919        if let Some(rw) = recv_window {
1920            query_params.insert("recvWindow".to_string(), json!(rw));
1921        }
1922
1923        send_request::<Vec<models::QueryUserWalletBalanceResponseInner>>(
1924            &self.configuration,
1925            "/sapi/v1/asset/wallet/balance",
1926            reqwest::Method::GET,
1927            query_params,
1928            body_params,
1929            if HAS_TIME_UNIT {
1930                self.configuration.time_unit
1931            } else {
1932                None
1933            },
1934            true,
1935        )
1936        .await
1937    }
1938
1939    async fn toggle_bnb_burn_on_spot_trade_and_margin_interest(
1940        &self,
1941        params: ToggleBnbBurnOnSpotTradeAndMarginInterestParams,
1942    ) -> anyhow::Result<RestApiResponse<models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse>>
1943    {
1944        let ToggleBnbBurnOnSpotTradeAndMarginInterestParams {
1945            spot_bnb_burn,
1946            interest_bnb_burn,
1947            recv_window,
1948        } = params;
1949
1950        let mut query_params = BTreeMap::new();
1951        let body_params = BTreeMap::new();
1952
1953        if let Some(rw) = spot_bnb_burn {
1954            query_params.insert("spotBNBBurn".to_string(), json!(rw));
1955        }
1956
1957        if let Some(rw) = interest_bnb_burn {
1958            query_params.insert("interestBNBBurn".to_string(), json!(rw));
1959        }
1960
1961        if let Some(rw) = recv_window {
1962            query_params.insert("recvWindow".to_string(), json!(rw));
1963        }
1964
1965        send_request::<models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse>(
1966            &self.configuration,
1967            "/sapi/v1/bnbBurn",
1968            reqwest::Method::POST,
1969            query_params,
1970            body_params,
1971            if HAS_TIME_UNIT {
1972                self.configuration.time_unit
1973            } else {
1974                None
1975            },
1976            true,
1977        )
1978        .await
1979    }
1980
1981    async fn trade_fee(
1982        &self,
1983        params: TradeFeeParams,
1984    ) -> anyhow::Result<RestApiResponse<Vec<models::TradeFeeResponseInner>>> {
1985        let TradeFeeParams {
1986            symbol,
1987            recv_window,
1988        } = params;
1989
1990        let mut query_params = BTreeMap::new();
1991        let body_params = BTreeMap::new();
1992
1993        if let Some(rw) = symbol {
1994            query_params.insert("symbol".to_string(), json!(rw));
1995        }
1996
1997        if let Some(rw) = recv_window {
1998            query_params.insert("recvWindow".to_string(), json!(rw));
1999        }
2000
2001        send_request::<Vec<models::TradeFeeResponseInner>>(
2002            &self.configuration,
2003            "/sapi/v1/asset/tradeFee",
2004            reqwest::Method::GET,
2005            query_params,
2006            body_params,
2007            if HAS_TIME_UNIT {
2008                self.configuration.time_unit
2009            } else {
2010                None
2011            },
2012            true,
2013        )
2014        .await
2015    }
2016
2017    async fn user_asset(
2018        &self,
2019        params: UserAssetParams,
2020    ) -> anyhow::Result<RestApiResponse<Vec<models::UserAssetResponseInner>>> {
2021        let UserAssetParams {
2022            asset,
2023            need_btc_valuation,
2024            recv_window,
2025        } = params;
2026
2027        let mut query_params = BTreeMap::new();
2028        let body_params = BTreeMap::new();
2029
2030        if let Some(rw) = asset {
2031            query_params.insert("asset".to_string(), json!(rw));
2032        }
2033
2034        if let Some(rw) = need_btc_valuation {
2035            query_params.insert("needBtcValuation".to_string(), json!(rw));
2036        }
2037
2038        if let Some(rw) = recv_window {
2039            query_params.insert("recvWindow".to_string(), json!(rw));
2040        }
2041
2042        send_request::<Vec<models::UserAssetResponseInner>>(
2043            &self.configuration,
2044            "/sapi/v3/asset/getUserAsset",
2045            reqwest::Method::POST,
2046            query_params,
2047            body_params,
2048            if HAS_TIME_UNIT {
2049                self.configuration.time_unit
2050            } else {
2051                None
2052            },
2053            true,
2054        )
2055        .await
2056    }
2057
2058    async fn user_universal_transfer(
2059        &self,
2060        params: UserUniversalTransferParams,
2061    ) -> anyhow::Result<RestApiResponse<models::UserUniversalTransferResponse>> {
2062        let UserUniversalTransferParams {
2063            r#type,
2064            asset,
2065            amount,
2066            from_symbol,
2067            to_symbol,
2068            recv_window,
2069        } = params;
2070
2071        let mut query_params = BTreeMap::new();
2072        let body_params = BTreeMap::new();
2073
2074        query_params.insert("type".to_string(), json!(r#type));
2075
2076        query_params.insert("asset".to_string(), json!(asset));
2077
2078        query_params.insert("amount".to_string(), json!(amount));
2079
2080        if let Some(rw) = from_symbol {
2081            query_params.insert("fromSymbol".to_string(), json!(rw));
2082        }
2083
2084        if let Some(rw) = to_symbol {
2085            query_params.insert("toSymbol".to_string(), json!(rw));
2086        }
2087
2088        if let Some(rw) = recv_window {
2089            query_params.insert("recvWindow".to_string(), json!(rw));
2090        }
2091
2092        send_request::<models::UserUniversalTransferResponse>(
2093            &self.configuration,
2094            "/sapi/v1/asset/transfer",
2095            reqwest::Method::POST,
2096            query_params,
2097            body_params,
2098            if HAS_TIME_UNIT {
2099                self.configuration.time_unit
2100            } else {
2101                None
2102            },
2103            true,
2104        )
2105        .await
2106    }
2107}
2108
2109#[cfg(all(test, feature = "wallet"))]
2110mod tests {
2111    use super::*;
2112    use crate::TOKIO_SHARED_RT;
2113    use crate::{errors::ConnectorError, models::DataFuture, models::RestApiRateLimit};
2114    use async_trait::async_trait;
2115    use std::collections::HashMap;
2116
2117    struct DummyRestApiResponse<T> {
2118        inner: Box<dyn FnOnce() -> DataFuture<Result<T, ConnectorError>> + Send + Sync>,
2119        status: u16,
2120        headers: HashMap<String, String>,
2121        rate_limits: Option<Vec<RestApiRateLimit>>,
2122    }
2123
2124    impl<T> From<DummyRestApiResponse<T>> for RestApiResponse<T> {
2125        fn from(dummy: DummyRestApiResponse<T>) -> Self {
2126            Self {
2127                data_fn: dummy.inner,
2128                status: dummy.status,
2129                headers: dummy.headers,
2130                rate_limits: dummy.rate_limits,
2131            }
2132        }
2133    }
2134
2135    struct MockAssetApiClient {
2136        force_error: bool,
2137    }
2138
2139    #[async_trait]
2140    impl AssetApi for MockAssetApiClient {
2141        async fn asset_detail(
2142            &self,
2143            _params: AssetDetailParams,
2144        ) -> anyhow::Result<RestApiResponse<models::AssetDetailResponse>> {
2145            if self.force_error {
2146                return Err(ConnectorError::ConnectorClientError {
2147                    msg: "ResponseError".to_string(),
2148                    code: None,
2149                }
2150                .into());
2151            }
2152
2153            let resp_json: Value = serde_json::from_str(r#"{"CTR":{"minWithdrawAmount":"70.00000000","depositStatus":false,"withdrawFee":35,"withdrawStatus":true,"depositTip":"Delisted, Deposit Suspended"},"SKY":{"minWithdrawAmount":"0.02000000","depositStatus":true,"withdrawFee":0.01,"withdrawStatus":true}}"#).unwrap_or_else(|_| serde_json::json!({}));
2154            let dummy_response: models::AssetDetailResponse =
2155                serde_json::from_value(resp_json.clone())
2156                    .expect("should parse into models::AssetDetailResponse");
2157
2158            let dummy = DummyRestApiResponse {
2159                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2160                status: 200,
2161                headers: HashMap::new(),
2162                rate_limits: None,
2163            };
2164
2165            Ok(dummy.into())
2166        }
2167
2168        async fn asset_dividend_record(
2169            &self,
2170            _params: AssetDividendRecordParams,
2171        ) -> anyhow::Result<RestApiResponse<models::AssetDividendRecordResponse>> {
2172            if self.force_error {
2173                return Err(ConnectorError::ConnectorClientError {
2174                    msg: "ResponseError".to_string(),
2175                    code: None,
2176                }
2177                .into());
2178            }
2179
2180            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"id":1637366104,"amount":"10.00000000","asset":"BHFT","divTime":1563189166000,"enInfo":"BHFT distribution","tranId":2968885920,"direction":1}],"total":2}"#).unwrap_or_else(|_| serde_json::json!({}));
2181            let dummy_response: models::AssetDividendRecordResponse =
2182                serde_json::from_value(resp_json.clone())
2183                    .expect("should parse into models::AssetDividendRecordResponse");
2184
2185            let dummy = DummyRestApiResponse {
2186                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2187                status: 200,
2188                headers: HashMap::new(),
2189                rate_limits: None,
2190            };
2191
2192            Ok(dummy.into())
2193        }
2194
2195        async fn dust_convert(
2196            &self,
2197            _params: DustConvertParams,
2198        ) -> anyhow::Result<RestApiResponse<models::DustConvertResponse>> {
2199            if self.force_error {
2200                return Err(ConnectorError::ConnectorClientError {
2201                    msg: "ResponseError".to_string(),
2202                    code: None,
2203                }
2204                .into());
2205            }
2206
2207            let resp_json: Value = serde_json::from_str(r#"{"totalTransfered":"3.5971223","totalServiceCharge":"0.0794964","transferResult":[{"tranId":2987331510,"fromAsset":"USDT","amount":"1","transferedAmount":"3.5971223","serviceChargeAmount":"0.0794964","operateTime":1765212029749}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2208            let dummy_response: models::DustConvertResponse =
2209                serde_json::from_value(resp_json.clone())
2210                    .expect("should parse into models::DustConvertResponse");
2211
2212            let dummy = DummyRestApiResponse {
2213                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2214                status: 200,
2215                headers: HashMap::new(),
2216                rate_limits: None,
2217            };
2218
2219            Ok(dummy.into())
2220        }
2221
2222        async fn dust_convertible_assets(
2223            &self,
2224            _params: DustConvertibleAssetsParams,
2225        ) -> anyhow::Result<RestApiResponse<models::DustConvertibleAssetsResponse>> {
2226            if self.force_error {
2227                return Err(ConnectorError::ConnectorClientError {
2228                    msg: "ResponseError".to_string(),
2229                    code: None,
2230                }
2231                .into());
2232            }
2233
2234            let resp_json: Value = serde_json::from_str(r#"{"dribbletPercentage":"0.02","totalTransferQuotaAssetAmount":"0.7899968","totalTransferTargetAssetAmount":"0.7899968","dribbletBase":"10","details":[{"asset":"AR","assetFullName":"AR","amountFree":"0.00856","exchange":"0.00073616","toQuotaAssetAmount":"0.036808","toTargetAssetAmount":"0.036808","toTargetAssetOffExchange":"0.03607184"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2235            let dummy_response: models::DustConvertibleAssetsResponse =
2236                serde_json::from_value(resp_json.clone())
2237                    .expect("should parse into models::DustConvertibleAssetsResponse");
2238
2239            let dummy = DummyRestApiResponse {
2240                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2241                status: 200,
2242                headers: HashMap::new(),
2243                rate_limits: None,
2244            };
2245
2246            Ok(dummy.into())
2247        }
2248
2249        async fn dust_transfer(
2250            &self,
2251            _params: DustTransferParams,
2252        ) -> anyhow::Result<RestApiResponse<models::DustTransferResponse>> {
2253            if self.force_error {
2254                return Err(ConnectorError::ConnectorClientError {
2255                    msg: "ResponseError".to_string(),
2256                    code: None,
2257                }
2258                .into());
2259            }
2260
2261            let resp_json: Value = serde_json::from_str(r#"{"totalServiceCharge":"0.02102542","totalTransfered":"1.05127099","transferResult":[{"amount":"0.03000000","fromAsset":"ETH","operateTime":1563368549307,"serviceChargeAmount":"0.00500000","tranId":2970932918,"transferedAmount":"0.25000000"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2262            let dummy_response: models::DustTransferResponse =
2263                serde_json::from_value(resp_json.clone())
2264                    .expect("should parse into models::DustTransferResponse");
2265
2266            let dummy = DummyRestApiResponse {
2267                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2268                status: 200,
2269                headers: HashMap::new(),
2270                rate_limits: None,
2271            };
2272
2273            Ok(dummy.into())
2274        }
2275
2276        async fn dustlog(
2277            &self,
2278            _params: DustlogParams,
2279        ) -> anyhow::Result<RestApiResponse<models::DustlogResponse>> {
2280            if self.force_error {
2281                return Err(ConnectorError::ConnectorClientError {
2282                    msg: "ResponseError".to_string(),
2283                    code: None,
2284                }
2285                .into());
2286            }
2287
2288            let resp_json: Value = serde_json::from_str(r#"{"total":8,"userAssetDribblets":[{"operateTime":1615985535000,"totalTransferedAmount":"0.00132256","totalServiceChargeAmount":"0.00002699","transId":45178372831,"userAssetDribbletDetails":[{"transId":4359321,"serviceChargeAmount":"0.000009","amount":"0.0009","operateTime":1615985535000,"transferedAmount":"0.000441","fromAsset":"USDT","targetAsset":"BNB"}]}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2289            let dummy_response: models::DustlogResponse = serde_json::from_value(resp_json.clone())
2290                .expect("should parse into models::DustlogResponse");
2291
2292            let dummy = DummyRestApiResponse {
2293                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2294                status: 200,
2295                headers: HashMap::new(),
2296                rate_limits: None,
2297            };
2298
2299            Ok(dummy.into())
2300        }
2301
2302        async fn funding_wallet(
2303            &self,
2304            _params: FundingWalletParams,
2305        ) -> anyhow::Result<RestApiResponse<Vec<models::FundingWalletResponseInner>>> {
2306            if self.force_error {
2307                return Err(ConnectorError::ConnectorClientError {
2308                    msg: "ResponseError".to_string(),
2309                    code: None,
2310                }
2311                .into());
2312            }
2313
2314            let resp_json: Value = serde_json::from_str(r#"[{"asset":"USDT","free":"1","locked":"0","freeze":"0","withdrawing":"0","btcValuation":"0.00000091"}]"#).unwrap_or_else(|_| serde_json::json!({}));
2315            let dummy_response: Vec<models::FundingWalletResponseInner> =
2316                serde_json::from_value(resp_json.clone())
2317                    .expect("should parse into Vec<models::FundingWalletResponseInner>");
2318
2319            let dummy = DummyRestApiResponse {
2320                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2321                status: 200,
2322                headers: HashMap::new(),
2323                rate_limits: None,
2324            };
2325
2326            Ok(dummy.into())
2327        }
2328
2329        async fn get_assets_that_can_be_converted_into_bnb(
2330            &self,
2331            _params: GetAssetsThatCanBeConvertedIntoBnbParams,
2332        ) -> anyhow::Result<RestApiResponse<models::GetAssetsThatCanBeConvertedIntoBnbResponse>>
2333        {
2334            if self.force_error {
2335                return Err(ConnectorError::ConnectorClientError {
2336                    msg: "ResponseError".to_string(),
2337                    code: None,
2338                }
2339                .into());
2340            }
2341
2342            let resp_json: Value = serde_json::from_str(r#"{"details":[{"asset":"ADA","assetFullName":"ADA","amountFree":"6.21","toBTC":"0.00016848","toBNB":"0.01777302","toBNBOffExchange":"0.01741756","exchange":"0.00035546"}],"totalTransferBtc":"0.00016848","totalTransferBNB":"0.01777302","dribbletPercentage":"0.02"}"#).unwrap_or_else(|_| serde_json::json!({}));
2343            let dummy_response: models::GetAssetsThatCanBeConvertedIntoBnbResponse =
2344                serde_json::from_value(resp_json.clone())
2345                    .expect("should parse into models::GetAssetsThatCanBeConvertedIntoBnbResponse");
2346
2347            let dummy = DummyRestApiResponse {
2348                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2349                status: 200,
2350                headers: HashMap::new(),
2351                rate_limits: None,
2352            };
2353
2354            Ok(dummy.into())
2355        }
2356
2357        async fn get_cloud_mining_payment_and_refund_history(
2358            &self,
2359            _params: GetCloudMiningPaymentAndRefundHistoryParams,
2360        ) -> anyhow::Result<RestApiResponse<models::GetCloudMiningPaymentAndRefundHistoryResponse>>
2361        {
2362            if self.force_error {
2363                return Err(ConnectorError::ConnectorClientError {
2364                    msg: "ResponseError".to_string(),
2365                    code: None,
2366                }
2367                .into());
2368            }
2369
2370            let resp_json: Value = serde_json::from_str(r#"{"total":5,"rows":[{"createTime":1667880112000,"tranId":121230610120,"type":248,"asset":"USDT","amount":"25.0068","status":"S"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2371            let dummy_response: models::GetCloudMiningPaymentAndRefundHistoryResponse =
2372                serde_json::from_value(resp_json.clone()).expect(
2373                    "should parse into models::GetCloudMiningPaymentAndRefundHistoryResponse",
2374                );
2375
2376            let dummy = DummyRestApiResponse {
2377                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2378                status: 200,
2379                headers: HashMap::new(),
2380                rate_limits: None,
2381            };
2382
2383            Ok(dummy.into())
2384        }
2385
2386        async fn get_open_symbol_list(
2387            &self,
2388        ) -> anyhow::Result<RestApiResponse<Vec<models::GetOpenSymbolListResponseInner>>> {
2389            if self.force_error {
2390                return Err(ConnectorError::ConnectorClientError {
2391                    msg: "ResponseError".to_string(),
2392                    code: None,
2393                }
2394                .into());
2395            }
2396
2397            let resp_json: Value =
2398                serde_json::from_str(r#"[{"openTime":1686161202000,"symbols":["BNBBTC"]}]"#)
2399                    .unwrap_or_else(|_| serde_json::json!({}));
2400            let dummy_response: Vec<models::GetOpenSymbolListResponseInner> =
2401                serde_json::from_value(resp_json.clone())
2402                    .expect("should parse into Vec<models::GetOpenSymbolListResponseInner>");
2403
2404            let dummy = DummyRestApiResponse {
2405                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2406                status: 200,
2407                headers: HashMap::new(),
2408                rate_limits: None,
2409            };
2410
2411            Ok(dummy.into())
2412        }
2413
2414        async fn get_spot_asset_tags(
2415            &self,
2416            _params: GetSpotAssetTagsParams,
2417        ) -> anyhow::Result<RestApiResponse<Vec<models::GetSpotAssetTagsResponseInner>>> {
2418            if self.force_error {
2419                return Err(ConnectorError::ConnectorClientError {
2420                    msg: "ResponseError".to_string(),
2421                    code: None,
2422                }
2423                .into());
2424            }
2425
2426            let resp_json: Value = serde_json::from_str(r#"[{"assetCode":"BNB","assetName":"BNB","trading":true,"tags":["Layer1_Layer2","BSC"]}]"#).unwrap_or_else(|_| serde_json::json!({}));
2427            let dummy_response: Vec<models::GetSpotAssetTagsResponseInner> =
2428                serde_json::from_value(resp_json.clone())
2429                    .expect("should parse into Vec<models::GetSpotAssetTagsResponseInner>");
2430
2431            let dummy = DummyRestApiResponse {
2432                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2433                status: 200,
2434                headers: HashMap::new(),
2435                rate_limits: None,
2436            };
2437
2438            Ok(dummy.into())
2439        }
2440
2441        async fn query_user_delegation_history(
2442            &self,
2443            _params: QueryUserDelegationHistoryParams,
2444        ) -> anyhow::Result<RestApiResponse<models::QueryUserDelegationHistoryResponse>> {
2445            if self.force_error {
2446                return Err(ConnectorError::ConnectorClientError {
2447                    msg: "ResponseError".to_string(),
2448                    code: None,
2449                }
2450                .into());
2451            }
2452
2453            let resp_json: Value = serde_json::from_str(r#"{"total":3316,"rows":[{"clientTranId":"293915932290879488","transferType":"Undelegate","asset":"ETH","amount":"1","time":1695205406000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2454            let dummy_response: models::QueryUserDelegationHistoryResponse =
2455                serde_json::from_value(resp_json.clone())
2456                    .expect("should parse into models::QueryUserDelegationHistoryResponse");
2457
2458            let dummy = DummyRestApiResponse {
2459                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2460                status: 200,
2461                headers: HashMap::new(),
2462                rate_limits: None,
2463            };
2464
2465            Ok(dummy.into())
2466        }
2467
2468        async fn query_user_universal_transfer_history(
2469            &self,
2470            _params: QueryUserUniversalTransferHistoryParams,
2471        ) -> anyhow::Result<RestApiResponse<models::QueryUserUniversalTransferHistoryResponse>>
2472        {
2473            if self.force_error {
2474                return Err(ConnectorError::ConnectorClientError {
2475                    msg: "ResponseError".to_string(),
2476                    code: None,
2477                }
2478                .into());
2479            }
2480
2481            let resp_json: Value = serde_json::from_str(r#"{"total":2,"rows":[{"asset":"USDT","amount":"1","type":"MAIN_UMFUTURE","status":"CONFIRMED","tranId":11415955596,"timestamp":1544433328000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2482            let dummy_response: models::QueryUserUniversalTransferHistoryResponse =
2483                serde_json::from_value(resp_json.clone())
2484                    .expect("should parse into models::QueryUserUniversalTransferHistoryResponse");
2485
2486            let dummy = DummyRestApiResponse {
2487                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2488                status: 200,
2489                headers: HashMap::new(),
2490                rate_limits: None,
2491            };
2492
2493            Ok(dummy.into())
2494        }
2495
2496        async fn query_user_wallet_balance(
2497            &self,
2498            _params: QueryUserWalletBalanceParams,
2499        ) -> anyhow::Result<RestApiResponse<Vec<models::QueryUserWalletBalanceResponseInner>>>
2500        {
2501            if self.force_error {
2502                return Err(ConnectorError::ConnectorClientError {
2503                    msg: "ResponseError".to_string(),
2504                    code: None,
2505                }
2506                .into());
2507            }
2508
2509            let resp_json: Value =
2510                serde_json::from_str(r#"[{"activate":true,"balance":"0","walletName":"Spot"}]"#)
2511                    .unwrap_or_else(|_| serde_json::json!({}));
2512            let dummy_response: Vec<models::QueryUserWalletBalanceResponseInner> =
2513                serde_json::from_value(resp_json.clone())
2514                    .expect("should parse into Vec<models::QueryUserWalletBalanceResponseInner>");
2515
2516            let dummy = DummyRestApiResponse {
2517                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2518                status: 200,
2519                headers: HashMap::new(),
2520                rate_limits: None,
2521            };
2522
2523            Ok(dummy.into())
2524        }
2525
2526        async fn toggle_bnb_burn_on_spot_trade_and_margin_interest(
2527            &self,
2528            _params: ToggleBnbBurnOnSpotTradeAndMarginInterestParams,
2529        ) -> anyhow::Result<
2530            RestApiResponse<models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse>,
2531        > {
2532            if self.force_error {
2533                return Err(ConnectorError::ConnectorClientError {
2534                    msg: "ResponseError".to_string(),
2535                    code: None,
2536                }
2537                .into());
2538            }
2539
2540            let resp_json: Value =
2541                serde_json::from_str(r#"{"spotBNBBurn":true,"interestBNBBurn":false}"#)
2542                    .unwrap_or_else(|_| serde_json::json!({}));
2543            let dummy_response: models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse =
2544                serde_json::from_value(resp_json.clone()).expect(
2545                    "should parse into models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse",
2546                );
2547
2548            let dummy = DummyRestApiResponse {
2549                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2550                status: 200,
2551                headers: HashMap::new(),
2552                rate_limits: None,
2553            };
2554
2555            Ok(dummy.into())
2556        }
2557
2558        async fn trade_fee(
2559            &self,
2560            _params: TradeFeeParams,
2561        ) -> anyhow::Result<RestApiResponse<Vec<models::TradeFeeResponseInner>>> {
2562            if self.force_error {
2563                return Err(ConnectorError::ConnectorClientError {
2564                    msg: "ResponseError".to_string(),
2565                    code: None,
2566                }
2567                .into());
2568            }
2569
2570            let resp_json: Value = serde_json::from_str(
2571                r#"[{"symbol":"ADABNB","makerCommission":"0.001","takerCommission":"0.001"}]"#,
2572            )
2573            .unwrap_or_else(|_| serde_json::json!({}));
2574            let dummy_response: Vec<models::TradeFeeResponseInner> =
2575                serde_json::from_value(resp_json.clone())
2576                    .expect("should parse into Vec<models::TradeFeeResponseInner>");
2577
2578            let dummy = DummyRestApiResponse {
2579                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2580                status: 200,
2581                headers: HashMap::new(),
2582                rate_limits: None,
2583            };
2584
2585            Ok(dummy.into())
2586        }
2587
2588        async fn user_asset(
2589            &self,
2590            _params: UserAssetParams,
2591        ) -> anyhow::Result<RestApiResponse<Vec<models::UserAssetResponseInner>>> {
2592            if self.force_error {
2593                return Err(ConnectorError::ConnectorClientError {
2594                    msg: "ResponseError".to_string(),
2595                    code: None,
2596                }
2597                .into());
2598            }
2599
2600            let resp_json: Value = serde_json::from_str(r#"[{"asset":"AVAX","free":"1","locked":"0","freeze":"0","withdrawing":"0","ipoable":"0","btcValuation":"0"}]"#).unwrap_or_else(|_| serde_json::json!({}));
2601            let dummy_response: Vec<models::UserAssetResponseInner> =
2602                serde_json::from_value(resp_json.clone())
2603                    .expect("should parse into Vec<models::UserAssetResponseInner>");
2604
2605            let dummy = DummyRestApiResponse {
2606                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2607                status: 200,
2608                headers: HashMap::new(),
2609                rate_limits: None,
2610            };
2611
2612            Ok(dummy.into())
2613        }
2614
2615        async fn user_universal_transfer(
2616            &self,
2617            _params: UserUniversalTransferParams,
2618        ) -> anyhow::Result<RestApiResponse<models::UserUniversalTransferResponse>> {
2619            if self.force_error {
2620                return Err(ConnectorError::ConnectorClientError {
2621                    msg: "ResponseError".to_string(),
2622                    code: None,
2623                }
2624                .into());
2625            }
2626
2627            let resp_json: Value = serde_json::from_str(r#"{"tranId":13526853623}"#)
2628                .unwrap_or_else(|_| serde_json::json!({}));
2629            let dummy_response: models::UserUniversalTransferResponse =
2630                serde_json::from_value(resp_json.clone())
2631                    .expect("should parse into models::UserUniversalTransferResponse");
2632
2633            let dummy = DummyRestApiResponse {
2634                inner: Box::new(move || Box::pin(async move { Ok(dummy_response) })),
2635                status: 200,
2636                headers: HashMap::new(),
2637                rate_limits: None,
2638            };
2639
2640            Ok(dummy.into())
2641        }
2642    }
2643
2644    #[test]
2645    fn asset_detail_required_params_success() {
2646        TOKIO_SHARED_RT.block_on(async {
2647            let client = MockAssetApiClient { force_error: false };
2648
2649            let params = AssetDetailParams::builder().build().unwrap();
2650
2651            let resp_json: Value = serde_json::from_str(r#"{"CTR":{"minWithdrawAmount":"70.00000000","depositStatus":false,"withdrawFee":35,"withdrawStatus":true,"depositTip":"Delisted, Deposit Suspended"},"SKY":{"minWithdrawAmount":"0.02000000","depositStatus":true,"withdrawFee":0.01,"withdrawStatus":true}}"#).unwrap_or_else(|_| serde_json::json!({}));
2652            let expected_response : models::AssetDetailResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AssetDetailResponse");
2653
2654            let resp = client.asset_detail(params).await.expect("Expected a response");
2655            let data_future = resp.data();
2656            let actual_response = data_future.await.unwrap();
2657            assert_eq!(actual_response, expected_response);
2658        });
2659    }
2660
2661    #[test]
2662    fn asset_detail_optional_params_success() {
2663        TOKIO_SHARED_RT.block_on(async {
2664            let client = MockAssetApiClient { force_error: false };
2665
2666            let params = AssetDetailParams::builder().asset("BTC".to_string()).recv_window(5000).build().unwrap();
2667
2668            let resp_json: Value = serde_json::from_str(r#"{"CTR":{"minWithdrawAmount":"70.00000000","depositStatus":false,"withdrawFee":35,"withdrawStatus":true,"depositTip":"Delisted, Deposit Suspended"},"SKY":{"minWithdrawAmount":"0.02000000","depositStatus":true,"withdrawFee":0.01,"withdrawStatus":true}}"#).unwrap_or_else(|_| serde_json::json!({}));
2669            let expected_response : models::AssetDetailResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AssetDetailResponse");
2670
2671            let resp = client.asset_detail(params).await.expect("Expected a response");
2672            let data_future = resp.data();
2673            let actual_response = data_future.await.unwrap();
2674            assert_eq!(actual_response, expected_response);
2675        });
2676    }
2677
2678    #[test]
2679    fn asset_detail_response_error() {
2680        TOKIO_SHARED_RT.block_on(async {
2681            let client = MockAssetApiClient { force_error: true };
2682
2683            let params = AssetDetailParams::builder().build().unwrap();
2684
2685            match client.asset_detail(params).await {
2686                Ok(_) => panic!("Expected an error"),
2687                Err(err) => {
2688                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2689                }
2690            }
2691        });
2692    }
2693
2694    #[test]
2695    fn asset_dividend_record_required_params_success() {
2696        TOKIO_SHARED_RT.block_on(async {
2697            let client = MockAssetApiClient { force_error: false };
2698
2699            let params = AssetDividendRecordParams::builder().build().unwrap();
2700
2701            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"id":1637366104,"amount":"10.00000000","asset":"BHFT","divTime":1563189166000,"enInfo":"BHFT distribution","tranId":2968885920,"direction":1}],"total":2}"#).unwrap_or_else(|_| serde_json::json!({}));
2702            let expected_response : models::AssetDividendRecordResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AssetDividendRecordResponse");
2703
2704            let resp = client.asset_dividend_record(params).await.expect("Expected a response");
2705            let data_future = resp.data();
2706            let actual_response = data_future.await.unwrap();
2707            assert_eq!(actual_response, expected_response);
2708        });
2709    }
2710
2711    #[test]
2712    fn asset_dividend_record_optional_params_success() {
2713        TOKIO_SHARED_RT.block_on(async {
2714            let client = MockAssetApiClient { force_error: false };
2715
2716            let params = AssetDividendRecordParams::builder().asset("BTC".to_string()).start_time(1623319461670).end_time(1641782889000).limit(20).recv_window(5000).build().unwrap();
2717
2718            let resp_json: Value = serde_json::from_str(r#"{"rows":[{"id":1637366104,"amount":"10.00000000","asset":"BHFT","divTime":1563189166000,"enInfo":"BHFT distribution","tranId":2968885920,"direction":1}],"total":2}"#).unwrap_or_else(|_| serde_json::json!({}));
2719            let expected_response : models::AssetDividendRecordResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::AssetDividendRecordResponse");
2720
2721            let resp = client.asset_dividend_record(params).await.expect("Expected a response");
2722            let data_future = resp.data();
2723            let actual_response = data_future.await.unwrap();
2724            assert_eq!(actual_response, expected_response);
2725        });
2726    }
2727
2728    #[test]
2729    fn asset_dividend_record_response_error() {
2730        TOKIO_SHARED_RT.block_on(async {
2731            let client = MockAssetApiClient { force_error: true };
2732
2733            let params = AssetDividendRecordParams::builder().build().unwrap();
2734
2735            match client.asset_dividend_record(params).await {
2736                Ok(_) => panic!("Expected an error"),
2737                Err(err) => {
2738                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2739                }
2740            }
2741        });
2742    }
2743
2744    #[test]
2745    fn dust_convert_required_params_success() {
2746        TOKIO_SHARED_RT.block_on(async {
2747            let client = MockAssetApiClient { force_error: false };
2748
2749            let params = DustConvertParams::builder("USDT".to_string(),).build().unwrap();
2750
2751            let resp_json: Value = serde_json::from_str(r#"{"totalTransfered":"3.5971223","totalServiceCharge":"0.0794964","transferResult":[{"tranId":2987331510,"fromAsset":"USDT","amount":"1","transferedAmount":"3.5971223","serviceChargeAmount":"0.0794964","operateTime":1765212029749}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2752            let expected_response : models::DustConvertResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustConvertResponse");
2753
2754            let resp = client.dust_convert(params).await.expect("Expected a response");
2755            let data_future = resp.data();
2756            let actual_response = data_future.await.unwrap();
2757            assert_eq!(actual_response, expected_response);
2758        });
2759    }
2760
2761    #[test]
2762    fn dust_convert_optional_params_success() {
2763        TOKIO_SHARED_RT.block_on(async {
2764            let client = MockAssetApiClient { force_error: false };
2765
2766            let params = DustConvertParams::builder("USDT".to_string(),).account_type("SPOT".to_string()).client_id("1".to_string()).target_asset("BTC".to_string()).third_party_client_id("1".to_string()).dust_quota_asset_to_target_asset_price(dec!(1.0)).build().unwrap();
2767
2768            let resp_json: Value = serde_json::from_str(r#"{"totalTransfered":"3.5971223","totalServiceCharge":"0.0794964","transferResult":[{"tranId":2987331510,"fromAsset":"USDT","amount":"1","transferedAmount":"3.5971223","serviceChargeAmount":"0.0794964","operateTime":1765212029749}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2769            let expected_response : models::DustConvertResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustConvertResponse");
2770
2771            let resp = client.dust_convert(params).await.expect("Expected a response");
2772            let data_future = resp.data();
2773            let actual_response = data_future.await.unwrap();
2774            assert_eq!(actual_response, expected_response);
2775        });
2776    }
2777
2778    #[test]
2779    fn dust_convert_response_error() {
2780        TOKIO_SHARED_RT.block_on(async {
2781            let client = MockAssetApiClient { force_error: true };
2782
2783            let params = DustConvertParams::builder("USDT".to_string())
2784                .build()
2785                .unwrap();
2786
2787            match client.dust_convert(params).await {
2788                Ok(_) => panic!("Expected an error"),
2789                Err(err) => {
2790                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2791                }
2792            }
2793        });
2794    }
2795
2796    #[test]
2797    fn dust_convertible_assets_required_params_success() {
2798        TOKIO_SHARED_RT.block_on(async {
2799            let client = MockAssetApiClient { force_error: false };
2800
2801            let params = DustConvertibleAssetsParams::builder("BTC".to_string(),).build().unwrap();
2802
2803            let resp_json: Value = serde_json::from_str(r#"{"dribbletPercentage":"0.02","totalTransferQuotaAssetAmount":"0.7899968","totalTransferTargetAssetAmount":"0.7899968","dribbletBase":"10","details":[{"asset":"AR","assetFullName":"AR","amountFree":"0.00856","exchange":"0.00073616","toQuotaAssetAmount":"0.036808","toTargetAssetAmount":"0.036808","toTargetAssetOffExchange":"0.03607184"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2804            let expected_response : models::DustConvertibleAssetsResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustConvertibleAssetsResponse");
2805
2806            let resp = client.dust_convertible_assets(params).await.expect("Expected a response");
2807            let data_future = resp.data();
2808            let actual_response = data_future.await.unwrap();
2809            assert_eq!(actual_response, expected_response);
2810        });
2811    }
2812
2813    #[test]
2814    fn dust_convertible_assets_optional_params_success() {
2815        TOKIO_SHARED_RT.block_on(async {
2816            let client = MockAssetApiClient { force_error: false };
2817
2818            let params = DustConvertibleAssetsParams::builder("BTC".to_string(),).account_type("SPOT".to_string()).dust_quota_asset_to_target_asset_price(dec!(1.0)).build().unwrap();
2819
2820            let resp_json: Value = serde_json::from_str(r#"{"dribbletPercentage":"0.02","totalTransferQuotaAssetAmount":"0.7899968","totalTransferTargetAssetAmount":"0.7899968","dribbletBase":"10","details":[{"asset":"AR","assetFullName":"AR","amountFree":"0.00856","exchange":"0.00073616","toQuotaAssetAmount":"0.036808","toTargetAssetAmount":"0.036808","toTargetAssetOffExchange":"0.03607184"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2821            let expected_response : models::DustConvertibleAssetsResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustConvertibleAssetsResponse");
2822
2823            let resp = client.dust_convertible_assets(params).await.expect("Expected a response");
2824            let data_future = resp.data();
2825            let actual_response = data_future.await.unwrap();
2826            assert_eq!(actual_response, expected_response);
2827        });
2828    }
2829
2830    #[test]
2831    fn dust_convertible_assets_response_error() {
2832        TOKIO_SHARED_RT.block_on(async {
2833            let client = MockAssetApiClient { force_error: true };
2834
2835            let params = DustConvertibleAssetsParams::builder("BTC".to_string())
2836                .build()
2837                .unwrap();
2838
2839            match client.dust_convertible_assets(params).await {
2840                Ok(_) => panic!("Expected an error"),
2841                Err(err) => {
2842                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2843                }
2844            }
2845        });
2846    }
2847
2848    #[test]
2849    fn dust_transfer_required_params_success() {
2850        TOKIO_SHARED_RT.block_on(async {
2851            let client = MockAssetApiClient { force_error: false };
2852
2853            let params = DustTransferParams::builder("BTC".to_string(),).build().unwrap();
2854
2855            let resp_json: Value = serde_json::from_str(r#"{"totalServiceCharge":"0.02102542","totalTransfered":"1.05127099","transferResult":[{"amount":"0.03000000","fromAsset":"ETH","operateTime":1563368549307,"serviceChargeAmount":"0.00500000","tranId":2970932918,"transferedAmount":"0.25000000"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2856            let expected_response : models::DustTransferResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustTransferResponse");
2857
2858            let resp = client.dust_transfer(params).await.expect("Expected a response");
2859            let data_future = resp.data();
2860            let actual_response = data_future.await.unwrap();
2861            assert_eq!(actual_response, expected_response);
2862        });
2863    }
2864
2865    #[test]
2866    fn dust_transfer_optional_params_success() {
2867        TOKIO_SHARED_RT.block_on(async {
2868            let client = MockAssetApiClient { force_error: false };
2869
2870            let params = DustTransferParams::builder("BTC".to_string(),).account_type(DustTransferAccountTypeEnum::Spot).recv_window(5000).build().unwrap();
2871
2872            let resp_json: Value = serde_json::from_str(r#"{"totalServiceCharge":"0.02102542","totalTransfered":"1.05127099","transferResult":[{"amount":"0.03000000","fromAsset":"ETH","operateTime":1563368549307,"serviceChargeAmount":"0.00500000","tranId":2970932918,"transferedAmount":"0.25000000"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2873            let expected_response : models::DustTransferResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustTransferResponse");
2874
2875            let resp = client.dust_transfer(params).await.expect("Expected a response");
2876            let data_future = resp.data();
2877            let actual_response = data_future.await.unwrap();
2878            assert_eq!(actual_response, expected_response);
2879        });
2880    }
2881
2882    #[test]
2883    fn dust_transfer_response_error() {
2884        TOKIO_SHARED_RT.block_on(async {
2885            let client = MockAssetApiClient { force_error: true };
2886
2887            let params = DustTransferParams::builder("BTC".to_string())
2888                .build()
2889                .unwrap();
2890
2891            match client.dust_transfer(params).await {
2892                Ok(_) => panic!("Expected an error"),
2893                Err(err) => {
2894                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2895                }
2896            }
2897        });
2898    }
2899
2900    #[test]
2901    fn dustlog_required_params_success() {
2902        TOKIO_SHARED_RT.block_on(async {
2903            let client = MockAssetApiClient { force_error: false };
2904
2905            let params = DustlogParams::builder().build().unwrap();
2906
2907            let resp_json: Value = serde_json::from_str(r#"{"total":8,"userAssetDribblets":[{"operateTime":1615985535000,"totalTransferedAmount":"0.00132256","totalServiceChargeAmount":"0.00002699","transId":45178372831,"userAssetDribbletDetails":[{"transId":4359321,"serviceChargeAmount":"0.000009","amount":"0.0009","operateTime":1615985535000,"transferedAmount":"0.000441","fromAsset":"USDT","targetAsset":"BNB"}]}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2908            let expected_response : models::DustlogResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustlogResponse");
2909
2910            let resp = client.dustlog(params).await.expect("Expected a response");
2911            let data_future = resp.data();
2912            let actual_response = data_future.await.unwrap();
2913            assert_eq!(actual_response, expected_response);
2914        });
2915    }
2916
2917    #[test]
2918    fn dustlog_optional_params_success() {
2919        TOKIO_SHARED_RT.block_on(async {
2920            let client = MockAssetApiClient { force_error: false };
2921
2922            let params = DustlogParams::builder().account_type(DustlogAccountTypeEnum::Spot).start_time(1623319461670).end_time(1641782889000).recv_window(5000).build().unwrap();
2923
2924            let resp_json: Value = serde_json::from_str(r#"{"total":8,"userAssetDribblets":[{"operateTime":1615985535000,"totalTransferedAmount":"0.00132256","totalServiceChargeAmount":"0.00002699","transId":45178372831,"userAssetDribbletDetails":[{"transId":4359321,"serviceChargeAmount":"0.000009","amount":"0.0009","operateTime":1615985535000,"transferedAmount":"0.000441","fromAsset":"USDT","targetAsset":"BNB"}]}]}"#).unwrap_or_else(|_| serde_json::json!({}));
2925            let expected_response : models::DustlogResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::DustlogResponse");
2926
2927            let resp = client.dustlog(params).await.expect("Expected a response");
2928            let data_future = resp.data();
2929            let actual_response = data_future.await.unwrap();
2930            assert_eq!(actual_response, expected_response);
2931        });
2932    }
2933
2934    #[test]
2935    fn dustlog_response_error() {
2936        TOKIO_SHARED_RT.block_on(async {
2937            let client = MockAssetApiClient { force_error: true };
2938
2939            let params = DustlogParams::builder().build().unwrap();
2940
2941            match client.dustlog(params).await {
2942                Ok(_) => panic!("Expected an error"),
2943                Err(err) => {
2944                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2945                }
2946            }
2947        });
2948    }
2949
2950    #[test]
2951    fn funding_wallet_required_params_success() {
2952        TOKIO_SHARED_RT.block_on(async {
2953            let client = MockAssetApiClient { force_error: false };
2954
2955            let params = FundingWalletParams::builder().build().unwrap();
2956
2957            let resp_json: Value = serde_json::from_str(r#"[{"asset":"USDT","free":"1","locked":"0","freeze":"0","withdrawing":"0","btcValuation":"0.00000091"}]"#).unwrap_or_else(|_| serde_json::json!({}));
2958            let expected_response : Vec<models::FundingWalletResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::FundingWalletResponseInner>");
2959
2960            let resp = client.funding_wallet(params).await.expect("Expected a response");
2961            let data_future = resp.data();
2962            let actual_response = data_future.await.unwrap();
2963            assert_eq!(actual_response, expected_response);
2964        });
2965    }
2966
2967    #[test]
2968    fn funding_wallet_optional_params_success() {
2969        TOKIO_SHARED_RT.block_on(async {
2970            let client = MockAssetApiClient { force_error: false };
2971
2972            let params = FundingWalletParams::builder().asset("BTC".to_string()).need_btc_valuation(true).recv_window(5000).build().unwrap();
2973
2974            let resp_json: Value = serde_json::from_str(r#"[{"asset":"USDT","free":"1","locked":"0","freeze":"0","withdrawing":"0","btcValuation":"0.00000091"}]"#).unwrap_or_else(|_| serde_json::json!({}));
2975            let expected_response : Vec<models::FundingWalletResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::FundingWalletResponseInner>");
2976
2977            let resp = client.funding_wallet(params).await.expect("Expected a response");
2978            let data_future = resp.data();
2979            let actual_response = data_future.await.unwrap();
2980            assert_eq!(actual_response, expected_response);
2981        });
2982    }
2983
2984    #[test]
2985    fn funding_wallet_response_error() {
2986        TOKIO_SHARED_RT.block_on(async {
2987            let client = MockAssetApiClient { force_error: true };
2988
2989            let params = FundingWalletParams::builder().build().unwrap();
2990
2991            match client.funding_wallet(params).await {
2992                Ok(_) => panic!("Expected an error"),
2993                Err(err) => {
2994                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
2995                }
2996            }
2997        });
2998    }
2999
3000    #[test]
3001    fn get_assets_that_can_be_converted_into_bnb_required_params_success() {
3002        TOKIO_SHARED_RT.block_on(async {
3003            let client = MockAssetApiClient { force_error: false };
3004
3005            let params = GetAssetsThatCanBeConvertedIntoBnbParams::builder().build().unwrap();
3006
3007            let resp_json: Value = serde_json::from_str(r#"{"details":[{"asset":"ADA","assetFullName":"ADA","amountFree":"6.21","toBTC":"0.00016848","toBNB":"0.01777302","toBNBOffExchange":"0.01741756","exchange":"0.00035546"}],"totalTransferBtc":"0.00016848","totalTransferBNB":"0.01777302","dribbletPercentage":"0.02"}"#).unwrap_or_else(|_| serde_json::json!({}));
3008            let expected_response : models::GetAssetsThatCanBeConvertedIntoBnbResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetAssetsThatCanBeConvertedIntoBnbResponse");
3009
3010            let resp = client.get_assets_that_can_be_converted_into_bnb(params).await.expect("Expected a response");
3011            let data_future = resp.data();
3012            let actual_response = data_future.await.unwrap();
3013            assert_eq!(actual_response, expected_response);
3014        });
3015    }
3016
3017    #[test]
3018    fn get_assets_that_can_be_converted_into_bnb_optional_params_success() {
3019        TOKIO_SHARED_RT.block_on(async {
3020            let client = MockAssetApiClient { force_error: false };
3021
3022            let params = GetAssetsThatCanBeConvertedIntoBnbParams::builder().account_type(GetAssetsThatCanBeConvertedIntoBnbAccountTypeEnum::Spot).recv_window(5000).build().unwrap();
3023
3024            let resp_json: Value = serde_json::from_str(r#"{"details":[{"asset":"ADA","assetFullName":"ADA","amountFree":"6.21","toBTC":"0.00016848","toBNB":"0.01777302","toBNBOffExchange":"0.01741756","exchange":"0.00035546"}],"totalTransferBtc":"0.00016848","totalTransferBNB":"0.01777302","dribbletPercentage":"0.02"}"#).unwrap_or_else(|_| serde_json::json!({}));
3025            let expected_response : models::GetAssetsThatCanBeConvertedIntoBnbResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetAssetsThatCanBeConvertedIntoBnbResponse");
3026
3027            let resp = client.get_assets_that_can_be_converted_into_bnb(params).await.expect("Expected a response");
3028            let data_future = resp.data();
3029            let actual_response = data_future.await.unwrap();
3030            assert_eq!(actual_response, expected_response);
3031        });
3032    }
3033
3034    #[test]
3035    fn get_assets_that_can_be_converted_into_bnb_response_error() {
3036        TOKIO_SHARED_RT.block_on(async {
3037            let client = MockAssetApiClient { force_error: true };
3038
3039            let params = GetAssetsThatCanBeConvertedIntoBnbParams::builder()
3040                .build()
3041                .unwrap();
3042
3043            match client
3044                .get_assets_that_can_be_converted_into_bnb(params)
3045                .await
3046            {
3047                Ok(_) => panic!("Expected an error"),
3048                Err(err) => {
3049                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3050                }
3051            }
3052        });
3053    }
3054
3055    #[test]
3056    fn get_cloud_mining_payment_and_refund_history_required_params_success() {
3057        TOKIO_SHARED_RT.block_on(async {
3058            let client = MockAssetApiClient { force_error: false };
3059
3060            let params = GetCloudMiningPaymentAndRefundHistoryParams::builder(1623319461670,1641782889000,).build().unwrap();
3061
3062            let resp_json: Value = serde_json::from_str(r#"{"total":5,"rows":[{"createTime":1667880112000,"tranId":121230610120,"type":248,"asset":"USDT","amount":"25.0068","status":"S"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
3063            let expected_response : models::GetCloudMiningPaymentAndRefundHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetCloudMiningPaymentAndRefundHistoryResponse");
3064
3065            let resp = client.get_cloud_mining_payment_and_refund_history(params).await.expect("Expected a response");
3066            let data_future = resp.data();
3067            let actual_response = data_future.await.unwrap();
3068            assert_eq!(actual_response, expected_response);
3069        });
3070    }
3071
3072    #[test]
3073    fn get_cloud_mining_payment_and_refund_history_optional_params_success() {
3074        TOKIO_SHARED_RT.block_on(async {
3075            let client = MockAssetApiClient { force_error: false };
3076
3077            let params = GetCloudMiningPaymentAndRefundHistoryParams::builder(1623319461670,1641782889000,).tran_id(1).client_tran_id("1".to_string()).asset("BTC".to_string()).current(1).size(10).build().unwrap();
3078
3079            let resp_json: Value = serde_json::from_str(r#"{"total":5,"rows":[{"createTime":1667880112000,"tranId":121230610120,"type":248,"asset":"USDT","amount":"25.0068","status":"S"}]}"#).unwrap_or_else(|_| serde_json::json!({}));
3080            let expected_response : models::GetCloudMiningPaymentAndRefundHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::GetCloudMiningPaymentAndRefundHistoryResponse");
3081
3082            let resp = client.get_cloud_mining_payment_and_refund_history(params).await.expect("Expected a response");
3083            let data_future = resp.data();
3084            let actual_response = data_future.await.unwrap();
3085            assert_eq!(actual_response, expected_response);
3086        });
3087    }
3088
3089    #[test]
3090    fn get_cloud_mining_payment_and_refund_history_response_error() {
3091        TOKIO_SHARED_RT.block_on(async {
3092            let client = MockAssetApiClient { force_error: true };
3093
3094            let params =
3095                GetCloudMiningPaymentAndRefundHistoryParams::builder(1623319461670, 1641782889000)
3096                    .build()
3097                    .unwrap();
3098
3099            match client
3100                .get_cloud_mining_payment_and_refund_history(params)
3101                .await
3102            {
3103                Ok(_) => panic!("Expected an error"),
3104                Err(err) => {
3105                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3106                }
3107            }
3108        });
3109    }
3110
3111    #[test]
3112    fn get_open_symbol_list_required_params_success() {
3113        TOKIO_SHARED_RT.block_on(async {
3114            let client = MockAssetApiClient { force_error: false };
3115
3116            let resp_json: Value =
3117                serde_json::from_str(r#"[{"openTime":1686161202000,"symbols":["BNBBTC"]}]"#)
3118                    .unwrap_or_else(|_| serde_json::json!({}));
3119            let expected_response: Vec<models::GetOpenSymbolListResponseInner> =
3120                serde_json::from_value(resp_json.clone())
3121                    .expect("should parse into Vec<models::GetOpenSymbolListResponseInner>");
3122
3123            let resp = client
3124                .get_open_symbol_list()
3125                .await
3126                .expect("Expected a response");
3127            let data_future = resp.data();
3128            let actual_response = data_future.await.unwrap();
3129            assert_eq!(actual_response, expected_response);
3130        });
3131    }
3132
3133    #[test]
3134    fn get_open_symbol_list_optional_params_success() {
3135        TOKIO_SHARED_RT.block_on(async {
3136            let client = MockAssetApiClient { force_error: false };
3137
3138            let resp_json: Value =
3139                serde_json::from_str(r#"[{"openTime":1686161202000,"symbols":["BNBBTC"]}]"#)
3140                    .unwrap_or_else(|_| serde_json::json!({}));
3141            let expected_response: Vec<models::GetOpenSymbolListResponseInner> =
3142                serde_json::from_value(resp_json.clone())
3143                    .expect("should parse into Vec<models::GetOpenSymbolListResponseInner>");
3144
3145            let resp = client
3146                .get_open_symbol_list()
3147                .await
3148                .expect("Expected a response");
3149            let data_future = resp.data();
3150            let actual_response = data_future.await.unwrap();
3151            assert_eq!(actual_response, expected_response);
3152        });
3153    }
3154
3155    #[test]
3156    fn get_open_symbol_list_response_error() {
3157        TOKIO_SHARED_RT.block_on(async {
3158            let client = MockAssetApiClient { force_error: true };
3159
3160            match client.get_open_symbol_list().await {
3161                Ok(_) => panic!("Expected an error"),
3162                Err(err) => {
3163                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3164                }
3165            }
3166        });
3167    }
3168
3169    #[test]
3170    fn get_spot_asset_tags_required_params_success() {
3171        TOKIO_SHARED_RT.block_on(async {
3172            let client = MockAssetApiClient { force_error: false };
3173
3174            let params = GetSpotAssetTagsParams::builder().build().unwrap();
3175
3176            let resp_json: Value = serde_json::from_str(r#"[{"assetCode":"BNB","assetName":"BNB","trading":true,"tags":["Layer1_Layer2","BSC"]}]"#).unwrap_or_else(|_| serde_json::json!({}));
3177            let expected_response : Vec<models::GetSpotAssetTagsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetSpotAssetTagsResponseInner>");
3178
3179            let resp = client.get_spot_asset_tags(params).await.expect("Expected a response");
3180            let data_future = resp.data();
3181            let actual_response = data_future.await.unwrap();
3182            assert_eq!(actual_response, expected_response);
3183        });
3184    }
3185
3186    #[test]
3187    fn get_spot_asset_tags_optional_params_success() {
3188        TOKIO_SHARED_RT.block_on(async {
3189            let client = MockAssetApiClient { force_error: false };
3190
3191            let params = GetSpotAssetTagsParams::builder().tag("Layer1_Layer2,BSC".to_string()).build().unwrap();
3192
3193            let resp_json: Value = serde_json::from_str(r#"[{"assetCode":"BNB","assetName":"BNB","trading":true,"tags":["Layer1_Layer2","BSC"]}]"#).unwrap_or_else(|_| serde_json::json!({}));
3194            let expected_response : Vec<models::GetSpotAssetTagsResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::GetSpotAssetTagsResponseInner>");
3195
3196            let resp = client.get_spot_asset_tags(params).await.expect("Expected a response");
3197            let data_future = resp.data();
3198            let actual_response = data_future.await.unwrap();
3199            assert_eq!(actual_response, expected_response);
3200        });
3201    }
3202
3203    #[test]
3204    fn get_spot_asset_tags_response_error() {
3205        TOKIO_SHARED_RT.block_on(async {
3206            let client = MockAssetApiClient { force_error: true };
3207
3208            let params = GetSpotAssetTagsParams::builder().build().unwrap();
3209
3210            match client.get_spot_asset_tags(params).await {
3211                Ok(_) => panic!("Expected an error"),
3212                Err(err) => {
3213                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3214                }
3215            }
3216        });
3217    }
3218
3219    #[test]
3220    fn query_user_delegation_history_required_params_success() {
3221        TOKIO_SHARED_RT.block_on(async {
3222            let client = MockAssetApiClient { force_error: false };
3223
3224            let params = QueryUserDelegationHistoryParams::builder("abc@test.com".to_string(),1623319461670,1641782889000,).build().unwrap();
3225
3226            let resp_json: Value = serde_json::from_str(r#"{"total":3316,"rows":[{"clientTranId":"293915932290879488","transferType":"Undelegate","asset":"ETH","amount":"1","time":1695205406000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
3227            let expected_response : models::QueryUserDelegationHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryUserDelegationHistoryResponse");
3228
3229            let resp = client.query_user_delegation_history(params).await.expect("Expected a response");
3230            let data_future = resp.data();
3231            let actual_response = data_future.await.unwrap();
3232            assert_eq!(actual_response, expected_response);
3233        });
3234    }
3235
3236    #[test]
3237    fn query_user_delegation_history_optional_params_success() {
3238        TOKIO_SHARED_RT.block_on(async {
3239            let client = MockAssetApiClient { force_error: false };
3240
3241            let params = QueryUserDelegationHistoryParams::builder("abc@test.com".to_string(),1623319461670,1641782889000,).r#type(QueryUserDelegationHistoryTypeEnum::Delegate).asset("BTC".to_string()).current(1).size(10).recv_window(5000).build().unwrap();
3242
3243            let resp_json: Value = serde_json::from_str(r#"{"total":3316,"rows":[{"clientTranId":"293915932290879488","transferType":"Undelegate","asset":"ETH","amount":"1","time":1695205406000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
3244            let expected_response : models::QueryUserDelegationHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryUserDelegationHistoryResponse");
3245
3246            let resp = client.query_user_delegation_history(params).await.expect("Expected a response");
3247            let data_future = resp.data();
3248            let actual_response = data_future.await.unwrap();
3249            assert_eq!(actual_response, expected_response);
3250        });
3251    }
3252
3253    #[test]
3254    fn query_user_delegation_history_response_error() {
3255        TOKIO_SHARED_RT.block_on(async {
3256            let client = MockAssetApiClient { force_error: true };
3257
3258            let params = QueryUserDelegationHistoryParams::builder(
3259                "abc@test.com".to_string(),
3260                1623319461670,
3261                1641782889000,
3262            )
3263            .build()
3264            .unwrap();
3265
3266            match client.query_user_delegation_history(params).await {
3267                Ok(_) => panic!("Expected an error"),
3268                Err(err) => {
3269                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3270                }
3271            }
3272        });
3273    }
3274
3275    #[test]
3276    fn query_user_universal_transfer_history_required_params_success() {
3277        TOKIO_SHARED_RT.block_on(async {
3278            let client = MockAssetApiClient { force_error: false };
3279
3280            let params = QueryUserUniversalTransferHistoryParams::builder("r#type_example".to_string(),).build().unwrap();
3281
3282            let resp_json: Value = serde_json::from_str(r#"{"total":2,"rows":[{"asset":"USDT","amount":"1","type":"MAIN_UMFUTURE","status":"CONFIRMED","tranId":11415955596,"timestamp":1544433328000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
3283            let expected_response : models::QueryUserUniversalTransferHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryUserUniversalTransferHistoryResponse");
3284
3285            let resp = client.query_user_universal_transfer_history(params).await.expect("Expected a response");
3286            let data_future = resp.data();
3287            let actual_response = data_future.await.unwrap();
3288            assert_eq!(actual_response, expected_response);
3289        });
3290    }
3291
3292    #[test]
3293    fn query_user_universal_transfer_history_optional_params_success() {
3294        TOKIO_SHARED_RT.block_on(async {
3295            let client = MockAssetApiClient { force_error: false };
3296
3297            let params = QueryUserUniversalTransferHistoryParams::builder("r#type_example".to_string(),).start_time(1623319461670).end_time(1641782889000).current(1).size(10).from_symbol(QueryUserUniversalTransferHistoryFromSymbolEnum::IsolatedmarginMargin).to_symbol(QueryUserUniversalTransferHistoryToSymbolEnum::MarginIsolatedmargin).recv_window(5000).build().unwrap();
3298
3299            let resp_json: Value = serde_json::from_str(r#"{"total":2,"rows":[{"asset":"USDT","amount":"1","type":"MAIN_UMFUTURE","status":"CONFIRMED","tranId":11415955596,"timestamp":1544433328000}]}"#).unwrap_or_else(|_| serde_json::json!({}));
3300            let expected_response : models::QueryUserUniversalTransferHistoryResponse = serde_json::from_value(resp_json.clone()).expect("should parse into models::QueryUserUniversalTransferHistoryResponse");
3301
3302            let resp = client.query_user_universal_transfer_history(params).await.expect("Expected a response");
3303            let data_future = resp.data();
3304            let actual_response = data_future.await.unwrap();
3305            assert_eq!(actual_response, expected_response);
3306        });
3307    }
3308
3309    #[test]
3310    fn query_user_universal_transfer_history_response_error() {
3311        TOKIO_SHARED_RT.block_on(async {
3312            let client = MockAssetApiClient { force_error: true };
3313
3314            let params =
3315                QueryUserUniversalTransferHistoryParams::builder("r#type_example".to_string())
3316                    .build()
3317                    .unwrap();
3318
3319            match client.query_user_universal_transfer_history(params).await {
3320                Ok(_) => panic!("Expected an error"),
3321                Err(err) => {
3322                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3323                }
3324            }
3325        });
3326    }
3327
3328    #[test]
3329    fn query_user_wallet_balance_required_params_success() {
3330        TOKIO_SHARED_RT.block_on(async {
3331            let client = MockAssetApiClient { force_error: false };
3332
3333            let params = QueryUserWalletBalanceParams::builder().build().unwrap();
3334
3335            let resp_json: Value =
3336                serde_json::from_str(r#"[{"activate":true,"balance":"0","walletName":"Spot"}]"#)
3337                    .unwrap_or_else(|_| serde_json::json!({}));
3338            let expected_response: Vec<models::QueryUserWalletBalanceResponseInner> =
3339                serde_json::from_value(resp_json.clone())
3340                    .expect("should parse into Vec<models::QueryUserWalletBalanceResponseInner>");
3341
3342            let resp = client
3343                .query_user_wallet_balance(params)
3344                .await
3345                .expect("Expected a response");
3346            let data_future = resp.data();
3347            let actual_response = data_future.await.unwrap();
3348            assert_eq!(actual_response, expected_response);
3349        });
3350    }
3351
3352    #[test]
3353    fn query_user_wallet_balance_optional_params_success() {
3354        TOKIO_SHARED_RT.block_on(async {
3355            let client = MockAssetApiClient { force_error: false };
3356
3357            let params = QueryUserWalletBalanceParams::builder()
3358                .quote_asset("BTC".to_string())
3359                .recv_window(5000)
3360                .build()
3361                .unwrap();
3362
3363            let resp_json: Value =
3364                serde_json::from_str(r#"[{"activate":true,"balance":"0","walletName":"Spot"}]"#)
3365                    .unwrap_or_else(|_| serde_json::json!({}));
3366            let expected_response: Vec<models::QueryUserWalletBalanceResponseInner> =
3367                serde_json::from_value(resp_json.clone())
3368                    .expect("should parse into Vec<models::QueryUserWalletBalanceResponseInner>");
3369
3370            let resp = client
3371                .query_user_wallet_balance(params)
3372                .await
3373                .expect("Expected a response");
3374            let data_future = resp.data();
3375            let actual_response = data_future.await.unwrap();
3376            assert_eq!(actual_response, expected_response);
3377        });
3378    }
3379
3380    #[test]
3381    fn query_user_wallet_balance_response_error() {
3382        TOKIO_SHARED_RT.block_on(async {
3383            let client = MockAssetApiClient { force_error: true };
3384
3385            let params = QueryUserWalletBalanceParams::builder().build().unwrap();
3386
3387            match client.query_user_wallet_balance(params).await {
3388                Ok(_) => panic!("Expected an error"),
3389                Err(err) => {
3390                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3391                }
3392            }
3393        });
3394    }
3395
3396    #[test]
3397    fn toggle_bnb_burn_on_spot_trade_and_margin_interest_required_params_success() {
3398        TOKIO_SHARED_RT.block_on(async {
3399            let client = MockAssetApiClient { force_error: false };
3400
3401            let params = ToggleBnbBurnOnSpotTradeAndMarginInterestParams::builder()
3402                .build()
3403                .unwrap();
3404
3405            let resp_json: Value =
3406                serde_json::from_str(r#"{"spotBNBBurn":true,"interestBNBBurn":false}"#)
3407                    .unwrap_or_else(|_| serde_json::json!({}));
3408            let expected_response: models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse =
3409                serde_json::from_value(resp_json.clone()).expect(
3410                    "should parse into models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse",
3411                );
3412
3413            let resp = client
3414                .toggle_bnb_burn_on_spot_trade_and_margin_interest(params)
3415                .await
3416                .expect("Expected a response");
3417            let data_future = resp.data();
3418            let actual_response = data_future.await.unwrap();
3419            assert_eq!(actual_response, expected_response);
3420        });
3421    }
3422
3423    #[test]
3424    fn toggle_bnb_burn_on_spot_trade_and_margin_interest_optional_params_success() {
3425        TOKIO_SHARED_RT.block_on(async {
3426            let client = MockAssetApiClient { force_error: false };
3427
3428            let params = ToggleBnbBurnOnSpotTradeAndMarginInterestParams::builder()
3429                .spot_bnb_burn("true".to_string())
3430                .interest_bnb_burn("true".to_string())
3431                .recv_window(5000)
3432                .build()
3433                .unwrap();
3434
3435            let resp_json: Value =
3436                serde_json::from_str(r#"{"spotBNBBurn":true,"interestBNBBurn":false}"#)
3437                    .unwrap_or_else(|_| serde_json::json!({}));
3438            let expected_response: models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse =
3439                serde_json::from_value(resp_json.clone()).expect(
3440                    "should parse into models::ToggleBnbBurnOnSpotTradeAndMarginInterestResponse",
3441                );
3442
3443            let resp = client
3444                .toggle_bnb_burn_on_spot_trade_and_margin_interest(params)
3445                .await
3446                .expect("Expected a response");
3447            let data_future = resp.data();
3448            let actual_response = data_future.await.unwrap();
3449            assert_eq!(actual_response, expected_response);
3450        });
3451    }
3452
3453    #[test]
3454    fn toggle_bnb_burn_on_spot_trade_and_margin_interest_response_error() {
3455        TOKIO_SHARED_RT.block_on(async {
3456            let client = MockAssetApiClient { force_error: true };
3457
3458            let params = ToggleBnbBurnOnSpotTradeAndMarginInterestParams::builder()
3459                .build()
3460                .unwrap();
3461
3462            match client
3463                .toggle_bnb_burn_on_spot_trade_and_margin_interest(params)
3464                .await
3465            {
3466                Ok(_) => panic!("Expected an error"),
3467                Err(err) => {
3468                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3469                }
3470            }
3471        });
3472    }
3473
3474    #[test]
3475    fn trade_fee_required_params_success() {
3476        TOKIO_SHARED_RT.block_on(async {
3477            let client = MockAssetApiClient { force_error: false };
3478
3479            let params = TradeFeeParams::builder().build().unwrap();
3480
3481            let resp_json: Value = serde_json::from_str(
3482                r#"[{"symbol":"ADABNB","makerCommission":"0.001","takerCommission":"0.001"}]"#,
3483            )
3484            .unwrap_or_else(|_| serde_json::json!({}));
3485            let expected_response: Vec<models::TradeFeeResponseInner> =
3486                serde_json::from_value(resp_json.clone())
3487                    .expect("should parse into Vec<models::TradeFeeResponseInner>");
3488
3489            let resp = client.trade_fee(params).await.expect("Expected a response");
3490            let data_future = resp.data();
3491            let actual_response = data_future.await.unwrap();
3492            assert_eq!(actual_response, expected_response);
3493        });
3494    }
3495
3496    #[test]
3497    fn trade_fee_optional_params_success() {
3498        TOKIO_SHARED_RT.block_on(async {
3499            let client = MockAssetApiClient { force_error: false };
3500
3501            let params = TradeFeeParams::builder()
3502                .symbol("ADABNB".to_string())
3503                .recv_window(5000)
3504                .build()
3505                .unwrap();
3506
3507            let resp_json: Value = serde_json::from_str(
3508                r#"[{"symbol":"ADABNB","makerCommission":"0.001","takerCommission":"0.001"}]"#,
3509            )
3510            .unwrap_or_else(|_| serde_json::json!({}));
3511            let expected_response: Vec<models::TradeFeeResponseInner> =
3512                serde_json::from_value(resp_json.clone())
3513                    .expect("should parse into Vec<models::TradeFeeResponseInner>");
3514
3515            let resp = client.trade_fee(params).await.expect("Expected a response");
3516            let data_future = resp.data();
3517            let actual_response = data_future.await.unwrap();
3518            assert_eq!(actual_response, expected_response);
3519        });
3520    }
3521
3522    #[test]
3523    fn trade_fee_response_error() {
3524        TOKIO_SHARED_RT.block_on(async {
3525            let client = MockAssetApiClient { force_error: true };
3526
3527            let params = TradeFeeParams::builder().build().unwrap();
3528
3529            match client.trade_fee(params).await {
3530                Ok(_) => panic!("Expected an error"),
3531                Err(err) => {
3532                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3533                }
3534            }
3535        });
3536    }
3537
3538    #[test]
3539    fn user_asset_required_params_success() {
3540        TOKIO_SHARED_RT.block_on(async {
3541            let client = MockAssetApiClient { force_error: false };
3542
3543            let params = UserAssetParams::builder().build().unwrap();
3544
3545            let resp_json: Value = serde_json::from_str(r#"[{"asset":"AVAX","free":"1","locked":"0","freeze":"0","withdrawing":"0","ipoable":"0","btcValuation":"0"}]"#).unwrap_or_else(|_| serde_json::json!({}));
3546            let expected_response : Vec<models::UserAssetResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::UserAssetResponseInner>");
3547
3548            let resp = client.user_asset(params).await.expect("Expected a response");
3549            let data_future = resp.data();
3550            let actual_response = data_future.await.unwrap();
3551            assert_eq!(actual_response, expected_response);
3552        });
3553    }
3554
3555    #[test]
3556    fn user_asset_optional_params_success() {
3557        TOKIO_SHARED_RT.block_on(async {
3558            let client = MockAssetApiClient { force_error: false };
3559
3560            let params = UserAssetParams::builder().asset("BTC".to_string()).need_btc_valuation(true).recv_window(5000).build().unwrap();
3561
3562            let resp_json: Value = serde_json::from_str(r#"[{"asset":"AVAX","free":"1","locked":"0","freeze":"0","withdrawing":"0","ipoable":"0","btcValuation":"0"}]"#).unwrap_or_else(|_| serde_json::json!({}));
3563            let expected_response : Vec<models::UserAssetResponseInner> = serde_json::from_value(resp_json.clone()).expect("should parse into Vec<models::UserAssetResponseInner>");
3564
3565            let resp = client.user_asset(params).await.expect("Expected a response");
3566            let data_future = resp.data();
3567            let actual_response = data_future.await.unwrap();
3568            assert_eq!(actual_response, expected_response);
3569        });
3570    }
3571
3572    #[test]
3573    fn user_asset_response_error() {
3574        TOKIO_SHARED_RT.block_on(async {
3575            let client = MockAssetApiClient { force_error: true };
3576
3577            let params = UserAssetParams::builder().build().unwrap();
3578
3579            match client.user_asset(params).await {
3580                Ok(_) => panic!("Expected an error"),
3581                Err(err) => {
3582                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3583                }
3584            }
3585        });
3586    }
3587
3588    #[test]
3589    fn user_universal_transfer_required_params_success() {
3590        TOKIO_SHARED_RT.block_on(async {
3591            let client = MockAssetApiClient { force_error: false };
3592
3593            let params = UserUniversalTransferParams::builder(
3594                UserUniversalTransferTypeEnum::MainUmfuture,
3595                "BTC".to_string(),
3596                dec!(1.0),
3597            )
3598            .build()
3599            .unwrap();
3600
3601            let resp_json: Value = serde_json::from_str(r#"{"tranId":13526853623}"#)
3602                .unwrap_or_else(|_| serde_json::json!({}));
3603            let expected_response: models::UserUniversalTransferResponse =
3604                serde_json::from_value(resp_json.clone())
3605                    .expect("should parse into models::UserUniversalTransferResponse");
3606
3607            let resp = client
3608                .user_universal_transfer(params)
3609                .await
3610                .expect("Expected a response");
3611            let data_future = resp.data();
3612            let actual_response = data_future.await.unwrap();
3613            assert_eq!(actual_response, expected_response);
3614        });
3615    }
3616
3617    #[test]
3618    fn user_universal_transfer_optional_params_success() {
3619        TOKIO_SHARED_RT.block_on(async {
3620            let client = MockAssetApiClient { force_error: false };
3621
3622            let params = UserUniversalTransferParams::builder(
3623                UserUniversalTransferTypeEnum::MainUmfuture,
3624                "BTC".to_string(),
3625                dec!(1.0),
3626            )
3627            .from_symbol(UserUniversalTransferFromSymbolEnum::IsolatedmarginMargin)
3628            .to_symbol(UserUniversalTransferToSymbolEnum::MarginIsolatedmargin)
3629            .recv_window(5000)
3630            .build()
3631            .unwrap();
3632
3633            let resp_json: Value = serde_json::from_str(r#"{"tranId":13526853623}"#)
3634                .unwrap_or_else(|_| serde_json::json!({}));
3635            let expected_response: models::UserUniversalTransferResponse =
3636                serde_json::from_value(resp_json.clone())
3637                    .expect("should parse into models::UserUniversalTransferResponse");
3638
3639            let resp = client
3640                .user_universal_transfer(params)
3641                .await
3642                .expect("Expected a response");
3643            let data_future = resp.data();
3644            let actual_response = data_future.await.unwrap();
3645            assert_eq!(actual_response, expected_response);
3646        });
3647    }
3648
3649    #[test]
3650    fn user_universal_transfer_response_error() {
3651        TOKIO_SHARED_RT.block_on(async {
3652            let client = MockAssetApiClient { force_error: true };
3653
3654            let params = UserUniversalTransferParams::builder(
3655                UserUniversalTransferTypeEnum::MainUmfuture,
3656                "BTC".to_string(),
3657                dec!(1.0),
3658            )
3659            .build()
3660            .unwrap();
3661
3662            match client.user_universal_transfer(params).await {
3663                Ok(_) => panic!("Expected an error"),
3664                Err(err) => {
3665                    assert_eq!(err.to_string(), "Connector client error: ResponseError");
3666                }
3667            }
3668        });
3669    }
3670}